# Verify Circuit-Breaker

The verify circuit-breaker is one of Forge's four [enforced controls](/harness/overview). 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
```

::: info 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](/harness/overview) 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.

::: tip Complementary controls
The breaker bounds *iterations*. Its complement, the [spend budget](/harness/budget), bounds *cost*. Both emit into the [session timeline](/harness/timeline) so verdicts and breaker state are auditable.
:::

## Next steps

- [The enforcement doctrine](/harness/overview) — where the breaker sits among the four controls.
- [Spend budget](/harness/budget) — the sibling gate that bounds cost instead of iterations.
- [The guardrails gate](/harness/guardrails) — the control that blocks dangerous actions.
- [Session timeline](/harness/timeline) — where breaker verdicts land, attributed and auditable.
- [Connect a live agent](/harness/live-agent-hooks) — wiring a Stop hook that runs the breaker.
