@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.
- package/CHANGELOG.md +47 -0
- package/README.md +1 -1
- package/README.tr.md +1 -1
- package/docs/features.md +1 -0
- package/install/_codex-agents.mjs +2 -2
- package/install/_dev-only-files.mjs +1 -0
- package/install/templates/claude-hooks.json +12 -1
- package/package.json +4 -3
- package/pipeline/agents/android-architect.md +1 -0
- package/pipeline/agents/backend-architect.md +1 -0
- package/pipeline/agents/bulk-reader.md +57 -0
- package/pipeline/agents/code-reviewer.md +1 -0
- package/pipeline/agents/dev-critic.md +2 -1
- package/pipeline/agents/explorer.md +1 -0
- package/pipeline/agents/ios-architect.md +1 -0
- package/pipeline/agents/security-auditor.md +1 -0
- package/pipeline/agents/task-clarifier.md +1 -0
- package/pipeline/commands/multi-agent/manual-test/SKILL.md +5 -1
- package/pipeline/commands/multi-agent/resume/SKILL.md +1 -0
- package/pipeline/commands/multi-agent/setup/SKILL.md +7 -5
- package/pipeline/commands/multi-agent/store-ready/SKILL.md +22 -0
- package/pipeline/commands/sim-test.md +10 -5
- package/pipeline/multi-agent-refs/channels/pr.md +22 -4
- package/pipeline/multi-agent-refs/features/autopilot-circuit-breaker.md +15 -2
- package/pipeline/multi-agent-refs/features/review-delta.md +89 -0
- package/pipeline/multi-agent-refs/features/scope-check.md +41 -0
- package/pipeline/multi-agent-refs/features/verify-by-test.md +6 -5
- package/pipeline/multi-agent-refs/features/worktree-finalize.md +1 -1
- package/pipeline/multi-agent-refs/payload-contracts.md +1 -1
- package/pipeline/multi-agent-refs/phases/phase-3-dev.md +17 -2
- package/pipeline/multi-agent-refs/phases/phase-4-review.md +46 -8
- package/pipeline/multi-agent-refs/phases/phase-5-test.md +10 -0
- package/pipeline/multi-agent-refs/phases/phase-6-commit.md +2 -0
- package/pipeline/multi-agent-refs/phases/phase-7-report.md +4 -2
- package/pipeline/multi-agent-refs/picker-contract.md +1 -1
- package/pipeline/multi-agent-refs/rules.md +2 -2
- package/pipeline/schemas/agent-state.schema.json +129 -0
- package/pipeline/schemas/bulk-read-output.schema.json +52 -0
- package/pipeline/schemas/dev-critic-output.schema.json +5 -0
- package/pipeline/schemas/prefs.schema.json +121 -19
- package/pipeline/schemas/reviewer-output.schema.json +7 -2
- package/pipeline/schemas/scope-check.schema.json +55 -0
- package/pipeline/schemas/token-budget.json +3 -3
- package/pipeline/schemas/triage-output.schema.json +12 -2
- package/pipeline/scripts/README.md +3 -2
- package/pipeline/scripts/_fingerprint.mjs +173 -0
- package/pipeline/scripts/bulk-read.sh +277 -0
- package/pipeline/scripts/check-read-size.py +335 -0
- package/pipeline/scripts/check-read-size.sh +86 -0
- package/pipeline/scripts/evidence-gate.mjs +73 -5
- package/pipeline/scripts/finding-fingerprint.mjs +101 -0
- package/pipeline/scripts/pre-commit-check.sh +1 -0
- package/pipeline/scripts/review-delta.mjs +217 -0
- package/pipeline/scripts/run-metrics.mjs +20 -0
- package/pipeline/scripts/scope-check-gate.mjs +90 -0
- package/pipeline/scripts/smoke-cross-cli-behavior.sh +11 -4
- package/pipeline/scripts/uninstall.mjs +1 -0
- package/pipeline/scripts/validate-reviewer.mjs +6 -0
- package/pipeline/scripts/validate-triage.mjs +20 -0
- package/pipeline/skills/shared/core/multi-agent-store-ready/SKILL.md +5 -0
- 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
|
|
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`
|
|
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}
|
|
97
|
+
return `'''\n${s}'''`;
|
|
98
98
|
}
|
|
99
99
|
const escaped = s.replace(/\\/g, "\\\\").replace(/"""/g, '\\"\\"\\"');
|
|
100
|
-
return `"""\n${escaped}
|
|
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.
|
|
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.
|
|
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",
|
|
@@ -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
|
|
|
@@ -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** →
|
|
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
|
|
816
|
+
### Step 8 - Enforcement hooks (optional, Claude Code)
|
|
817
817
|
|
|
818
|
-
Offer to make the
|
|
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 | `
|
|
18
|
-
| 6 | `
|
|
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
|
|
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
|
|
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
|
|