@mmerterden/multi-agent-pipeline 16.19.0 → 16.21.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (61) hide show
  1. package/CHANGELOG.md +47 -0
  2. package/README.md +1 -1
  3. package/README.tr.md +1 -1
  4. package/docs/features.md +1 -0
  5. package/install/_codex-agents.mjs +2 -2
  6. package/install/_dev-only-files.mjs +1 -0
  7. package/install/templates/claude-hooks.json +12 -1
  8. package/package.json +4 -3
  9. package/pipeline/agents/android-architect.md +1 -0
  10. package/pipeline/agents/backend-architect.md +1 -0
  11. package/pipeline/agents/bulk-reader.md +57 -0
  12. package/pipeline/agents/code-reviewer.md +1 -0
  13. package/pipeline/agents/dev-critic.md +2 -1
  14. package/pipeline/agents/explorer.md +1 -0
  15. package/pipeline/agents/ios-architect.md +1 -0
  16. package/pipeline/agents/security-auditor.md +1 -0
  17. package/pipeline/agents/task-clarifier.md +1 -0
  18. package/pipeline/commands/multi-agent/manual-test/SKILL.md +5 -1
  19. package/pipeline/commands/multi-agent/resume/SKILL.md +1 -0
  20. package/pipeline/commands/multi-agent/setup/SKILL.md +7 -5
  21. package/pipeline/commands/multi-agent/store-ready/SKILL.md +22 -0
  22. package/pipeline/commands/sim-test.md +10 -5
  23. package/pipeline/multi-agent-refs/channels/pr.md +22 -4
  24. package/pipeline/multi-agent-refs/features/autopilot-circuit-breaker.md +15 -2
  25. package/pipeline/multi-agent-refs/features/review-delta.md +89 -0
  26. package/pipeline/multi-agent-refs/features/scope-check.md +41 -0
  27. package/pipeline/multi-agent-refs/features/verify-by-test.md +6 -5
  28. package/pipeline/multi-agent-refs/features/worktree-finalize.md +1 -1
  29. package/pipeline/multi-agent-refs/payload-contracts.md +1 -1
  30. package/pipeline/multi-agent-refs/phases/phase-3-dev.md +17 -2
  31. package/pipeline/multi-agent-refs/phases/phase-4-review.md +46 -8
  32. package/pipeline/multi-agent-refs/phases/phase-5-test.md +10 -0
  33. package/pipeline/multi-agent-refs/phases/phase-6-commit.md +2 -0
  34. package/pipeline/multi-agent-refs/phases/phase-7-report.md +4 -2
  35. package/pipeline/multi-agent-refs/picker-contract.md +1 -1
  36. package/pipeline/multi-agent-refs/rules.md +2 -2
  37. package/pipeline/schemas/agent-state.schema.json +129 -0
  38. package/pipeline/schemas/bulk-read-output.schema.json +52 -0
  39. package/pipeline/schemas/dev-critic-output.schema.json +5 -0
  40. package/pipeline/schemas/prefs.schema.json +121 -19
  41. package/pipeline/schemas/reviewer-output.schema.json +7 -2
  42. package/pipeline/schemas/scope-check.schema.json +55 -0
  43. package/pipeline/schemas/token-budget.json +3 -3
  44. package/pipeline/schemas/triage-output.schema.json +12 -2
  45. package/pipeline/scripts/README.md +3 -2
  46. package/pipeline/scripts/_fingerprint.mjs +173 -0
  47. package/pipeline/scripts/bulk-read.sh +277 -0
  48. package/pipeline/scripts/check-read-size.py +335 -0
  49. package/pipeline/scripts/check-read-size.sh +86 -0
  50. package/pipeline/scripts/evidence-gate.mjs +73 -5
  51. package/pipeline/scripts/finding-fingerprint.mjs +101 -0
  52. package/pipeline/scripts/pre-commit-check.sh +1 -0
  53. package/pipeline/scripts/review-delta.mjs +217 -0
  54. package/pipeline/scripts/run-metrics.mjs +20 -0
  55. package/pipeline/scripts/scope-check-gate.mjs +90 -0
  56. package/pipeline/scripts/smoke-cross-cli-behavior.sh +11 -4
  57. package/pipeline/scripts/uninstall.mjs +1 -0
  58. package/pipeline/scripts/validate-reviewer.mjs +6 -0
  59. package/pipeline/scripts/validate-triage.mjs +20 -0
  60. package/pipeline/skills/shared/core/multi-agent-store-ready/SKILL.md +5 -0
  61. package/pipeline/skills/shared/external/backlog/SKILL.md +10 -6
package/CHANGELOG.md CHANGED
@@ -16,6 +16,53 @@ Internal file-layout changes that don't affect the slash-command surface are sti
16
16
 
17
17
  ## [Unreleased]
18
18
 
