@mmerterden/multi-agent-pipeline 16.16.0 → 16.17.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 +10 -0
- package/package.json +1 -1
- package/pipeline/commands/multi-agent/review/SKILL.md +15 -0
- package/pipeline/multi-agent-refs/_dev-context.md +8 -0
- package/pipeline/multi-agent-refs/phases/phase-4-review.md +10 -0
- package/pipeline/multi-agent-refs/platform-parity.md +123 -0
- package/pipeline/schemas/token-budget.json +2 -2
- package/pipeline/skills/shared/core/multi-agent-review/SKILL.md +13 -0
package/CHANGELOG.md
CHANGED
|
@@ -16,6 +16,16 @@ Internal file-layout changes that don't affect the slash-command surface are sti
|
|
|
16
16
|
|
|
17
17
|
## [Unreleased]
|
|
18
18
|
|
|
19
|
+
## [16.17.0] - 2026-08-31
|
|
20
|
+
|
|
21
|
+
### Added
|
|
22
|
+
|
|
23
|
+
- **Review compares the change against the other platform's repo.** A feature written twice drifts, and the drift is invisible from inside one repo: the iOS diff is self-consistent, the tests pass, and nobody notices that the Android screen calls a different endpoint, sends one parameter fewer, or reads a localization key the other side no longer has. When the dev-context picker carries a counterpart app repo and the diff touches a screen, a service, a request model or a localization file, Phase 4 and `/multi-agent:review` now compare four axes against it: endpoints called, parameters sent, business rules around the call, localization keys used. Nothing else - layout, naming and idiom differ between the platforms by design, and reporting them would bury the four that matter.
|
|
24
|
+
|
|
25
|
+
The counterpart is located through the code graph rather than by reading the other repo broadly: `graph-query.mjs` is token-budgeted, and the step reads at most 8 counterpart files, naming what it left out instead of truncating silently. The repo is **read only** - never edited, staged, committed, pushed or built, because the gap belongs to the other platform's team and their backlog, not to this PR. Findings land in their own `Platform parity` section and are never blocking: a reviewer that halts a correct iOS PR over an Android omission is a reviewer people turn off.
|
|
26
|
+
|
|
27
|
+
A finding may not report an extractor miss as an absence. The graph is built by deterministic regex rules, so the contract requires "no counterpart call was found in the 6 files compared" rather than "the other platform does not call it" - the same stance the analysis phase already takes on its own scan. `smoke-platform-parity.sh` asserts the cap, the read-only prohibitions, the four axes, the non-blocking rule and that all three entry points actually reach the contract. Contract: `multi-agent-refs/platform-parity.md`.
|
|
28
|
+
|
|
19
29
|
## [16.16.0] - 2026-08-31
|
|
20
30
|
|
|
21
31
|
### Added
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@mmerterden/multi-agent-pipeline",
|
|
3
|
-
"version": "16.
|
|
3
|
+
"version": "16.17.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",
|
|
@@ -201,6 +201,21 @@ Each finding gets the `ruleID` from the catalog plus the platform policy ref:
|
|
|
201
201
|
|
|
202
202
|
Catalog-only - does NOT invoke binaries. For a full scan, use `/multi-agent:test "store-ready"`.
|
|
203
203
|
|
|
204
|
+
### 4b. Platform parity cross-check (advisory, read-only)
|
|
205
|
+
|
|
206
|
+
When the run carries a counterpart app repo (dev-context `extras[]` /
|
|
207
|
+
`readonlySiblings[]` whose stack is the other mobile platform) and the diff
|
|
208
|
+
touches a screen, a service, a request model or a localization file, compare the
|
|
209
|
+
change against that repo on four axes: endpoints called, parameters sent,
|
|
210
|
+
business rules around the call, localization keys used.
|
|
211
|
+
|
|
212
|
+
The counterpart is located through the code graph, capped at 8 files, and is
|
|
213
|
+
**read only** - never edited, staged, committed, pushed or built. Output is its
|
|
214
|
+
own `Platform parity` section; findings are advisory and never blocking.
|
|
215
|
+
|
|
216
|
+
No counterpart repo, or nothing comparable in the diff → skipped silently.
|
|
217
|
+
Contract: `$HOME/.claude/multi-agent-refs/platform-parity.md`.
|
|
218
|
+
|
|
204
219
|
### 5. Triage (Fable)
|
|
205
220
|
|
|
206
221
|
Classify findings into:
|
|
@@ -113,3 +113,11 @@ When a read-only sibling is present (e.g. a vendored SDK checkout), Phase 3 (Dev
|
|
|
113
113
|
- Treat it as **read-only context** - code may be read for understanding, never edited or committed.
|
|
114
114
|
- Prefer solving the task in the primary repo(s) (e.g. by wrapping/extending in consumer code) rather than patching the sibling.
|
|
115
115
|
- Surface this constraint in the Phase 3 plan output so reviewers know why a workaround was chosen.
|
|
116
|
+
|
|
117
|
+
A **counterpart app repo** is a legitimate read-only sibling: the same product's
|
|
118
|
+
other mobile platform, added here so Phase 4 can compare the change against it.
|
|
119
|
+
Phase 3 treats it exactly like any other sibling - read, never edited. Phase 4
|
|
120
|
+
additionally runs the parity cross-check over it
|
|
121
|
+
(`$HOME/.claude/multi-agent-refs/platform-parity.md`), which is also read-only.
|
|
122
|
+
Adding one is worthwhile when the feature exists on both platforms and their
|
|
123
|
+
services, parameters, rules or localization keys are expected to match.
|
|
@@ -125,6 +125,16 @@ Phase 4 reuses the cached map from Phase 1 when both phases run in the same task
|
|
|
125
125
|
|
|
126
126
|
Cost ledger: `phase-4.repo_map_emitted bytes=N budget=B cache_hit=true|false` - Phase 7 cost rollup distinguishes a cache hit (free) from a regeneration (~150-300ms wall, 0 LLM cost either way).
|
|
127
127
|
|
|
128
|
+
#### Step 1.8 - Platform parity cross-check (advisory, read-only)
|
|
129
|
+
|
|
130
|
+
Runs only when dev-context recorded a counterpart app repo (`extras[]` /
|
|
131
|
+
`readonlySiblings[]` on the other mobile platform) AND the diff touches a
|
|
132
|
+
screen, service, request model or localization file. Otherwise skip silently -
|
|
133
|
+
no section, no placeholder.
|
|
134
|
+
|
|
135
|
+
Load `$HOME/.claude/multi-agent-refs/platform-parity.md` and follow it. The
|
|
136
|
+
counterpart repo is **read only**, and parity findings are **never blocking**.
|
|
137
|
+
|
|
128
138
|
#### Step 1.75 - Diff Risk Scoring (advisory)
|
|
129
139
|
|
|
130
140
|
Before dispatching reviewers, run the deterministic diff risk scorer and inject the top-N files into each reviewer's prompt as a priority hint. **Advisory only - never gates the pipeline.** Heuristic, zero LLM, runs in well under a second.
|
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
---
|
|
2
|
+
description: "Internal - cross-platform parity cross-check for Phase 4 and /multi-agent:review."
|
|
3
|
+
---
|
|
4
|
+
|
|
5
|
+
# Platform parity - compare the change against the other platform's repo
|
|
6
|
+
|
|
7
|
+
A feature that exists on iOS and Android is written twice, and the two copies
|
|
8
|
+
drift. The drift is invisible from inside one repo: the iOS diff is
|
|
9
|
+
self-consistent, the tests pass, and nobody notices that the Android screen
|
|
10
|
+
calls a different endpoint, sends one parameter fewer, or reads a localization
|
|
11
|
+
key that no longer exists on the other side.
|
|
12
|
+
|
|
13
|
+
This step reads the counterpart repo and reports what differs. It is advisory:
|
|
14
|
+
it never blocks, never edits, and its silence is never evidence.
|
|
15
|
+
|
|
16
|
+
## When it runs
|
|
17
|
+
|
|
18
|
+
Both conditions, or the step is skipped with no output and no placeholder:
|
|
19
|
+
|
|
20
|
+
1. The dev-context picker recorded a counterpart app repo - an `extras[]` or
|
|
21
|
+
`readonlySiblings[]` entry whose stack resolves to the other mobile platform
|
|
22
|
+
(`android` when the primary is `ios`, `ios` when the primary is `android`).
|
|
23
|
+
2. The diff touches something with a counterpart worth checking: a screen, a
|
|
24
|
+
service/repository/use-case, a request model, or a localization file.
|
|
25
|
+
|
|
26
|
+
A counterpart repo that is not checked out locally is skipped the same way. The
|
|
27
|
+
step never clones one: cloning a repository to review a different one is a
|
|
28
|
+
side effect nobody asked for.
|
|
29
|
+
|
|
30
|
+
## Read-only, without exception
|
|
31
|
+
|
|
32
|
+
The counterpart repo is **read**. Never edited, never staged, never committed,
|
|
33
|
+
never pushed, never branched, and never built. The parity gap belongs to the
|
|
34
|
+
other platform's team and their backlog, not to this PR.
|
|
35
|
+
|
|
36
|
+
This is the `_dev-context.md` read-only sibling contract, applied to Phase 4:
|
|
37
|
+
the primary repo is where the work happens, and a finding here is information
|
|
38
|
+
for a human, not a task for the pipeline.
|
|
39
|
+
|
|
40
|
+
## Locating the counterpart, deterministically
|
|
41
|
+
|
|
42
|
+
Do not grep the other repo by hand and do not read it broadly. Use the code
|
|
43
|
+
graph, which is LLM-free and token-budgeted:
|
|
44
|
+
|
|
45
|
+
```bash
|
|
46
|
+
SIB_STACK=android # or ios, mirrored
|
|
47
|
+
SIB_GRAPH="$HOME/.claude/knowledge/$(basename "$SIB_ROOT")/code-graph.json"
|
|
48
|
+
|
|
49
|
+
# Build once per repo; refresh only when HEAD moved past the graph's baseCommit.
|
|
50
|
+
node "$HOME/.claude/scripts/graph-build.mjs" --root "$SIB_ROOT" --stack "$SIB_STACK" --out "$SIB_GRAPH"
|
|
51
|
+
|
|
52
|
+
# One budgeted query per feature name taken from the diff. Budget is the point:
|
|
53
|
+
# an unbounded dump of the other repo is the context-stuffing this replaces.
|
|
54
|
+
node "$HOME/.claude/scripts/graph-query.mjs" "<feature or screen name>" \
|
|
55
|
+
--graph "$SIB_GRAPH" --budget 1500 --json
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
Feature names come from the changed paths and changed type names in the primary
|
|
59
|
+
diff, not from the task title - a title says what someone wanted, a path says
|
|
60
|
+
what changed.
|
|
61
|
+
|
|
62
|
+
**Cap: at most 8 counterpart files are read, and the step stops there.** A
|
|
63
|
+
change that spans more than that is reported as partially compared, naming what
|
|
64
|
+
was left out. A truncation nobody sees is worse than a smaller answer.
|
|
65
|
+
|
|
66
|
+
## What is compared
|
|
67
|
+
|
|
68
|
+
Four axes, in this order. Each finding names both sides with `file:line`, or it
|
|
69
|
+
is not reported.
|
|
70
|
+
|
|
71
|
+
| # | Axis | The question |
|
|
72
|
+
|---|---|---|
|
|
73
|
+
| 1 | Services | Does the counterpart screen call the same endpoints? An endpoint one side calls and the other does not is the finding - including a service that exists only on one platform. |
|
|
74
|
+
| 2 | Parameters | Same request fields, query parameters and headers, with the same optionality. A field sent by one side and omitted by the other is a finding even when both requests succeed. |
|
|
75
|
+
| 3 | Business rules | The conditions around the call and the response: validation, eligibility, retry, empty and error handling, feature-flag checks. A rule present on one side only is the finding. |
|
|
76
|
+
| 4 | Localization keys | The keys the changed screen uses on each side. Different key for the same string, a key one side has and the other does not, and a key that resolves to different copy. |
|
|
77
|
+
|
|
78
|
+
Nothing else. Layout, naming, architecture and idiom differ between the
|
|
79
|
+
platforms by design, and reporting them buries the four things that matter.
|
|
80
|
+
|
|
81
|
+
## What a finding may not claim
|
|
82
|
+
|
|
83
|
+
**The extractor's silence is not evidence of absence.** The code graph is
|
|
84
|
+
built by deterministic regex rules, so a counterpart it did not find may exist
|
|
85
|
+
under a name the rules do not match. A finding therefore reads "no Android call
|
|
86
|
+
to `/v1/checkin` was found in the 6 files compared", never "Android does not
|
|
87
|
+
call `/v1/checkin`".
|
|
88
|
+
|
|
89
|
+
When the counterpart screen cannot be located at all, say that, and stop. A
|
|
90
|
+
parity report against a file set that is not the counterpart is worse than no
|
|
91
|
+
report.
|
|
92
|
+
|
|
93
|
+
## Output
|
|
94
|
+
|
|
95
|
+
One section, after the review findings and before the triage notes:
|
|
96
|
+
|
|
97
|
+
```
|
|
98
|
+
## Platform parity - <counterpart repo> (advisory, read-only)
|
|
99
|
+
|
|
100
|
+
Compared: <N> files against <primary screen/feature>.
|
|
101
|
+
Not compared: <what was left out, or "nothing">.
|
|
102
|
+
|
|
103
|
+
1. Services - iOS calls POST /v1/checkin/seat (SeatService.swift:88); no
|
|
104
|
+
counterpart call found in the 6 files compared.
|
|
105
|
+
2. Parameters - both call POST /v1/checkin, iOS sends `cabinClass`
|
|
106
|
+
(CheckinRequest.swift:31), Android does not
|
|
107
|
+
(CheckinRequest.kt:24).
|
|
108
|
+
3. Rules - iOS blocks the call for infants (SeatViewModel.swift:142);
|
|
109
|
+
no equivalent guard found on the counterpart.
|
|
110
|
+
4. Keys - iOS `checkin.seat.title` (Localizable.strings:410) vs
|
|
111
|
+
counterpart `checkin_seat_header` (strings.xml:88).
|
|
112
|
+
```
|
|
113
|
+
|
|
114
|
+
Empty on every axis → one line: `Platform parity: no differences found across
|
|
115
|
+
the 4 axes in <N> files compared.` The step never prints an empty section.
|
|
116
|
+
|
|
117
|
+
## Severity
|
|
118
|
+
|
|
119
|
+
Parity findings are never blocking. They do not enter the blocking severity
|
|
120
|
+
ladder, do not set `review_blocking`, and do not stop a commit or a PR. Triage may summarize them;
|
|
121
|
+
it may not promote one to blocking. A platform gap is a planning decision for
|
|
122
|
+
two teams, and a reviewer that halts a correct iOS PR over an Android omission
|
|
123
|
+
is a reviewer people turn off.
|
|
@@ -36,6 +36,6 @@
|
|
|
36
36
|
"warn_tokens": 5600
|
|
37
37
|
}
|
|
38
38
|
},
|
|
39
|
-
"total_max_tokens":
|
|
40
|
-
"note": "Token estimate = ceil(chars / 4). Per-phase budget rule: warn = current+10% (rounded to nearest 50), max = current+25%. Gives ~6 edit cycles of headroom before warn trips - intentionally quiet under normal maintenance, loud when a phase grows unusually. Only the active phase is loaded (lazy). Recalibrated at v10.0.0 after the validator/consistency/simplifier/lesson gate contracts landed in phases 1-4. Recalibrated again at v10.9.0 after the verify-by-test (Phase 4 Step 3.7), update-check (Phase 0 Step 0.6), immutable-test (Phase 3 GREEN) and redTests re-entry contracts landed - Step 3.7 prose was compressed to a pointer into refs/features/verify-by-test.md before the recalibration. Total bumped 50000 -> 51000 at v12.5.0 after the worktree residue/traversal-prune contract (Phase 0 + Phase 5 heal) and the Reflexion causal-diagnosis contract (Phase 4 lesson memory) landed; the prose was compressed first (161 tokens reclaimed) and every per-phase max still passes - only the aggregate needed room. Recalibrated again at v13.6.0 after the install-relative path correction: an instruction that names `pipeline/scripts/x` resolves only from a repo checkout, and a run happens in the user's worktree, so 157 references across these docs moved to `$HOME/.claude/...` at +5 bytes each - 196 tokens of pure correctness cost. Same discipline as before: prose was compressed FIRST (149 tokens reclaimed, by pointing Phase 1's Figma tier table at the Phase 0 probe that already resolved it and Phase 4's Codex constraints at the always-loaded AGENTS.md block), and only then were the budgets moved. Five warn lines had been permanently amber, which makes the amber tier useless as a signal, so every warn was reset to the documented current+10% and the four maxes that the new warn would have collided with were reset to current+25%. Aggregate 51000 -> 51500. Total bumped 51500 -> 52200 at v14.0.0 after Phase 4 Review entered the four --dev mode phase sets and the criteria-resolution contract (Step 1.78) landed. Same discipline as every prior bump: prose was compressed FIRST, 820 tokens reclaimed, before the number moved. Two of those compressions are structural rather than cosmetic - the hardcoded SwiftUI interaction list in Step 1.5 and the SwiftUI convention paragraph in Step 2.8 were transcriptions of rules that now live in a scoped registry, so keeping them here would have re-created the drift this release exists to remove, and the third moved the Step 1.78 full contract into refs/features/skill-conformance.md leaving a pointer. What remains is contract text that cannot be inferred: the manifest's four consumer-visible parts, the conformance checklist the reviewers must return, and the fail-closed semantics. Every per-phase max still passes (phase-4 12405/14750); only the aggregate needed room. Total bumped 52200 -> 52700 at v14.1.0 after two more contracts landed: stack skill routing (Phase 3 pre-flight step 9) and worktree finalize (Phase 6 step 9). Compression came first, as always, and twice: 224 tokens out of Phase 3 by pointing its criteria-ledger and routing steps at their feature files instead of restating them, and 190 out of Phase 6 by moving the finalize contract into refs/features/worktree-finalize.md and leaving the invocation plus the exit-3 semantics. Both new contracts follow the pattern the earlier ones set: the phase doc carries the call and the decision, the feature file carries the reasoning, and the feature files are outside this budget because it loops only the eight phase-N-* keys. Every per-phase max still passes (phase-3 7677/8950, phase-6 5223/6150 and both under warn); only the aggregate needed room. Total bumped 52700 -> 52750 for the Phase 0 Step 3 branch-persistence correction: the step wrote the legacy `projects[].branches` while the TTL filter two sections below read `global.recentBranches`, and both spots named a `{name, lastUsed}` shape the schema rejects (`branch` required, `additionalProperties: false`), so the recent-branch picker option could never populate and a literal implementation would have failed prefs validation. Naming the right target, the right key and the legacy field to avoid costs 41 tokens over the one line it replaces. Compression came first and was applied three times to the replacement text itself, from 120 tokens down to 66, by moving the rationale out of the phase doc entirely: the reasoning now lives where it is enforced, in the migrate-prefs carry-forward comment and the smoke-pref-migration f7 block, leaving the phase doc with only the instruction. 50 was the smallest step that clears it; phase-0-init sits at 10893/12400, far under its own max, so this is purely an aggregate ceiling. v15.0.0: total 52750 -> 53100, the stack-skill tables in phase-1/2/4 now carry plugin-namespaced names (ai-<stack>-toolkit:<skill>) - functional prefixes, ~170 tokens. v15.10.0: total 53350 -> 53950 for the memory-recall + context-offload contracts (Phase 1 two-block durable-knowledge injection and its telemetry, Phase 3 build-log offload pipe, Phase 4 ranked prior art, offload pipe and recall telemetry). Compression came first and twice, taking the new prose from 1168 tokens to 580: the reasoning behind the two blocks lives in multi-agent-refs/prompt-assembly.md and the reasoning behind the offload filter lives in the offload-ref.sh header, both outside this budget, so the phase docs carry only the call, the pref that gates it and the one fact an agent cannot infer - that the evidence gate still reads the whole build log, so offloading changes what is read, never what counts as a verified pass. Every per-phase max still passes (phase-3 7985/8950, phase-4 12997/14750); phase-3 and phase-4 crossed their warn lines and are left amber on purpose, because that is the signal that those two docs are the next ones needing structural compression rather than another bump. v15.13.0: total 53950 -> 54050 for the prefs-to-flag bridges. Five settings had shipped declared-but-inert: contextOffload.minLines and .tailLines (fixed in 15.11.0), learningsLedger.maxBriefEntries, and testGap.scanTree and .promoteSeverity - the last two declared in the schema AND implemented as flags in the scanner, with nothing in between reading the pref and passing the flag. Wiring three of them costs the phase docs 94 tokens, which is the wiring itself and not prose: two `--max` substitutions and a three-line GAP_FLAGS block. Compression came first and twice, as always: the rationale that would have sat in phase-5 now lives in the header of smoke-prefs-consumed.sh, the gate that makes this class fail a build instead of shipping, and a `--severity-promote` table row was dropped because the invocation above it now shows the flag and names the pref that triggers it, which the row did not. 100 was the smallest step that clears it. Every per-phase max still passes; phase-3 and phase-4 remain amber on purpose. v15.14.0: total 54050 -> 54400 for the supported-version gate. Phase 0 Step 0.6 stopped being purely advisory: a release can now publish an npm dist-tag `required` that names the oldest runnable version, and below it the run halts instead of nagging. What the phase doc has to carry is the part an agent cannot infer - the third stdout field, that the halt is identical in autopilot, and that the run must NOT continue on the freshly updated install because its docs were already loaded from the old version. Compression came first, as always, and took the new prose from 469 tokens to 337: the rationale for the floor, the exemption list, the fail-open rules and the `npm dist-tag add` recipe all moved to multi-agent-refs/rules.md \"Supported Version Gate\" (loaded by 25 commands, outside this budget) and to the header of require-supported-version.sh, leaving the phase doc with the call, the decision table and the halt. 350 was the smallest step that clears it. Every per-phase max still passes (phase-0-init 11230/12400); phase-3 and phase-4 remain amber on purpose. v15.17.0: total 54400 -> 54900 for the Phase 1 analysis-document step. Phase 2 and Phase 3 pre-flights had BLOCKED on `analysis/<feature>-<platform>.md` since v9.0.0 while nothing produced it, so a full run either aborted at Phase 2 or the model ignored its own BLOCKING contract; Step 4 is the producer. What the phase doc carries is only what cannot be inferred: the when-table (taskType x Figma reference), the four refs in load order, the two artefacts, and that the doc validator fails closed. Compression came first and took the step from 745 tokens to 497: the history of why the gap existed moved to the CHANGELOG, the per-ref one-line descriptions moved into the refs' own headers, and the autopilot carve-out collapsed to one clause. The 17.4k-token analysis engine itself is NOT in this budget - it moved out of commands/ into multi-agent-refs/analysis/{locked,evidence,synthesis,render}.md, loaded on demand, which also took analysis/SKILL.md from 18081 to 5974 tokens and retired its lint grace entry. 500 was the smallest step that clears it; phase-1-analysis sits at 4338/4600 and is amber on purpose, like phase-3 and phase-4. v15.18.0: total 54900 -> 55250 for analysis mode. Three phase docs gained a mode branch that cannot be inferred: Phase 4 reviews a document instead of a diff (validator, the one question reviewers answer, the open-question walk), and Phase 6 publishes instead of committing. Compression came first and was applied twice to the new prose and once to old: the Phase 4 branch went from 320 tokens to 180 and the Phase 6 branch from 190 to 120 by pointing at multi-agent-refs/analysis/{resolve,render}.md, which now hold the walks themselves, and the front-matter parse contract stopped being spelled out in both pre-flights. The analysis engine keeps leaving this budget rather than entering it: intake joined locked/evidence/synthesis/render/resolve in multi-agent-refs/analysis/, which is what let analysis/SKILL.md drop under the 6000 hard cap after its grace entry was retired. 350 was the smallest step that clears it; phase-4 and phase-6 are amber on purpose, as phase-1 and phase-3 already were. v15.20.0: total 55250 -> 55500 for the TDD bridge. Phase 3 pre-flight read the analysis doc's concept table and even said test method names come from it, while nothing read Section 15 - so the RED step invented tests and the analysis test matrix never reached development. Phase 3 step 5b now loads it into state.dev.testPlan[] and Phase 4 step 1.45 cross-checks every planned row against a real test, which is what turns \"analysis quality is output quality\" from a slogan into a finding. Compression came first on both blocks, 300 tokens down to 175, by dropping the enumerated failure modes to one line each and the rationale to one clause; the reasoning lives in the CHANGELOG. 250 was the smallest step that clears it. v15.21.0: total 55500 -> 55800 for the post-analysis confirmation. Phase 2 gained Step 0.9, the last human checkpoint before Phase 3: derived values are shown for confirmation and only Section 20 rows are asked, through the resolve engine that already exists in refs. It belongs here rather than Phase 4 because Phase 4 runs after development, where an answer arrives too late to change anything. Compression came first and twice, 430 tokens down to 250, by collapsing the derived-vs-asked explanation to one sentence each and moving the walk itself to multi-agent-refs/analysis/resolve.md, which Phase 4 and analysis-resolve already mount. 300 was the smallest step that clears it. v15.22.0: total 55800 -> 55900 for the analyst-toolkit hooks. Phase 1 Step 4 now names the two prefs that decide whether a document is produced at all and how deep it goes (forceFull, mode) - the first of those had shipped declared-but-inert and smoke-prefs-consumed caught it - and Phase 4 triage gained one clause: a finding that blames a third-party library asks evidence-github whether it is already open upstream, which turns it into a deferred item with a citation instead of Phase 3 rework on code that is not ours. Compression came first and three times, taking the new prose from 220 tokens to 110, and the Phase 1d evidence contract itself never entered this budget - it lives in multi-agent-refs/analysis/evidence.md beside the phases it belongs to. 100 was the smallest step that clears it, leaving 34 tokens of headroom. phase-4 stays amber and the debt named at v15.10.0 stands: it is the doc that needs structural compression rather than another bump, and the two candidates are the inline triage JSON shape and the 3.4 telemetry block, both of which restate something already authoritative elsewhere. v16.0.0: total 55900 -> 56350 for the depth picker. `--dev` and the four dev-* commands are gone; depth is Phase 0 Step 7.5, which costs phase-0-init a step it did not have. Compression came first and three times, taking the step from 530 tokens to 300: the question wording, the per-taskType recommendation and the mode tables all live in phases/modes.md (outside this budget), so the phase doc carries only what an agent cannot infer - that the step runs after Step 7 and why, who is exempt, that ASK_CHOICE_DEFAULT must be passed explicitly because ask-choice.sh takes the FIRST option on a non-TTY, and that Short flips the Phase 1/2 tiles late rather than pre-marking them. The phase-4 telemetry block named as compression debt at v15.22.0 was collapsed to an emit() helper (-27) and the four dev-* mode files left the tree entirely, but neither offsets a genuinely new phase step. 450 was the smallest step that clears it, leaving 119 tokens of headroom. phase-4 remains amber and its other named candidate, the inline triage JSON shape, was left alone on purpose: it is the prompt the triage agent is handed, not a restatement for readers. v16.2.0: total 56350 -> 56600 for the spec-freshness and reuse-tag contracts. Phase 3 step 3 had compared `state.run.lastAnalysisDigest` since it was written, against a key nothing ever set and that the state schema did not declare, so the staleness branch was unreachable and every run reported fresh by default. Phase 1 now persists the digest and a `base_commit` anchor, and step 3 gained the repo-drift half the digest cannot see: a reused document keeps a matching digest precisely because its evidence inputs did not change, while the code underneath it moved. The second contract is the Section 14 tag reaching development: Phase 2 carries it onto the todo as `sourceTag` and Phase 3 treats it as an instruction, which is what stops a Reuse row from being re-implemented. Compression came first and took the four additions from 380 tokens to 214, by moving every rationale clause out of the phase docs: why the commit anchor exists rather than a digest recomputation lives in this note and the CHANGELOG, and the schema descriptions carry the field semantics. The baseline had 9 tokens of headroom, so no addition of any size could have fit without a bump. 250 was the smallest step that clears it, leaving 45 tokens. phase-3 and phase-4 remain amber. v16.13.0: total 57600 -> 57700 for the code-graph injection and the fable-rung switch. Phase 1 gained Step 2.6 (query the graph, hand Explore a ranked starting set), Phase 7 gained the post-branch graph refresh, and Phase 0 Step 0 gained one line: a prefs switch that resolves every preferredModel: fable persona to opus for the run, which also collapses the Phase 4 Claude Code panel from three reviewers to two. Compression came first and mostly structurally: of roughly 1,630 tokens of new contract text, 1,310 never entered this budget at all - the whole code-graph contract lives in multi-agent-refs/features/code-graph.md (604) and the fable switch's scope table, per-host effects and cost-accounting consequence live in features/model-fallback.md (+707), leaving the phase docs with the call, the pref that gates it and the one fact an agent cannot infer. Phase 4 was compressed on top of that: its TLDR restated the reviewer matrix 270 lines below it, so 36 tokens came back and the doc nets +6 despite carrying two new clauses. One of those clauses is a correction rather than a feature - the consensus rule still said reviewerCount is 2 on Claude Code, which stopped being true when the third reviewer landed in 16.12.0, and the cross-CLI smoke never caught it because it reads the matrix line instead. 100 was the smallest step that clears it, leaving 54 tokens. phase-3 and phase-4 remain amber."
|
|
39
|
+
"total_max_tokens": 57850,
|
|
40
|
+
"note": "Token estimate = ceil(chars / 4). Per-phase budget rule: warn = current+10% (rounded to nearest 50), max = current+25%. Gives ~6 edit cycles of headroom before warn trips - intentionally quiet under normal maintenance, loud when a phase grows unusually. Only the active phase is loaded (lazy). Recalibrated at v10.0.0 after the validator/consistency/simplifier/lesson gate contracts landed in phases 1-4. Recalibrated again at v10.9.0 after the verify-by-test (Phase 4 Step 3.7), update-check (Phase 0 Step 0.6), immutable-test (Phase 3 GREEN) and redTests re-entry contracts landed - Step 3.7 prose was compressed to a pointer into refs/features/verify-by-test.md before the recalibration. Total bumped 50000 -> 51000 at v12.5.0 after the worktree residue/traversal-prune contract (Phase 0 + Phase 5 heal) and the Reflexion causal-diagnosis contract (Phase 4 lesson memory) landed; the prose was compressed first (161 tokens reclaimed) and every per-phase max still passes - only the aggregate needed room. Recalibrated again at v13.6.0 after the install-relative path correction: an instruction that names `pipeline/scripts/x` resolves only from a repo checkout, and a run happens in the user's worktree, so 157 references across these docs moved to `$HOME/.claude/...` at +5 bytes each - 196 tokens of pure correctness cost. Same discipline as before: prose was compressed FIRST (149 tokens reclaimed, by pointing Phase 1's Figma tier table at the Phase 0 probe that already resolved it and Phase 4's Codex constraints at the always-loaded AGENTS.md block), and only then were the budgets moved. Five warn lines had been permanently amber, which makes the amber tier useless as a signal, so every warn was reset to the documented current+10% and the four maxes that the new warn would have collided with were reset to current+25%. Aggregate 51000 -> 51500. Total bumped 51500 -> 52200 at v14.0.0 after Phase 4 Review entered the four --dev mode phase sets and the criteria-resolution contract (Step 1.78) landed. Same discipline as every prior bump: prose was compressed FIRST, 820 tokens reclaimed, before the number moved. Two of those compressions are structural rather than cosmetic - the hardcoded SwiftUI interaction list in Step 1.5 and the SwiftUI convention paragraph in Step 2.8 were transcriptions of rules that now live in a scoped registry, so keeping them here would have re-created the drift this release exists to remove, and the third moved the Step 1.78 full contract into refs/features/skill-conformance.md leaving a pointer. What remains is contract text that cannot be inferred: the manifest's four consumer-visible parts, the conformance checklist the reviewers must return, and the fail-closed semantics. Every per-phase max still passes (phase-4 12405/14750); only the aggregate needed room. Total bumped 52200 -> 52700 at v14.1.0 after two more contracts landed: stack skill routing (Phase 3 pre-flight step 9) and worktree finalize (Phase 6 step 9). Compression came first, as always, and twice: 224 tokens out of Phase 3 by pointing its criteria-ledger and routing steps at their feature files instead of restating them, and 190 out of Phase 6 by moving the finalize contract into refs/features/worktree-finalize.md and leaving the invocation plus the exit-3 semantics. Both new contracts follow the pattern the earlier ones set: the phase doc carries the call and the decision, the feature file carries the reasoning, and the feature files are outside this budget because it loops only the eight phase-N-* keys. Every per-phase max still passes (phase-3 7677/8950, phase-6 5223/6150 and both under warn); only the aggregate needed room. Total bumped 52700 -> 52750 for the Phase 0 Step 3 branch-persistence correction: the step wrote the legacy `projects[].branches` while the TTL filter two sections below read `global.recentBranches`, and both spots named a `{name, lastUsed}` shape the schema rejects (`branch` required, `additionalProperties: false`), so the recent-branch picker option could never populate and a literal implementation would have failed prefs validation. Naming the right target, the right key and the legacy field to avoid costs 41 tokens over the one line it replaces. Compression came first and was applied three times to the replacement text itself, from 120 tokens down to 66, by moving the rationale out of the phase doc entirely: the reasoning now lives where it is enforced, in the migrate-prefs carry-forward comment and the smoke-pref-migration f7 block, leaving the phase doc with only the instruction. 50 was the smallest step that clears it; phase-0-init sits at 10893/12400, far under its own max, so this is purely an aggregate ceiling. v15.0.0: total 52750 -> 53100, the stack-skill tables in phase-1/2/4 now carry plugin-namespaced names (ai-<stack>-toolkit:<skill>) - functional prefixes, ~170 tokens. v15.10.0: total 53350 -> 53950 for the memory-recall + context-offload contracts (Phase 1 two-block durable-knowledge injection and its telemetry, Phase 3 build-log offload pipe, Phase 4 ranked prior art, offload pipe and recall telemetry). Compression came first and twice, taking the new prose from 1168 tokens to 580: the reasoning behind the two blocks lives in multi-agent-refs/prompt-assembly.md and the reasoning behind the offload filter lives in the offload-ref.sh header, both outside this budget, so the phase docs carry only the call, the pref that gates it and the one fact an agent cannot infer - that the evidence gate still reads the whole build log, so offloading changes what is read, never what counts as a verified pass. Every per-phase max still passes (phase-3 7985/8950, phase-4 12997/14750); phase-3 and phase-4 crossed their warn lines and are left amber on purpose, because that is the signal that those two docs are the next ones needing structural compression rather than another bump. v15.13.0: total 53950 -> 54050 for the prefs-to-flag bridges. Five settings had shipped declared-but-inert: contextOffload.minLines and .tailLines (fixed in 15.11.0), learningsLedger.maxBriefEntries, and testGap.scanTree and .promoteSeverity - the last two declared in the schema AND implemented as flags in the scanner, with nothing in between reading the pref and passing the flag. Wiring three of them costs the phase docs 94 tokens, which is the wiring itself and not prose: two `--max` substitutions and a three-line GAP_FLAGS block. Compression came first and twice, as always: the rationale that would have sat in phase-5 now lives in the header of smoke-prefs-consumed.sh, the gate that makes this class fail a build instead of shipping, and a `--severity-promote` table row was dropped because the invocation above it now shows the flag and names the pref that triggers it, which the row did not. 100 was the smallest step that clears it. Every per-phase max still passes; phase-3 and phase-4 remain amber on purpose. v15.14.0: total 54050 -> 54400 for the supported-version gate. Phase 0 Step 0.6 stopped being purely advisory: a release can now publish an npm dist-tag `required` that names the oldest runnable version, and below it the run halts instead of nagging. What the phase doc has to carry is the part an agent cannot infer - the third stdout field, that the halt is identical in autopilot, and that the run must NOT continue on the freshly updated install because its docs were already loaded from the old version. Compression came first, as always, and took the new prose from 469 tokens to 337: the rationale for the floor, the exemption list, the fail-open rules and the `npm dist-tag add` recipe all moved to multi-agent-refs/rules.md \"Supported Version Gate\" (loaded by 25 commands, outside this budget) and to the header of require-supported-version.sh, leaving the phase doc with the call, the decision table and the halt. 350 was the smallest step that clears it. Every per-phase max still passes (phase-0-init 11230/12400); phase-3 and phase-4 remain amber on purpose. v15.17.0: total 54400 -> 54900 for the Phase 1 analysis-document step. Phase 2 and Phase 3 pre-flights had BLOCKED on `analysis/<feature>-<platform>.md` since v9.0.0 while nothing produced it, so a full run either aborted at Phase 2 or the model ignored its own BLOCKING contract; Step 4 is the producer. What the phase doc carries is only what cannot be inferred: the when-table (taskType x Figma reference), the four refs in load order, the two artefacts, and that the doc validator fails closed. Compression came first and took the step from 745 tokens to 497: the history of why the gap existed moved to the CHANGELOG, the per-ref one-line descriptions moved into the refs' own headers, and the autopilot carve-out collapsed to one clause. The 17.4k-token analysis engine itself is NOT in this budget - it moved out of commands/ into multi-agent-refs/analysis/{locked,evidence,synthesis,render}.md, loaded on demand, which also took analysis/SKILL.md from 18081 to 5974 tokens and retired its lint grace entry. 500 was the smallest step that clears it; phase-1-analysis sits at 4338/4600 and is amber on purpose, like phase-3 and phase-4. v15.18.0: total 54900 -> 55250 for analysis mode. Three phase docs gained a mode branch that cannot be inferred: Phase 4 reviews a document instead of a diff (validator, the one question reviewers answer, the open-question walk), and Phase 6 publishes instead of committing. Compression came first and was applied twice to the new prose and once to old: the Phase 4 branch went from 320 tokens to 180 and the Phase 6 branch from 190 to 120 by pointing at multi-agent-refs/analysis/{resolve,render}.md, which now hold the walks themselves, and the front-matter parse contract stopped being spelled out in both pre-flights. The analysis engine keeps leaving this budget rather than entering it: intake joined locked/evidence/synthesis/render/resolve in multi-agent-refs/analysis/, which is what let analysis/SKILL.md drop under the 6000 hard cap after its grace entry was retired. 350 was the smallest step that clears it; phase-4 and phase-6 are amber on purpose, as phase-1 and phase-3 already were. v15.20.0: total 55250 -> 55500 for the TDD bridge. Phase 3 pre-flight read the analysis doc's concept table and even said test method names come from it, while nothing read Section 15 - so the RED step invented tests and the analysis test matrix never reached development. Phase 3 step 5b now loads it into state.dev.testPlan[] and Phase 4 step 1.45 cross-checks every planned row against a real test, which is what turns \"analysis quality is output quality\" from a slogan into a finding. Compression came first on both blocks, 300 tokens down to 175, by dropping the enumerated failure modes to one line each and the rationale to one clause; the reasoning lives in the CHANGELOG. 250 was the smallest step that clears it. v15.21.0: total 55500 -> 55800 for the post-analysis confirmation. Phase 2 gained Step 0.9, the last human checkpoint before Phase 3: derived values are shown for confirmation and only Section 20 rows are asked, through the resolve engine that already exists in refs. It belongs here rather than Phase 4 because Phase 4 runs after development, where an answer arrives too late to change anything. Compression came first and twice, 430 tokens down to 250, by collapsing the derived-vs-asked explanation to one sentence each and moving the walk itself to multi-agent-refs/analysis/resolve.md, which Phase 4 and analysis-resolve already mount. 300 was the smallest step that clears it. v15.22.0: total 55800 -> 55900 for the analyst-toolkit hooks. Phase 1 Step 4 now names the two prefs that decide whether a document is produced at all and how deep it goes (forceFull, mode) - the first of those had shipped declared-but-inert and smoke-prefs-consumed caught it - and Phase 4 triage gained one clause: a finding that blames a third-party library asks evidence-github whether it is already open upstream, which turns it into a deferred item with a citation instead of Phase 3 rework on code that is not ours. Compression came first and three times, taking the new prose from 220 tokens to 110, and the Phase 1d evidence contract itself never entered this budget - it lives in multi-agent-refs/analysis/evidence.md beside the phases it belongs to. 100 was the smallest step that clears it, leaving 34 tokens of headroom. phase-4 stays amber and the debt named at v15.10.0 stands: it is the doc that needs structural compression rather than another bump, and the two candidates are the inline triage JSON shape and the 3.4 telemetry block, both of which restate something already authoritative elsewhere. v16.0.0: total 55900 -> 56350 for the depth picker. `--dev` and the four dev-* commands are gone; depth is Phase 0 Step 7.5, which costs phase-0-init a step it did not have. Compression came first and three times, taking the step from 530 tokens to 300: the question wording, the per-taskType recommendation and the mode tables all live in phases/modes.md (outside this budget), so the phase doc carries only what an agent cannot infer - that the step runs after Step 7 and why, who is exempt, that ASK_CHOICE_DEFAULT must be passed explicitly because ask-choice.sh takes the FIRST option on a non-TTY, and that Short flips the Phase 1/2 tiles late rather than pre-marking them. The phase-4 telemetry block named as compression debt at v15.22.0 was collapsed to an emit() helper (-27) and the four dev-* mode files left the tree entirely, but neither offsets a genuinely new phase step. 450 was the smallest step that clears it, leaving 119 tokens of headroom. phase-4 remains amber and its other named candidate, the inline triage JSON shape, was left alone on purpose: it is the prompt the triage agent is handed, not a restatement for readers. v16.2.0: total 56350 -> 56600 for the spec-freshness and reuse-tag contracts. Phase 3 step 3 had compared `state.run.lastAnalysisDigest` since it was written, against a key nothing ever set and that the state schema did not declare, so the staleness branch was unreachable and every run reported fresh by default. Phase 1 now persists the digest and a `base_commit` anchor, and step 3 gained the repo-drift half the digest cannot see: a reused document keeps a matching digest precisely because its evidence inputs did not change, while the code underneath it moved. The second contract is the Section 14 tag reaching development: Phase 2 carries it onto the todo as `sourceTag` and Phase 3 treats it as an instruction, which is what stops a Reuse row from being re-implemented. Compression came first and took the four additions from 380 tokens to 214, by moving every rationale clause out of the phase docs: why the commit anchor exists rather than a digest recomputation lives in this note and the CHANGELOG, and the schema descriptions carry the field semantics. The baseline had 9 tokens of headroom, so no addition of any size could have fit without a bump. 250 was the smallest step that clears it, leaving 45 tokens. phase-3 and phase-4 remain amber. v16.13.0: total 57600 -> 57700 for the code-graph injection and the fable-rung switch. Phase 1 gained Step 2.6 (query the graph, hand Explore a ranked starting set), Phase 7 gained the post-branch graph refresh, and Phase 0 Step 0 gained one line: a prefs switch that resolves every preferredModel: fable persona to opus for the run, which also collapses the Phase 4 Claude Code panel from three reviewers to two. Compression came first and mostly structurally: of roughly 1,630 tokens of new contract text, 1,310 never entered this budget at all - the whole code-graph contract lives in multi-agent-refs/features/code-graph.md (604) and the fable switch's scope table, per-host effects and cost-accounting consequence live in features/model-fallback.md (+707), leaving the phase docs with the call, the pref that gates it and the one fact an agent cannot infer. Phase 4 was compressed on top of that: its TLDR restated the reviewer matrix 270 lines below it, so 36 tokens came back and the doc nets +6 despite carrying two new clauses. One of those clauses is a correction rather than a feature - the consensus rule still said reviewerCount is 2 on Claude Code, which stopped being true when the third reviewer landed in 16.12.0, and the cross-CLI smoke never caught it because it reads the matrix line instead. 100 was the smallest step that clears it, leaving 54 tokens. phase-3 and phase-4 remain amber. v16.17.0: total 57700 -> 57850 for the platform-parity cross-check. Phase 4 gained Step 1.8: when dev-context carries a counterpart app repo, the review compares the change against the other platform on four axes. Compression came first and structurally, as always - of roughly 1,610 tokens of new contract text, 1,490 never entered this budget at all, because the four axes, the file cap, the graph-query recipe, the read-only prohibitions and the rule that an extractor miss may not be reported as an absence all live in multi-agent-refs/platform-parity.md. The step itself was then cut from ~200 tokens to 120 by deleting everything the ref already owns, leaving the trigger, the pointer and the two facts an agent must not infer: the counterpart repo is read-only, and parity findings are never blocking. The baseline had 13 tokens of headroom, so no addition of any size could have fit without a bump. 150 was the smallest step that clears it, leaving 35 tokens. phase-3 and phase-4 remain amber, and phase-4's structural-compression debt still stands."
|
|
41
41
|
}
|
|
@@ -55,6 +55,19 @@ Skip Phase 0-3 and review a diff only. Input shapes: a PR (`#N`, `repo#N`, GitHu
|
|
|
55
55
|
|
|
56
56
|
It does NOT invoke any binary/tool - the review stage only uses the catalog. For a full scan use `multi-agent-test "store-ready"`.
|
|
57
57
|
|
|
58
|
+
4b. **Platform parity cross-check** (advisory, read-only) - when the run carries a
|
|
59
|
+
counterpart app repo (dev-context `extras[]` / `readonlySiblings[]` whose stack is
|
|
60
|
+
the other mobile platform) and the diff touches a screen, a service, a request model
|
|
61
|
+
or a localization file, compare the change against that repo on four axes: endpoints
|
|
62
|
+
called, parameters sent, business rules around the call, localization keys used.
|
|
63
|
+
|
|
64
|
+
The counterpart is located through the code graph, capped at 8 files, and is **read
|
|
65
|
+
only** - never edited, staged, committed, pushed or built. Output is its own
|
|
66
|
+
`Platform parity` section; findings are advisory and never blocking. No counterpart
|
|
67
|
+
repo, or nothing comparable in the diff → skipped silently.
|
|
68
|
+
|
|
69
|
+
Contract: `$HOME/.claude/multi-agent-refs/platform-parity.md`.
|
|
70
|
+
|
|
58
71
|
5. **Triage** - classify the findings:
|
|
59
72
|
- 🔴 **Blocking** → must fix
|
|
60
73
|
- 🟡 **Important** → fix recommended
|