Skip to content
Download PDF

Verify Circuit-Breaker ​

The verify circuit-breaker is one of Forge's four enforced controls. It bounds the iterations of the implement loop: after a change fails verification too many times in a row, the breaker opens, returns a non-zero exit, and forces an escalation to a human instead of retrying forever.

forge verify ​

forge verify runs the project's configured test/lint command plus spec scenario coverage, and prints a report ending in a verdict:

text
Verdict: PASS

or

text
Verdict: FAIL

Bare forge verify is read-only

Run without --change, forge verify is a reporter. It returns exit 0 even on FAIL — it tells you what happened but does not gate. This is backward compatible: existing scripts and workflows see no behavior change.

Opting into the breaker with --change ​

forge verify --change <c> opts into the circuit-breaker. Now Forge tracks consecutive verify failures for that change:

  • At a threshold (default 3, override with --max-failures N), it prints CIRCUIT OPEN and returns a non-zero exit. This is the enforced "stop looping and escalate to a human."
  • A passing verify resets the streak to 0.
  • forge verify --reset-breaker --change <c> clears the breaker after a human has intervened.

Progression (exit codes matter) ​

text
$ forge verify --change checkout   # attempt 1
Verdict: FAIL
Breaker: 1/3 consecutive failures for change "checkout" — fix the smallest cause and re-run.
# exit 0

$ forge verify --change checkout   # attempt 2
Verdict: FAIL
Breaker: 2/3 consecutive failures for change "checkout" — fix the smallest cause and re-run.
# exit 0

$ forge verify --change checkout   # attempt 3
Verdict: FAIL
Breaker: CIRCUIT OPEN — 3 consecutive verify failures for change "checkout".
# exit 1  → any gate/loop halts; escalate to a human

Notice that attempts 1 and 2 return exit 0: the breaker warns while the streak builds, but only refuses at the threshold. Once open, the non-zero exit propagates — any gate or loop wired to the exit code halts.

Clearing the breaker ​

After a human looks at the failure and does something about it, clear the streak so the loop can resume:

sh
forge verify --reset-breaker --change checkout

A subsequent passing verify would also reset it, but --reset-breaker is the explicit "I intervened" signal.

Persisted state ​

The breaker's state lives on disk, so it survives context compaction, restarts, and is visible to teammates:

yaml
# .forge/changes/checkout/verify-attempts.yaml
consecutive_failures: 3
open: true
last_verdict: FAIL
total_attempts: 7

Because the file is git-friendly, the breaker state is part of the change's history, not a volatile in-memory counter.

Why it matters ​

In Fowler's harness model, the highest-ROI control is the feedback loop — the Sensor that observes a run and corrects it. The circuit-breaker is the fuse on that loop. Without it, a well-meaning agent will happily "retry forever," burning iterations against a failure it cannot fix. The breaker converts an unbounded retry into a bounded one that ends in a human decision.

Complementary controls

The breaker bounds iterations. Its complement, the spend budget, bounds cost. Both emit into the session timeline so verdicts and breaker state are auditable.

Next steps ​