19
+ ## [16.21.0] - 2026-09-08
20
+
21
+ ### Added
22
+
23
+ - **A read-size gate, and a cheap worker to send an oversized read to.** `offload-ref.sh` took half the machinery bill in 15.10.0 - the build log, the diff, the test output become a pointer plus a tail. The other half was never looked at, because nothing could look at it: only a `PreToolUse` hook sees a tool call before it runs. A phase that reads six 900-line files pays for 5,400 lines at that phase's own rung, and the part it needed was a handful of symbols.
24
+
25
+ `check-read-size.sh` (+ `check-read-size.py`, the decision core) is the third hook in `install/templates/claude-hooks.json` and the first on the READ side. `bulk-read.sh` is where a blocked read goes instead: the file reaches a haiku-rung worker over the `bulk-reader` persona, and what comes back is a structured summary with LINE NUMBERS, so the caller's next step is a bounded `Read(offset:limit:)` around the region that matters - which is cheap, exact, and passes the gate. The full text is parked under `.multi-agent/refs/`, the same place and the same promise `offload-ref.sh` makes.
26
+
27
+ **`observe` is a real mode, not a debug flag.** It decides and logs, blocks nothing, and it is what `bulkRead.mode` should be set to first: a gate switched straight to `enforce` has no baseline to be compared against, and "we cut tokens" becomes a claim nothing can check. The saving is measured from `metrics.jsonl` (`read.observed` / `read.blocked` / `bulk_read.delegated`), not asserted here - this entry deliberately quotes no percentage.
28
+
29
+ **Phase 3 is exempt, and that is load-bearing.** Claude Code's `Edit` requires the same file to have been `Read` first, so a gate that blocks reads while code is being changed blocks the change. So does any file the run itself has touched (`phases[n].files[]`). The gate is for the phases that read to UNDERSTAND. A draft of the decision core read `run.phase` and `dev.editSet` - neither of which `agent-state.schema.json` declares - so the exemption could never have engaged and development would have been blocked by a hook whose message read like advice; `smoke-bulk-read.sh` now asserts the field names against the schema so it cannot come back quietly.
30
+
31
+ **A ceiling, because delegation is not free either** (`bulkRead.maxBytes`, default 1 MB). Past some size the worker's own input bill approaches the read it replaced, and a file large enough to strain its window comes back truncated - a partial summary presented as a whole one is the one thing this feature must never produce. Over the ceiling the caller is told to narrow first (grep, then a bounded read). The check runs BEFORE the file is hashed or parked, so the guard is not theatre.
32
+
33
+ **The command parser is per-tool, because the flags are not shared.** `cat -n` NUMBERS LINES rather than taking a count, and reading its next token as one swallowed the filename, left no operand, and let `cat -n <bigfile>` through the gate entirely. `sed -n '1,900p'` looked bounded because it carried a flag, when the range in its script IS the bound. An unparseable count reads as UNBOUNDED, never as 1. A `tail -f` is a stream and passes, because blocking it would be a false positive with no cheap alternative to offer.
34
+
35
+ Off by default (`bulkRead.mode: "off"`), so merging the hook block is not itself a behaviour change. The worker degrades rather than inventing: no CLI, no auth, a timeout, or a non-JSON answer prints why and tells the caller to do a bounded read. A fabricated summary of a file nobody read is the one outcome worse than paying full price for the file.
36
+
37
+ ### Changed
38
+
39
+ - **`multi-agent:setup` Step 8 and the picker-contract stop miscounting the hooks.** Both said two gates ship, and the setup step called the secret scan "the only deterministic gate that is OS-enforceable as a hook" - untrue since `agent-guard.sh` landed. Three ship now, and both places say so, along with which side of the run each one inspects.
40
+ - **`smoke-gate-hooks.sh` covers all three gates** rather than two, and asserts the shipped defaults are safe (the read gate off, phase 3 exempt) - a read gate that shipped switched on would have been a breaking change disguised as a merge.
41
+
42
+
43
+ ## [16.20.0] - 2026-09-07
44
+
45
+ A comparison against `msitarzewski/agency-agents`, a 150k-star persona catalog, found nothing to copy wholesale and three things to fix: the personas were never registered, the circuit-breaker was prose, and a review finding had no identity from one round to the next. This release gives findings that identity and builds the loop controls, the handoff records and the evidence rules on top of it.
46
+
47
+ ### Added
48
+
49
+ - **A finding keeps its identity across review rounds.** `finding-fingerprint.mjs` stamps every reviewer, triage and dev-critic finding with `F:xxxxxxxx`, computed from the file and either the cited rule ID or the normalised issue text; the line, the severity and the fix text take no part, so a finding whose line moved after the fix is still the same finding. `review-delta.mjs` compares one round's triage with the previous one and reports `stillPresent`, `resolved`, `downgraded` and `new`, plus how many consecutive rework cycles each survivor has lasted. Phase 4 keeps one `.pipeline/triage-round-<N>.json` per round, injects the previous round's accepted findings into the shared reviewer prefix so reviewers echo instead of rediscover, and stores the delta in `state.reviewIterations[i].delta`. The Phase 3 reflection prompt puts the survivors first, marked `STILL PRESENT`.
50
+ - **The circuit-breaker has two triggers in code.** Trigger 2 (a blocking or important finding that survives `identicalFindingCycles` consecutive rework cycles, default 2) fires from `review-delta.mjs` exit 3 at Phase 4 Step 3.8; trigger 3 (the rework cap) is recorded by the Phase 3 re-entry. Both write `state.circuitBreaker` and halt visibly in autopilot; interactive modes show the survivors and ask. `prefs.global.autopilotCircuitBreaker` and `state.circuitBreaker` now exist in the schemas the feature doc had been naming, `resume` clears the trip, and `smoke-autopilot-circuit-breaker` asserts the schema fields, the scripts and the phase wiring instead of grepping the prose.
51
+ - **Dev states its scope before review reads it.** Phase 3 Step 3.7 writes `.pipeline/scope-check.json`: a reason per touched file, the changes deliberately not made, and the code-simplifier rationales that used to be discarded. `scope-check-gate.mjs` compares it with the real diff; Phase 4 renders it as `<scope-self-check>` so reviewers judge against the stated scope and do not re-propose what was rejected; Phase 6 builds the PR `Changes` bullets and a "Follow-ups not done in this PR" list from it.
52
+ - **PR bodies carry a risk section when the diff earns one.** `channels/pr.md` gains the conditional `## Risk and Security` section (auth flow touched, secret handling changed, data migration, rollback), required whenever `state.diffRisk.signals` carries a high-stakes signal. Phase 4 now persists the diff-risk totals to `state.diffRisk`, and `run-metrics.mjs` reports `diff.filesTouched`, `locAdded`, `locRemoved` and the cross-round delta.
53
+ - **Manual test results are evidence, not a chat reply.** Phase 5 writes `.pipeline/manual-test.json` with one row per acceptance criterion (the quoted spec, the observation, the verdict, the screenshot) and `evidence-gate.mjs --claim manual` refuses an "ok" whose criteria are missing, failed or untested without a reason. The simulator UI report pairs every bug with its spec quote and its before/after captures and ends with a production-readiness verdict that defaults to FAILED.
54
+ - **One green run is not proof.** Verify-by-test re-runs a passing repro test `verifyByTest.repeatCount` times (default 3) before it may downgrade a blocking finding; a run that disagrees makes the verdict `inconclusive` with a `flaky` note. Phase 3 runs every new or changed test `testStability.repeatCount` times (default 3) and records `test.flake_signal` when outcomes disagree: a test that passes only on retry is a flake signal, not a pass.
55
+ - **Persona files round-trip and store readiness asks about symbols and rollout.** `lint-personas.mjs` checks every persona's frontmatter, its `## Output Format` section, and that the Codex TOML rendered from it decodes back to the same description and body byte for byte; the renderer no longer appends a newline the source did not have. The smokes that hardcoded six persona names now derive the list from the directory. `store-ready` flags an archive without dSYMs (or a minified bundle without `mapping.txt`) as blocking, checks that a symbol upload step exists, and ends the report with the phased-rollout thresholds and the rollback owner a release needs written down.
56
+
57
+ ### Changed
58
+
59
+ - **Token budgets: phase-4-review max 14750 -> 15150, total 58250 -> 60250.** The full contracts for the review delta and the scope self-check live in `multi-agent-refs/features/review-delta.md` and `features/scope-check.md`, outside the budget; the phase docs carry the call, the pref and the exit table, and were compressed twice before the numbers moved. `rules.md` was tightened by 150 bytes to keep the fixed per-run load under its 60000-byte ceiling. Reasoning in `schemas/token-budget.json`.
60
+
61
+ ### Fixed
62
+
63
+ - **Phase 4 and Phase 7 disagreed on the triage file name.** Phase 4 wrote `.pipeline/triage.json`; Phase 7, `worktree-finalize.sh`, `render-work-summary.sh` and `diff-explain.mjs` read `triage-output.json`. The salvage step bridged it only when the worktree was removed, and everywhere else the triage corpus and the learnings ledger silently stopped being fed. Phase 4 now copies the latest round to `triage-output.json` itself.
64
+ - **The eight personas were never registered as subagents.** `pipeline/agents/*.md` carried `description`, `model`, `preferredModel` and `modelRationale` but no `name:`, and Claude Code drops a subagent file without one silently: no error, no agent. Every `subagent_type: "code-reviewer"`, `"ios-architect"`, `"security-auditor"`, `"dev-critic"` and `"task-clarifier"` dispatch in the phase docs named an agent the host did not have. Each persona now declares `name:` equal to its filename stem, and `smoke-agent-model-routing` fails when a persona lacks it, when the name differs from the stem, or when it is not lowercase kebab-case. Found while comparing the persona format against `msitarzewski/agency-agents`, whose linter treats `name` as a required field.
65
+
19
66
  ## [16.19.0] - 2026-09-02
