The goal pattern
Goal loop: freeze an acceptance check, then repeat a cycle — compose a gap plan from the goal-check output, build that whole plan, re-check the goal — until the frozen goal goes green, two cycles plan no work, or the cycle ceiling is hit. Use for a moving target expressed as an executable acceptance check rather than a fixed plan; the recursive built-in that reuses the whole build as its cycle body.
[header] name = "goal" version = "1.1" description = """ Goal loop: freeze an acceptance check, then repeat a cycle — compose a gap plan from the goal-check output, build that whole plan, re-check the goal — until the frozen goal goes green, two cycles plan no work, or the cycle ceiling is hit. Use for a moving target expressed as an executable acceptance check rather than a fixed plan; the recursive built-in that reuses the whole build as its cycle body. """ entry = "main"
The top-level rows are cycles; each cycle's build supplies the milestone/sprint labels beneath it.
[[header.levels]] label = "cycle" [[header.parameters]] name = "goal_source" kind = "file" declared_plan_source = true description = "The acceptance goal file frozen before the goal loop starts." [[header.parameters]] name = "test" kind = "string" default = "" description = "The optional baseline test command that must stay green during the goal run." [[header.parameters]] name = "max_cycles" kind = "string" default = "18446744073709551615" description = "The optional cycle ceiling before the loop stops resumably."
The partial-merge request is a concrete goal-owned channel file under the orchestration directory.
[[channels]] name = "partial_merge" path = "state/goal-partial-merge.toml" values = ["requested"]
Consecutive cycles whose build reported empty-campaign — the declared outcome, not a stop-message
substring.
[[counters]] name = "empty_cycles" reset = "consecutive" increment_on = "sub-pattern-empty-campaign"
main
The baseline check must be amber to proceed. Green at baseline means there is nothing to do, so the run ends successfully from the goal-check's own verdict branch.
[[blocks.main]] type = "goal-check" input = "goal_source" test = "test" max_cycles = "max_cycles" output = "goal-output.txt" compose_cycle_plan = true if = "achieved" then = "success" [[blocks.main]] type = "loop" body = "cycle_body" rules = "cycle_ending"
cycle_body
compose the gap plan → build it → re-check the goal.
Run the whole build against the composed cycle plan. Build's declared empty-campaign outcome is how goal detects a cycle that planned no work.
[[blocks.cycle_body]] type = "sub-pattern" pattern = "build" parameters = { plan_source = "$goal-cycle.plan" } goal_cycle = true
Re-run the frozen acceptance check. Exit 0 (achieved) ends the run from the producing step; non-zero (unmet) is written to the next cycle's goal-output file and composes the next gap plan.
[[blocks.cycle_body]] type = "goal-check" input = "goal_source" output = "goal-output.txt" compose_cycle_plan = true if = "achieved" then = "success"
cycle_ending
The non-achieved endings, first-match-wins, all of them ordinary declared state — a channel file, a
counter that advances on build's empty-campaign outcome, and the loop's own iteration count:
- a partial-merge request after a cycle that built work → a calm resumable partial-merge stop;
- two consecutive empty cycles while the goal is still amber → stop as a goal discrepancy;
- the
max_cyclesceiling → a calm resumable partial-merge stop, not a failure.
Land the completed cycles and stop resumably.
[[rule_blocks.cycle_ending]] condition = { kind = "channel-value", channel = "partial_merge", value = "requested" } outcome = "stop"
Two consecutive cycles planned no work while the goal is still amber: stop as a goal discrepancy.
[[rule_blocks.cycle_ending]] condition = { kind = "counter-threshold", counter = "empty_cycles", threshold = 2 } outcome = "failure"
The configured max_cycles ceiling was reached: a calm resumable partial-merge stop, not a failure.
[[rule_blocks.cycle_ending]] condition = { kind = "iteration", number = "{{max_cycles}}" } outcome = "stop"
goal — the recursive built-in (
--goal/--loop)Freeze an acceptance check, then repeat a cycle until the frozen goal goes green. The cycle body is the whole build pattern, run as a sub-pattern against a plan composed from the goal-check's own output — so goal is build's recursive caller rather than a second engine.
The run ends when the goal-check reports achieved; the three other endings are gathered in
cycle_endingbelow.As-built reference: the goal loop in
src/engine/run/driver_goal.rs.