# Harness Metrics

A harness you can't measure is a harness you can't tune. `forge metrics`
aggregates the state the [enforced gates](/harness/overview) already record —
across every change, active and archived — so you can see whether the harness is
doing its job.

No extra instrumentation: the numbers come from the
[session timeline](/harness/timeline), the
[circuit-breaker](/harness/circuit-breaker) state, the
[budget ledger](/harness/budget), and secscan waivers.

## Usage

```sh
forge metrics            # readable rollup
forge metrics --json     # stable machine output for dashboards / CI
```

```
Harness metrics (2 change(s): 1 active, 1 archived)

Verify      2 run(s), 1 failed  (50% pass)
Breaker     0 change(s) with an OPEN breaker, 0 attempt(s), 0.0 avg/change
Budget      1200 tokens, 7 tool-call(s), 0 change(s) exceeded a ceiling
Secscan     0 waived finding(s)
Timeline    5 event(s)  (verify 2, budget 1, note 1, tool 1)
Contributors  Ana, Claude (agent), María (backend)
```

## What each line tells you

| Line | Reads on | What a bad number means |
|---|---|---|
| **Verify** | timeline verify events | A low pass rate means the agent is shipping work that doesn't hold up — tighten the spec or the tests, not the breaker |
| **Breaker** | `verify-attempts.yaml` | Constantly opening → the threshold is too tight, or changes are being scoped too large and the loop thrashes |
| **Budget** | `budget.yaml` | Regular ceiling breaches → the ceilings are wrong, or the work per change is too big |
| **Secscan** | waiver ledger | Waivers piling up → findings are being acknowledged rather than fixed |
| **Timeline / Contributors** | session log | Volume and who produced it; useful on a shared repo |

::: tip Read the rollup, not the single change
One change tells you about that change. The rollup tells you about the
*harness*. Look at it after a batch of work, and tune thresholds from the
trend — not from the last thing that annoyed you.
:::

## Degradation

Every per-change read is best-effort: a corrupt or missing state file zeroes
that one dimension and the report still renders. Only a missing
`.forge/changes` directory is an error — an empty one is a valid zero report.
With no recorded runs, the verify line reads `no runs recorded` rather than
`0% pass`, which would look like failure instead of "no data yet".

## See also

- [Enforcement Doctrine](/harness/overview) — what the gates are and why
- [Session Timeline](/harness/timeline) — the event log these numbers derive from