20
67
 
21
68
  A review of the three repositories together (pipeline, toolkit MCP, plugin marketplace) with every test suite green found the defects the suites could not see. This release fixes what was found in the pipeline; `@mmerterden/multi-agent-toolkit-mcp` 3.8.0 and the marketplace plugins carry their own halves.
package/README.md CHANGED
@@ -213,7 +213,7 @@ The pipeline runs natively on **Claude Code**, **Copilot CLI** and **Codex CLI**
213
213
 
214
214
  | Tool | Flag | What it installs |
215
215
  |---|---|---|
216
- | Claude Code | `--claude` (default) | slash commands + skills + agents + `PreToolUse` secret-scan hook |
216
+ | Claude Code | `--claude` (default) | slash commands + skills + agents + three `PreToolUse` hooks (secret scan, agent-guard, read-size gate) |
217
217
  | Copilot CLI | `--copilot` | instructions + 55 sub-command skills + scripts |
218
218
  | Codex CLI | `--codex` | one router skill + 55 specs as refs + 8 agent TOML + `AGENTS.md` block + `codex mcp add` |
219
219
 
package/README.tr.md CHANGED
@@ -213,7 +213,7 @@ Pipeline **Claude Code**, **Copilot CLI** ve **Codex CLI** üzerinde native çal
213
213
 
214
214
  | Araç | Bayrak | Ne kurar |
215
215
  |---|---|---|
216
- | Claude Code | `--claude` (varsayılan) | slash komutları + skill'ler + agent'lar + `PreToolUse` secret-scan hook'u |
216
+ | Claude Code | `--claude` (varsayılan) | slash komutları + skill'ler + agent'lar + üç `PreToolUse` hook'u (secret scan, agent-guard, okuma-boyutu geçidi) |
217
217
  | Copilot CLI | `--copilot` | talimatlar + 55 alt-komut skill'i + script'ler |
218
218
  | Codex CLI | `--codex` | bir router skill + ref olarak 55 spec + 8 agent TOML + `AGENTS.md` bloğu + `codex mcp add` |
219
219
 
package/docs/features.md CHANGED
@@ -222,6 +222,7 @@ Phase 3 treats the issue-tracker status update as a required step with a post-mu
222
222
  ## Safety & Hygiene
223
223
 
224
224
  - **Pre-Commit Secret Detection** (12 patterns): `PreToolUse` hook scans staged files for API keys/tokens, AWS access keys, private keys, `.env` files, service account JSON. Commit **blocked** if found.
225
+ - **Read-Size Gate** (opt-in, `prefs.global.bulkRead.mode`): a `PreToolUse` hook inspects `Read` and the shell commands that read a file whole. In `observe` it only logs what it would have caught - the baseline you measure before routing anything. In `enforce` a file over `minLines` (default 350) is blocked and delegated to a haiku-rung worker (`bulk-read.sh`), which returns a line-numbered summary so the follow-up is a bounded `Read(offset:limit:)` instead of the whole file; the full text is parked under `.multi-agent/refs/`. The development phase and any file the run has already touched are exempt, because Claude Code's `Edit` requires its own `Read` first.
225
226
  - **Build Queue**: All `xcodebuild` calls acquire a lock. Each worktree uses own `-derivedDataPath`. Stale locks auto-clean after 15 min. Non-Xcode builds don't need the lock.
226
227
  - **Context Management**: `CLAUDE_AUTOCOMPACT_PCT_OVERRIDE=65` - compaction at 65% usage (prevents degradation in 8-phase sessions).
227
228
  - **3-Iteration Hard Kill**: Any retry loop stops after 3 attempts, then pauses for user. No infinite loops.
@@ -94,10 +94,10 @@ export function tomlString(s) {
94
94
  return JSON.stringify(s);
95
95
  }
96
96
  if (!s.includes("'''")) {
97
- return `'''\n${s}\n'''`;
97
+ return `'''\n${s}'''`;
98
98
  }
