# Pipeline Performance

The pipeline logs per-event metrics to `~/.claude/logs/multi-agent/metrics.jsonl`
as it runs. The `aggregate-metrics.mjs` script turns that file into a summary
you can read, embed in a report, or feed into a dashboard.

## Quick Start

```bash
# Plain-text summary (the default - fits in a terminal)
node pipeline/scripts/aggregate-metrics.mjs

# Markdown table (for PR descriptions, wikis, dashboards)
node pipeline/scripts/aggregate-metrics.mjs --markdown

# JSON (for machine consumption - Phase 7 report uses this)
node pipeline/scripts/aggregate-metrics.mjs --json

# Filtered - only recent runs
node pipeline/scripts/aggregate-metrics.mjs --since=2026-04-01

# Per-task or per-phase drill-down
node pipeline/scripts/aggregate-metrics.mjs --task-id=PROJ-123
node pipeline/scripts/aggregate-metrics.mjs --phase=4
```

## What Gets Measured

Each event in `metrics.jsonl` is a single-line JSON object written by
`log-metric.sh`. Events cover:

- **Review cycles** - how many iterations of Phase 3 → Phase 4 → Phase 3 a task
  needed before triage approved.
- **Triage classification** - accepted / deferred / rejected counts per review.
- **Triage edge cases** - over-rejection guard trips, contradictions, invalid-
  JSON retries, timeouts.
- **Phase 3 retries** - build / test / lint retry distribution per task.
- **Cost per model** - calls, duration, tokens in/out, broken down by model
  (Fable, Opus, Sonnet, GPT-5.4).
- **Language preference** - distribution of EN vs TR prompts.

## Typical Output (Markdown)

```markdown
# Pipeline Metrics Summary

_Source: ~/.claude/logs/multi-agent/metrics.jsonl · Events: 421 (0 parse errors) · Unique tasks: 34_

## Reviews

| Metric | Value |
|--------|-------|
| Completed | 28 |
| Cycles per task (avg) | 1.3 |
| Cycles per task (p95) | 2 |

## Triage Classification

| Category | Count | Rate |
|----------|-------|------|
| Raw findings | 167 | - |
| Accepted | 41 | 0.25 |
| Deferred | 19 | - |
| Rejected | 107 | 0.64 |

## Cost Per Model

| Model | Calls | Duration (ms) | Tokens In | Tokens Out |
|-------|-------|---------------|-----------|------------|
| `claude-fable-5` | 124 | 612430 | 380221 | 92114 |
| `claude-sonnet-4-6` | 89 | 412318 | 201445 | 58903 |
| `gpt-5.4` | 88 | 398214 | 194302 | 55128 |
```

## Interpreting Review-Cycle Metrics

- **`cycles per task avg` > 2.0** - triage is rejecting too many real findings
  or Phase 3 isn't converging. Inspect the edge-cases table.
- **Most-common edge case = `over_rejection_guard_tripped`** - the triage
  prompt lost scope context. Look at `phase-4-review.md:57-91`.
- **`p95` much higher than `avg`** - a few tasks are looping 3+ times. Usually
  means one of: bad acceptance criteria in Phase 2, tests that flake, or
  environment-dependent build failures.

## Phase-by-Phase Token Budget

Phase docs have hard-capped token limits in
`pipeline/schemas/token-budget.json`. `smoke-token-budget.sh` enforces them.
Current totals (v3.5.0):

| Phase | Warn | Max | Typical |
|-------|------|-----|---------|
| 0 INIT        | 3500 | 4000 | 3434 |
| 1 ANALYSIS    | 1200 | 1500 | 1315 |
| 2 PLANNING    |  800 | 1000 |  798 |
| 3 DEV         | 1500 | 1800 | 1451 |
| 4 REVIEW      | 1800 | 2200 | 2110 |
| 5 TEST        |  600 |  800 |  796 |
| 6 COMMIT      | 2400 | 2800 | 2537 |
| 7 REPORT      | 1800 | 2200 | 1851 |
| **Total** | **13600** | **16300** | **~14.3k** |

Lazy loading keeps these off the model's context until each phase actually
runs - the full 14 k total is never loaded at once.

## Embedding Metrics in Phase 7 Reports

Phase 7 automatically calls `aggregate-metrics.mjs --json` with the current
task id and embeds the last 30 days' summary into the report body. See the
template in `phase-7-report.md`.

## Disabling Metrics

Remove or rename `~/.claude/logs/multi-agent/metrics.jsonl`. The pipeline
will not error - `log-metric.sh` fails silently if the file isn't writable.
Nothing is sent off-device.