99
99
  const escaped = s.replace(/\\/g, "\\\\").replace(/"""/g, '\\"\\"\\"');
100
- return `"""\n${escaped}\n"""`;
100
+ return `"""\n${escaped}"""`;
101
101
  }
102
102
 
103
103
  /**
@@ -59,6 +59,7 @@ const DEV_ONLY_TOOLING = Object.freeze([
59
59
  "run-smokes.mjs",
60
60
  "scorecard.mjs",
61
61
  "lint-skills.mjs",
62
+ "lint-personas.mjs", // imports install/_codex-agents.mjs, which never ships to scripts/
62
63
  "lint-mcp-refs.mjs",
63
64
  "check-md-links.mjs",
64
65
  "validate-schemas.mjs", // validates the repo's own schema files, needs ajv
@@ -1,5 +1,5 @@
1
1
  {
2
- "_readme": "Recommended Claude Code hooks for multi-agent-pipeline. Merge the `hooks` object into your ~/.claude/settings.json to make these deterministic, OS-enforced PreToolUse gates real (exit 2 blocks the tool call) rather than prompt-level hopes. Two gates ship here: (1) a staged-diff secret scan on git commit (pre-commit-check.sh); (2) an agent-guard on git commit + git push (agent-guard.sh) that blocks AI/assistant attribution in commit messages and force-push to a protected branch (main/master/develop). Both scripts are self-contained, fail-open on internal error, never execute the inspected command, and need no run-specific arguments, which is why they are naturally PreToolUse hooks. The other deterministic gates (evidence, consensus, intent, learnings) take run-specific arguments and are phase-enforced by the pipeline instead. multi-agent:setup offers to merge this block.",
2
+ "_readme": "Recommended Claude Code hooks for multi-agent-pipeline. Merge the `hooks` object into your ~/.claude/settings.json to make these deterministic, OS-enforced PreToolUse gates real (exit 2 blocks the tool call) rather than prompt-level hopes. Three gates ship here: (1) a staged-diff secret scan on git commit (pre-commit-check.sh); (2) an agent-guard on git commit + git push (agent-guard.sh) that blocks AI/assistant attribution in commit messages and force-push to a protected branch (main/master/develop); (3) a read-size gate on Read and Bash (check-read-size.sh), which inspects Read plus the shell commands that read a file whole (cat/head/tail/sed) and returns immediately for everything else, which routes an oversized read to a cheap worker instead of the caller's own rung. The first two inspect what a run WRITES; the third inspects what it pays to READ, and it is inert until `prefs.global.bulkRead.mode` is set to observe or enforce - so merging this block changes nothing until you opt in. All three are self-contained, fail-open on internal error, never execute the inspected command, and need no run-specific arguments, which is why they are naturally PreToolUse hooks. The other deterministic gates (evidence, consensus, intent, learnings) take run-specific arguments and are phase-enforced by the pipeline instead. multi-agent:setup offers to merge this block.",
3
3
  "hooks": {
4
4
  "PreToolUse": [
5
5
  {
@@ -29,6 +29,17 @@
29
29
  "statusMessage": "Checking push safety..."
30
30
  }
31
31
  ]
32
+ },
33
+ {
34
+ "matcher": "Read|Bash",
35
+ "hooks": [
36
+ {
37
+ "type": "command",
38
+ "command": "bash $HOME/.claude/scripts/check-read-size.sh",
39
+ "timeout": 10,
40
+ "statusMessage": "Checking read size..."
41
+ }
42
+ ]
32
43
  }
33
44
  ]
34
45
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mmerterden/multi-agent-pipeline",
3
- "version": "16.19.0",
3
+ "version": "16.21.0",
4
4
  "description": "8-phase AI development pipeline with full orchestration on Claude Code, Copilot CLI and Codex CLI. Analysis, planning, TDD, CLI-aware parallel review with consensus surfacing + Fable triage, default-FAIL evidence gates, secret + intent guards, per-phase cost ledger, persistent learnings memory, wiki generation, commit automation. Token-preserving uninstall.",
5
5
  "type": "module",
6
6
  "main": "index.js",
@@ -14,11 +14,11 @@
14
14
  },
15
15
  "scripts": {
16
16
  "start": "node index.js",
17
- "test": "npm run format:check && node --test test/*.test.mjs && node pipeline/scripts/run-smokes.mjs && node pipeline/scripts/lint-skills.mjs && node pipeline/scripts/lint-mcp-refs.mjs && node pipeline/scripts/eval-triage.mjs && node pipeline/scripts/eval-golden-tasks.mjs && node pipeline/scripts/eval-intent.mjs && node pipeline/scripts/eval-recall.mjs && node pipeline/scripts/validate-schemas.mjs && node pipeline/scripts/validate-prefs.mjs && node pipeline/scripts/scorecard.mjs",
17
+ "test": "npm run format:check && node --test test/*.test.mjs && node pipeline/scripts/run-smokes.mjs && node pipeline/scripts/lint-skills.mjs && node pipeline/scripts/lint-personas.mjs && node pipeline/scripts/lint-mcp-refs.mjs && node pipeline/scripts/eval-triage.mjs && node pipeline/scripts/eval-golden-tasks.mjs && node pipeline/scripts/eval-intent.mjs && node pipeline/scripts/eval-recall.mjs && node pipeline/scripts/validate-schemas.mjs && node pipeline/scripts/validate-prefs.mjs && node pipeline/scripts/scorecard.mjs",
18
18
  "test:unit": "node --test test/*.test.mjs",
19
19
  "test:smoke": "node pipeline/scripts/run-smokes.mjs",
20
20
  "lint:skills": "node pipeline/scripts/lint-skills.mjs",
21
- "test:quick": "node --test test/*.test.mjs && node pipeline/scripts/lint-skills.mjs && node pipeline/scripts/lint-mcp-refs.mjs",
21
+ "test:quick": "node --test test/*.test.mjs && node pipeline/scripts/lint-skills.mjs && node pipeline/scripts/lint-personas.mjs && node pipeline/scripts/lint-mcp-refs.mjs",
22
22
  "test:coverage": "c8 --clean --reporter=none node --test test/*.test.mjs && c8 --clean=false --check-coverage --reporter=text --reporter=lcov node pipeline/scripts/run-smokes.mjs",
23
23
  "lint": "eslint .",
24
24
  "lint:fix": "eslint . --fix",
@@ -85,6 +85,7 @@
85
85
  "!pipeline/scripts/eval-*.mjs",
86
86
  "!pipeline/scripts/scorecard.mjs",
87
87
  "!pipeline/scripts/lint-skills.mjs",
88
+ "!pipeline/scripts/lint-personas.mjs",
88
89
  "!pipeline/scripts/lint-mcp-refs.mjs",
89
90
  "!pipeline/scripts/check-md-links.mjs",
90
91
  "!pipeline/scripts/validate-schemas.mjs",
@@ -1,4 +1,5 @@
1
1
  ---
2
+ name: android-architect
2
3
  description: Android architect - evaluates design decisions, patterns, and module structure
3
4
  model: fable
4
5
  preferredModel: fable
@@ -1,4 +1,5 @@
1
1
  ---
2
+ name: backend-architect
2
3
  description: Backend architect - evaluates API design, data modeling, and system architecture
3
4
  model: fable
4
5
  preferredModel: fable
@@ -0,0 +1,57 @@
1
+ ---
2
+ name: bulk-reader
3
+ description: "Reads ONE large file and returns a structured, line-numbered summary so the full text never enters the caller's context. Dispatched by bulk-read.sh when check-read-size.sh blocks a whole-file read. Haiku by default; a delegated read costs a fraction of a cent."
4
+ model: haiku
5
+ preferredModel: haiku
6
+ modelRationale: "Reading a file and reporting what is in it is extraction, not judgement - the task has a single source, a fixed output shape, and no reasoning chain. Haiku is the right rung and the whole point: the saving is the difference between this rung and the caller's. A worker that reasons is the wrong tool here, and the contract below forbids it explicitly, because a cheap rung's opinion about code is worth less than nothing."
7
+ ---
8
+
9
+ # Bulk Reader
10
+
11
+ You are given ONE file and ONE question. You return ONE JSON object and nothing
12
+ else: no prose before it, no markdown fence around it, no commentary after it.
13
+
14
+ The file arrives with its lines numbered. Those numbers are the file's own, so a
15
+ number you report is a number the caller can open directly.
16
+
17
+ ## Rules
18
+
19
+ - **Every claim carries the line numbers it comes from.** A claim without them is
20
+ not usable - the caller cannot open it, cannot check it, and ends up reading
21
+ the file itself, having now paid for it twice. If you cannot cite it, do not
22
+ claim it.
23
+ - **You describe what IS in the file.** You do not review it, do not judge its
24
+ quality, do not propose changes, and do not name defects. Judgement about code
25
+ is the caller's; you are here so the caller has something to judge.
26
+ - **You never guess.** If the question cannot be answered from this file, say
27
+ exactly that in `answer` and return an empty `regions`. A confident wrong
28
+ summary is the one outcome worse than the caller paying full price for the
29
+ file, because nothing downstream can tell it is wrong.
30
+ - **`regions` are where a reader should look next**, most important first, at
31
+ most 8. Each one is a span worth opening on its own - not the whole file
32
+ restated as one region.
33
+ - If you did not see the whole file, set `truncated: true`. Do not summarize a
34
+ part as though it were the whole.
35
+
36
+ ## Output Format
37
+
38
+ ```json
39
+ {
40
+ "answer": "<direct answer to the question, or why this file cannot answer it>",
41
+ "summary": "<what this file is and does, 3-6 sentences>",
42
+ "symbols": [{"name": "<declaration>", "kind": "type|func|var|extension|other", "line": 42}],
43
+ "regions": [{"why": "<what a reader finds here>", "start": 120, "end": 180}],
44
+ "truncated": false
45
+ }
46
+ ```
47
+
48
+ Contract: `pipeline/schemas/bulk-read-output.schema.json`.
49
+
50
+ ## What this agent does NOT do
51
+
52
+ - Does NOT review, rate, or critique the code it reads.
53
+ - Does NOT read a second file, follow an import, or look anything up.
54
+ - Does NOT answer from prior knowledge of a framework - only from this file.
55
+ - Does NOT edit anything. It has no write path by design: a summary has no
56
+ reliable basis for an edit, which is why the caller comes back with a bounded
57
+ read before changing a line.
@@ -1,4 +1,5 @@
1
1
  ---
2
+ name: code-reviewer
2
3
  description: "Code reviewer for multi-agent Phase 4 - security, architecture, quality, performance. Default model is fable (opus is the first fallback); Phase 4 orchestrator overrides to sonnet for Reviewer 3."
3
4
  model: fable
4
5
  preferredModel: fable
@@ -1,4 +1,5 @@
1
1
  ---
2
+ name: dev-critic
2
3
  description: "Phase 3.5 evaluator - runs after Dev's last edit, before Phase 4. Verifies build/test/checklist gates; returns pass | fix-list. Sonnet by default; Phase 3 orchestrator may override."
3
4
  model: sonnet
4
5
  preferredModel: sonnet
@@ -79,7 +80,7 @@ Apply the platform checklist verbatim. **Cite the rule file + line/section** so
79
80
  - **Max 2 critic iterations.** Generator gets feedback, edits, you re-evaluate. If round 2 still fails gates, **escalate**: return `escalate: true` and let the orchestrator decide (pause user / abort / continue with known failures).
80
81
  - Round 1 budget: full critic pass with all gates + checklist.
81
82
  - Round 2 budget: ONLY re-check the items that failed round 1. Don't re-flag what the generator fixed.
82
- - Never add new findings in round 2 that weren't in round 1's output - that's scope creep, not iteration.
83
+ - Never add new findings in round 2 that weren't in round 1's output - that's scope creep, not iteration. Round-2 findings carry the round-1 `fingerprint` (`finding-fingerprint.mjs annotate --kind dev-critic`); a round-2 finding with no round-1 fingerprint is the scope creep this rule forbids.
83
84
 
84
85
  ## Output Format
85
86
 
@@ -1,4 +1,5 @@
1
1
  ---
2
+ name: explorer
2
3
  description: "Codebase explorer agent for multi-agent Phase 1 - scans project structure, patterns, and impact areas"
3
4
  model: sonnet
4
5
  preferredModel: sonnet
@@ -1,4 +1,5 @@
1
1
  ---
2
+ name: ios-architect
2
3
  description: iOS architect - evaluates design decisions, patterns, and module structure
3
4
  model: fable
4
5
  preferredModel: fable
@@ -1,4 +1,5 @@
1
1
  ---
2
+ name: security-auditor
2
3
  description: Security specialist - analyzes code for vulnerabilities and compliance issues
3
4
  model: opus
4
5
  preferredModel: opus
@@ -1,4 +1,5 @@
1
1
  ---
2
+ name: task-clarifier
2
3
  description: "Phase 0 Step 9 task ambiguity scorer - reads task description, emits clarity score (0-10) and up to N clarifying questions. Haiku by default; cost stays under 1¢ per call."
3
4
  model: haiku
4
5
  preferredModel: haiku
@@ -47,5 +47,9 @@ Lets you switch to the task branch for manual testing in Xcode before the PR is
47
47
  5. **Wait for the user's reply**
48
48
 
49
49
  6. **Branch on the answer**:
50
- - **OK** → `phase-tracker.sh update 5 completed` + `phase-tracker.sh meta 5 Result "local test passed (user)"`, recreate the worktree, continue to Phase 6
50
+ - **OK** → first write `$WORKTREE/.pipeline/manual-test.json` (one entry per acceptance criterion from the analysis doc test plan, the plan tasks, or the user's own words):
51
+ ```json
52
+ {"criteria":[{"spec":"<quote>","source":"analysis 15.2 | plan task 3 | user","observed":"<what was seen>","verdict":"pass|fail|not-tested","reason":"<required when not-tested>","screenshot":"<path or null>"}],"verdict":"passed|failed"}
53
+ ```
54
+ then run `node $HOME/.claude/scripts/evidence-gate.mjs --claim manual --status passed --evidence "$WORKTREE/.pipeline/manual-test.json"`. Exit 1 means the "ok" is not accepted: name the criterion that is missing evidence and wait for the next reply. Exit 0 → `phase-tracker.sh update 5 completed` + `phase-tracker.sh meta 5 Result "local test passed (user)"`, recreate the worktree, continue to Phase 6. Full contract: `$HOME/.claude/multi-agent-refs/phases/phase-5-test.md` step 5.
51
55
  - **Fix needed** → `phase-tracker.sh now 5 "applying fix: <summary>"`, recreate the worktree, apply the fix
@@ -23,6 +23,7 @@ Resume a paused or failed task from the last successful phase.
23
23
  - `currentPhase` - last completed phase
24
24
  - `status` - `paused` | `failed` | `in_progress`
25
25
  - `haltReason` - if set, show it so the user knows why the run stopped; clear it on successful re-entry
26
+ - `circuitBreaker` - if `tripped`, show `trigger` + `detail`, then set `tripped: false` and keep `counters`; if the same trigger fires again at the next checkpoint the breaker re-trips (no silent bypass)
26
27
  - `autopilot` - preserve the mode
27
28
 
28
29
  3. **Load context** - rebuild working context from durable artifacts, never from conversation memory:
@@ -813,13 +813,15 @@ To set up multi-agent on a new machine:
813
813
 
814
814
  All tokens are optional in the sense that every service can be answered with Skip - but the ASKING is not optional: the Step 3 sequential loop still walks every missing service one by one (token → author → host). Phase 0 re-asks at runtime only for tokens the user skipped here.
815
815
 
816
- ### Step 8 - Enforcement hook (optional, Claude Code)
816
+ ### Step 8 - Enforcement hooks (optional, Claude Code)
817
817
 
818
- Offer to make the secret scan a HARD pre-commit gate (a non-zero exit blocks the commit) instead of an advisory step. The recommended block ships at `install/templates/claude-hooks.json`.
818
+ Offer to make the three hookable gates HARD (a non-zero exit blocks the tool call). The block ships at `install/templates/claude-hooks.json`: secret scan, agent-guard, read-size gate.
819
+
820
+ - Ask (picker): "Install the pipeline's PreToolUse gates into `~/.claude/settings.json`?" Default Yes.
821
+ - On Yes, deep-merge the template's `hooks.PreToolUse` (preserve existing hooks; never duplicate a matcher already calling the same script).
822
+ - Say what the merge does NOT cover: only these three need no run-specific arguments, so only these three are hookable; the rest are phase-enforced.
823
+ - Say what it does not turn on: the read-size gate is inert until `prefs.global.bulkRead.mode` is set. Recommend `observe` first. Why, and the Phase 3 exemption: `$HOME/.claude/multi-agent-refs/picker-contract.md`.
819
824
 
820
- - Ask (picker): "Install the pre-commit secret-scan hook into `~/.claude/settings.json`?" Default Yes.
821
- - On Yes, deep-merge the template's `hooks.PreToolUse` into the user's `settings.json` (preserve any existing hooks; do not duplicate a matcher that already calls `pre-commit-check.sh`).
822
- - Honest note to show: this is the only deterministic gate that is OS-enforceable as a hook (it needs no run-specific arguments). The evidence / consensus / intent / learnings gates are invoked by the pipeline phases with per-run arguments, so they are enforced by the phase contract + the installed gate scripts, not by a hook.
823
825
  ### Step 9 - Default stack plugin enablement
824
826
 
825
827
  Stack skills ship as versioned plugins in the `{owner}/multi-agent-plugins` marketplace. On first setup, wire the stack so the pipeline works out of the box.
@@ -218,10 +218,22 @@ is a guess the user must be able to correct.
218
218
  Use the fallback only when the tool is genuinely absent, and say in the report
219
219
  which path ran - a rule set that silently differed between two invocations is
220
220
  worse than a missing gate.
221
+
222
+ Then, whichever path ran, count `<archive>/dSYMs/*.dSYM`. Zero is a blocking
223
+ finding: `[SYMBOLS] archive carries no dSYM; crash reports will not symbolicate`,
224
+ with the hint `DEBUG_INFORMATION_FORMAT = dwarf-with-dsym` for the Release
225
+ configuration. This check runs from the package alone and does not need the
226
+ MCP tool.
221
227
  - **Android**: `android_apk_audit` on the artifact, plus the
222
228
  `google-play-compliance` skill's 21 rules - `bundletool validate` and manifest
223
229
  dump, `aapt2 dump badging`, `apksigner verify`, ABI / native scan.
224
230
 
231
+ Then, when the module has `minifyEnabled true` and the bundle build produced no
232
+ `mapping.txt`, raise the same class of blocking finding:
233
+ `[SYMBOLS] minified bundle carries no mapping.txt; crash reports will not
234
+ deobfuscate`. This check reads the module config and the build output alone
235
+ and does not need the MCP tool.
236
+
225
237
  `error` findings are blocking; `warning` is advisory. Group by severity and keep
226
238
  each finding's ITMS / Play policy code - Gate 2 may return the same code on iOS,
227
239
  and seeing it in both places tells the user it is real rather than a heuristic.
@@ -259,6 +271,7 @@ that catches what a human reviewer rejects, so it reads source, not the binary.
259
271
  | Privacy policy | reachable in-app and in the metadata |
260
272
  | IAP | anything unlocking features goes through StoreKit, with no external purchase path |
261
273
  | Sign in with Apple | present when a third-party social login is offered |
274
+ | Crash symbolication | a dSYM upload step exists: an Xcode run-script calling `upload-symbols`, or a Crashlytics / Sentry / Datadog upload in CI |
262
275
 
263
276
  **Android** - `ai-android-toolkit:play-store-review`:
264
277
 
@@ -272,6 +285,7 @@ that catches what a human reviewer rejects, so it reads source, not the binary.
272
285
  | Account deletion | if the app creates accounts, an in-app deletion path exists, plus the web deletion URL Play requires |
273
286
  | Content rating | the questionnaire answers match the app's actual content |
274
287
  | Signing | Play App Signing configured, upload key distinct from the app signing key |
288
+ | Crash symbolication | a `mapping.txt` upload exists: the Firebase Crashlytics Gradle plugin, or the Play App Bundle deobfuscation file |
275
289
 
276
290
  For each: `pass` / `fail` / `not-applicable` with the evidence path that justifies
277
291
  it. `not-applicable` needs a reason - an unexamined area is not a pass.
@@ -303,6 +317,12 @@ Advisory
303
317
 
304
318
  Not run
305
319
  Gate 2: no local Play validator - authoritative check is server-side only
320
+
321
+ Before rollout (human inputs, not verified)
322
+ Phased rollout: <1% -> 10% -> 50% -> 100% | full>
323
+ Halt thresholds: crash-free < 99.5% (iOS, Android) or ANR > 0.47% (Android) => pause the rollout
324
+ Rollback / forward-fix owner: <name>
325
+ Forward-fix plan: <one line>
306
326
  ```
307
327
 
308
328
  Rules for the report:
@@ -311,6 +331,8 @@ Rules for the report:
311
331
  skip. An Android run therefore reads `2 of 3 gates cleared, 1 skipped` at best.
312
332
  - Every blocking finding carries a file path or a store code. A finding the user
313
333
  cannot act on is noise.
334
+ - The `Before rollout` block is filled by a human, never inferred. When it is
335
+ left unfilled the verdict line gains the suffix `, rollout plan missing`.
314
336
  - Humanize via `--lang en` by default (`promptLanguage` is locked to `"en"`); pass
315
337
  `--lang=tr` explicitly to opt into Turkish.
316
338
  - No AI or assistant attribution anywhere, per
@@ -253,16 +253,18 @@ Then output full report:
253
253
  - **Steps**: 1. Open app -> 2. Tap {X} -> 3. Observe {issue}
254
254
  - **Expected**: {correct behavior}
255
255
  - **Actual**: {what's wrong}
256
+ - **Spec**: "<quoted acceptance criterion from the analysis doc Section 15 / 20, or: no spec, model expectation>" (<source>)
257
+ - **Evidence**: before=<png path> after=<png path>
256
258
 
257
259
  ### BUG-2: ...
258
260
 
259
261
  ## Screens Visited ({N})
260
262
 
261
- | # | Screen | Light | Dark | Large Text | Bugs |
262
- | --- | -------- | ----- | ----- | ---------- | ---- |
263
- | 1 | Home | ok | BUG-1 | ok | 1 |
264
- | 2 | Login | ok | ok | BUG-2 | 1 |
265
- | 3 | Settings | ok | ok | ok | 0 |
263
+ | # | Screen | Light | Dark | Large Text | Bugs | Evidence |
264
+ | --- | -------- | ----- | ----- | ---------- | ---- | -------- |
265
+ | 1 | Home | ok | BUG-1 | ok | 1 | 3 |
266
+ | 2 | Login | ok | ok | BUG-2 | 1 | 4 |
267
+ | 3 | Settings | ok | ok | ok | 0 | 2 |
266
268
 
267
269
  ## Summary
268
270
 
@@ -272,8 +274,11 @@ Then output full report:
272
274
  - Critical: {N} | Major: {N} | Minor: {N}
273
275
  - Accessibility audit (accessibility scenario): {N} audited, {N} not audited (reason per screen), deep pass: {ran / skipped: reason}
274
276
  - Crashes (full scenario): {N} during this run
277
+ - Production readiness: FAILED | NEEDS WORK | READY
275
278
  ```
276
279
 
280
+ `Evidence` in a bug block is the captures already written to files in Step 4: a tap-driven finding needs both `before` and `after`, a static finding (layout, contrast, dark mode, large text) needs `after` only. The `Evidence` column in Screens Visited is the count of screenshot files written for that screen. Production readiness defaults to FAILED; it is NEEDS WORK when only Minor bugs remain, and READY only when there are zero Critical / Major bugs and every planned screen was visited.
281
+
277
282
  Save to: `$HOME/.claude/logs/sim-test/{bundle_id}/{timestamp}.md`
278
283
 
279
284
  ### Step 7 - Fix Offer
@@ -14,14 +14,15 @@ The PR description targets code reviewers - it stays technical. Every adapter
14
14
  | 2 | `changes` | `## Değişiklikler` | `## Changes` | always |
15
15
  | 3 | `architecture` | `## Mimari Kararlar` | `## Architecture Decisions` | when a non-trivial design choice was made |
16
16
  | 4 | `verification` | `## Doğrulama` | `## Verification` | always |
17
- | 5 | `dependencies` | `## Bağımlılıklar` | `## Dependencies` | when deps added/removed/bumped |
18
- | 6 | `related` | `## İlgili` | `## Related` | always (Jira/issue ref; never `Closes/Fixes`) |
17
+ | 5 | `risk` | `## Risk ve Güvenlik` | `## Risk and Security` | when `state.diffRisk.signals` carries a high-stakes signal (`security_path`, `migration`, `public_api`, `no_test_change`, `test_lines_removed`) |
18
+ | 6 | `dependencies` | `## Bağımlılıklar` | `## Dependencies` | when deps added/removed/bumped |
19
+ | 7 | `related` | `## İlgili` | `## Related` | always (Jira/issue ref; never `Closes/Fixes`) |
19
20
 
20
21
  ### Section content rules
21
22
 
22
23
  **`summary`** - 1-3 sentences in `outputLanguage`. The "why" of the change. Past tense, no marketing voice. Code identifiers stay verbatim.
23
24
 
24
- **`changes`** - bullet list, one item per logically distinct change. Each bullet starts with the touched component and ends with a one-line "what". Use the stack's native file extensions / module paths - the example below shows the **shape**, not a stack lock-in:
25
+ **`changes`** - bullet list, one item per logically distinct change. Each bullet starts with the touched component and ends with a one-line "what". The source is `$WORKTREE/.pipeline/scope-check.json` `files[].reason` (Phase 3 Step 3.7): a file the dev could not justify there is a file this list cannot describe either, so the bullet quotes the gate output instead of inventing a reason. Use the stack's native file extensions / module paths - the example below shows the **shape**, not a stack lock-in:
25
26
 
26
27
  ```markdown
27
28
  ## Changes
@@ -50,6 +51,17 @@ Skeleton (the adapter fills the body with the actual stack-appropriate lines at
50
51
 
51
52
  Multi-repo PRs (one PR per repo) emit verification commands for that repo's stack only - never mix iOS + Android commands into a single PR body.
52
53
 
54
+ **`risk`** - only when `state.diffRisk.signals` (Phase 4 Step 1.75) contains a high-stakes signal. Four fixed lines, each answered, never left as a placeholder; the source is Phase 1 `touchedAreas` plus the signals themselves, and when a signal is present the absence of this section is a Phase 6 Step 3 blocker:
55
+
56
+ ```markdown
57
+ ## Risk and Security
58
+
59
+ - Auth flow touched: yes | no
60
+ - Secret handling changed: yes | no
61
+ - Data migration: yes | no
62
+ - Rollback: feature flag <name> | git revert <sha> | none, and why
63
+ ```
64
+
53
65
  **`dependencies`** - only when `Package.swift` / `Podfile` / `build.gradle` / `package.json` changed. Each entry: `package@old → new - reason`.
54
66
 
55
67
  **`related`** - flat list, plain text. Examples:
@@ -61,15 +73,21 @@ Multi-repo PRs (one PR per repo) emit verification commands for that repo's stac
61
73
  - Issue: #123
62
74
  - Confluence: <page-url> (if work referenced a spec)
63
75
  - Figma: <design-url> (if work referenced a design)
76
+
77
+ Follow-ups not done in this PR:
78
+ - <scope-check.json notDone[].what> - <why>
79
+ - <deferred triage finding> - <triage reason>
64
80
  ```
65
81
 
82
+ The follow-up list is present only when `scope-check.json` `notDone[]` or the final triage `deferred[]` is non-empty; the two sources merge into one list.
83
+
66
84
  Never use `Closes #N`, `Fixes #N`, `Resolves PROJ-X`. Issues require 4-approval close, the auto-close keywords break that contract.
67
85
 
68
86
  ### Assembly order (per run)
69
87
 
70
88
  ```
71
89
  1. Read agent-state.json (taskId, contextLinks, identity, language).
72
- 2. Build section bodies in markdown - summary first, then in the table order, skipping conditional sections that don't apply.
90
+ 2. Build section bodies in markdown - summary first, then in the table order, skipping conditional sections that don't apply. Section order is fixed: `summary` → `changes` → `architecture` (cond.) → `verification` → `risk` (cond.) → `dependencies` (cond.) → `related`.
73
91
  3. Run the assembled body through the `humanizer` skill.
74
92
  4. Apply Multi-repo cross-links (## Related PRs prepend when projects.length > 1).
75
93
  5. Dispatch per the Behaviour-by-remote table.
@@ -2,7 +2,7 @@
2
2
 
3
3
  **Pattern**: autopilot runs with zero interaction, which is exactly when a silent failure loop is most expensive - an agent can burn a budget re-attempting the same broken fix, or thrash between two phases, with nobody watching. A circuit-breaker converts "keep going no matter what" into "keep going until a defined unsafe condition, then halt and hand back to the user." This is the sanctioned autopilot pause (same class as the Phase 7 channels pause): the run stops, records why, and waits for an explicit `resume`.
4
4
 
5
- **Gated by `prefs.global.autopilotCircuitBreaker`** (default: enabled; thresholds tunable). Halting is always safe, so the breaker itself defaults on. Disable per-run only with an explicit override. Complements, does not replace, the existing autopilot safety rules (build-fail max 3 retries, Phase 4 blocking-finding rework, destructive-op confirmations).
5
+ **Gated by `prefs.global.autopilotCircuitBreaker`** (`enabled` default true, `identicalFindingCycles` default 2, `maxReworkCycles` default 3; `schemas/prefs.schema.json`). Halting is always safe, so the breaker itself defaults on. Disable per-run only with an explicit override. Complements, does not replace, the existing autopilot safety rules (build-fail max 3 retries, Phase 4 blocking-finding rework, destructive-op confirmations).
6
6
 
7
7
  ## Trip conditions
8
8
 
@@ -18,12 +18,25 @@ Any one trips the breaker. All are evaluated from `agent-state.json` + telemetry
18
18
 
19
19
  Trigger 2 is the key addition over the plain build-retry cap: a build can "fail differently" three times (legitimate iteration) or "fail identically" twice (stuck). Only the identical-failure case is a stall; the retry cap catches the rest.
20
20
 
21
+ ## Wiring status
22
+
23
+ | Trigger | Evaluated by | Status |
24
+ |---|---|---|
25
+ | 2, finding half | `review-delta.mjs` exit 3 at Phase 4 Step 3.8: a blocking/important finding whose `fingerprint` (finding-fingerprint.mjs) stays in the accepted set for `identicalFindingCycles` consecutive rounds | **code** (v16.20.0) |
26
+ | 3 | Phase 3 re-entry item 6: the `retryCount === 3` hard-kill records the trip | **code** (v16.20.0) |
27
+ | 2, build-error half | needs a build-log signature normaliser | documented behaviour, no script yet |
28
+ | 1 | needs checkpoint-to-checkpoint artifact diffing | documented behaviour, no script yet |
29
+ | 4 | belongs to `cost-budget-check.mjs` | documented behaviour, no script yet |
30
+ | 5 | Phase 6 push | documented behaviour, no script yet |
31
+
32
+ State shape: `state.circuitBreaker = {tripped, trigger, detail, checkpoint: {phase, step, iteration}, trippedAt, counters: {identicalFindingCycles, reworkCycles}}` (`schemas/agent-state.schema.json`). The per-round classification the finding half reads lives in `state.reviewIterations[i].delta` (`new`, `stillPresent`, `resolved`, `downgraded`, `recurrence`, `plateau`). `smoke-autopilot-circuit-breaker.sh` asserts the schema fields, the scripts and the phase wiring, not only this prose.
33
+
21
34
  ## Action on trip
22
35
 
23
36
  1. Set `agent-state.json.circuitBreaker = {tripped: true, trigger: <#>, detail, checkpoint}` and flip `autopilot` handling to paused (the run does not continue unattended).
24
37
  2. Emit one actionable line per the progress contract: what tripped, the evidence (error signature / cycle count / spend vs ceiling), and the single next action (`resume #N` after a fix, or `kill #N`).
25
38
  3. Never auto-resolve the underlying cause - no force-anything, no conflict auto-merge, no budget self-raise. The breaker hands control back; it does not paper over the problem.
26
- 4. `resume #N` clears the tripped flag and continues from the recorded checkpoint. If the same trigger fires again immediately, the breaker re-trips (no silent bypass).
39
+ 4. `resume #N` clears `circuitBreaker.tripped` (keeping `counters`) and continues from the recorded checkpoint. If the same trigger fires again immediately, the breaker re-trips (no silent bypass).
27
40
 
28
41
  ## Why this is the right autopilot exception
29
42