@mmerterden/multi-agent-pipeline 16.17.0 → 16.17.1

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 CHANGED
@@ -16,6 +16,18 @@ Internal file-layout changes that don't affect the slash-command surface are sti
16
16
 
17
17
  ## [Unreleased]
18
18
 
19
+ ## [16.17.1] - 2026-08-31
20
+
21
+ ### Fixed
22
+
23
+ - **The platform-parity cross-check shipped with a trigger nothing could satisfy.** 16.17.0 said the step runs when dev-context recorded a counterpart repo "whose stack resolves to the other mobile platform" - naming an `extras[]` / `readonlySiblings[]` entry and a `stack` field on it. None of the three existed: the picker's return value was never persisted anywhere, `agent-state.schema.json` declared no such array, and no phase wrote one. Phase 4 runs hours after Phase 0 and reads state, so the condition could never be true and the step could never fire. It was a feature that passed every gate and did nothing.
24
+
25
+ `state.siblings[]` now exists as the one source: declared in the schema with a closed shape (`name`, `root`, `stack`, `canPush`), written by the dev-context picker at Phase 0, and read by the parity step and nothing else. `stack` is resolved from marker files in the checkout using the table Phase 1 Step 2 already owns, never from the repo name - `my-app-android` is a naming convention, and a wrong stack sends a cross-repo reader at the wrong tree. An entry with no checkout, or an unresolved stack, is skipped rather than guessed at.
26
+
27
+ Two limits are now stated instead of discovered: a standalone `/multi-agent:review <PR-URL>` has no state file, so it has no siblings and skips the step - the counterpart repo is a human's choice in the picker, and inferring one from a PR URL would be a cross-repo read nobody authorized; and nothing is ever cloned, because cloning a repository in order to review a different one is a side effect nobody asked for.
28
+
29
+ The gate is the actual fix. `smoke-platform-parity.sh` asserted only that the four documents referenced each other, which is why it passed on a trigger that was about nothing. It now checks that the field the trigger reads is declared in the schema with the shape it expects AND written by a phase, that all four documents trigger off that same field, and that the name-based stack shortcut is ruled out in writing. Verified against the 16.17.0 tree: both new checks fail on it.
30
+
19
31
  ## [16.17.0] - 2026-08-31
20
32
 
21
33
  ### Added
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mmerterden/multi-agent-pipeline",
3
- "version": "16.17.0",
3
+ "version": "16.17.1",
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",
@@ -203,11 +203,15 @@ Catalog-only - does NOT invoke binaries. For a full scan, use `/multi-agent:te
203
203
 
204
204
  ### 4b. Platform parity cross-check (advisory, read-only)
205
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.
206
+ When `state.siblings[]` holds a checked-out repo whose `stack` is the other
207
+ mobile platform and the diff touches a screen, a service, a request model or a
208
+ localization file, compare the change against that repo on four axes: endpoints
209
+ called, parameters sent, business rules around the call, localization keys used.
210
+
211
+ That array is written by the Phase 0 dev-context picker, so a standalone review
212
+ of a PR URL - no pipeline run, no state file - has no siblings and skips this
213
+ step. The counterpart repo is a human's choice in the picker; guessing one from
214
+ a PR URL would be a cross-repo read nobody authorized.
211
215
 
212
216
  The counterpart is located through the code graph, capped at 8 files, and is
213
217
  **read only** - never edited, staged, committed, pushed or built. Output is its
@@ -48,6 +48,26 @@ Selects extra repos the pipeline may touch beyond the primary repo(s) - typica
48
48
 
49
49
  4. **Empty submit** - user picks nothing → `extras=[]`, primary repo(s) only.
50
50
 
51
+ 5. **Persist the result into `state.siblings[]`.** Everything the picker learned
52
+ about repos this run will NOT modify goes here: every `readonlySiblings[]`
53
+ entry, plus any selected `extras[]` that is not being given a worktree. The
54
+ phases that consume them run hours later and have no access to the picker's
55
+ return value, so a result that is not written here is a result nothing can
56
+ read - Phase 4's platform-parity cross-check reads `state.siblings[]` and
57
+ nothing else.
58
+
59
+ Resolve each entry's `stack` from its local checkout, with the marker table
60
+ in `phases/phase-1-analysis.md` Step 2 (`.xcodeproj` / `Package.swift` →
61
+ `ios`, `build.gradle(.kts)` → `android`, and so on). No checkout, or no
62
+ marker matched → `stack: "unknown"` and `root: null`. Never infer a stack
63
+ from the repo NAME: `my-app-android` is a naming convention, not a marker,
64
+ and a wrong stack sends a cross-repo reader at the wrong tree.
65
+
66
+ ```bash
67
+ printf '{"siblings":%s}' "$SIBLINGS_JSON" \
68
+ | node $HOME/.claude/scripts/write-state.mjs "$STATE_FILE"
69
+ ```
70
+
51
71
  ## Web repos - `webRepos`
52
72
 
53
73
  Web repos are rarely submodules of the app repo, so submodule detection never finds them. `prefs.projects[<key>].webRepos[]` (or the pre-rename `frontendRepos[]`) is the primary source for them and is merged into the candidate list alongside the detected submodules. Only `/multi-agent:analysis` used to read this key, which meant the pipeline's own dev-context picker could not offer a web repo at all.
@@ -127,10 +127,11 @@ Cost ledger: `phase-4.repo_map_emitted bytes=N budget=B cache_hit=true|false` -
127
127
 
128
128
  #### Step 1.8 - Platform parity cross-check (advisory, read-only)
129
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.
130
+ Runs only when `state.siblings[]` (written by the Phase 0 dev-context picker)
131
+ holds a checked-out repo whose `stack` is the other mobile platform AND the diff
132
+ touches a screen, service, request model or localization file. Otherwise skip
133
+ silently - no section, no placeholder. No siblings entry means no comparison;
134
+ nothing is cloned and no stack is guessed from a repo name.
134
135
 
135
136
  Load `$HOME/.claude/multi-agent-refs/platform-parity.md` and follow it. The
136
137
  counterpart repo is **read only**, and parity findings are **never blocking**.
@@ -17,15 +17,34 @@ it never blocks, never edits, and its silence is never evidence.
17
17
 
18
18
  Both conditions, or the step is skipped with no output and no placeholder:
19
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`).
20
+ 1. `state.siblings[]` holds an entry with a non-null `root` whose `stack` is the
21
+ other mobile platform - `android` when the run's stack is `ios`, `ios` when
22
+ it is `android`. That array is written by the dev-context picker at Phase 0
23
+ (`_dev-context.md` step 5) and is the only source consulted. `stack` there is
24
+ resolved from marker files in the checkout, never from the repo name.
23
25
  2. The diff touches something with a counterpart worth checking: a screen, a
24
26
  service/repository/use-case, a request model, or a localization file.
25
27
 
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.
28
+ ```bash
29
+ SIB=$(node -e 'try{const s=require(process.argv[1]);const want=process.argv[2];
30
+ const m=(s.siblings||[]).find(x=>x&&x.root&&x.stack===want);
31
+ if(m)process.stdout.write(JSON.stringify({name:m.name,root:m.root,stack:m.stack}))}catch{}' \
32
+ "$STATE_FILE" "$COUNTERPART_STACK")
33
+ [ -n "$SIB" ] || exit 0 # nothing to compare against; no section, no placeholder
34
+ ```
35
+
36
+ Consequences worth stating rather than discovering:
37
+
38
+ - **A run with no state file has no siblings, so the step never fires.** A bare
39
+ `/multi-agent:review <PR-URL>` outside a pipeline run is exactly that case.
40
+ This is a limit, not a bug: the counterpart repo is something a human chose in
41
+ the picker, and guessing one from a PR URL would be a cross-repo read nobody
42
+ authorized.
43
+ - **A sibling with `root: null` is skipped**, and the step never clones one.
44
+ Cloning a repository in order to review a different one is a side effect
45
+ nobody asked for.
46
+ - **`stack: "unknown"` is skipped**, because the marker scan found nothing and a
47
+ guess would send the reader at the wrong tree.
29
48
 
30
49
  ## Read-only, without exception
31
50
 
@@ -104,6 +104,36 @@
104
104
  "type": ["string", "null"],
105
105
  "description": "Set when a phase halts on a hard error (validator failed twice, no subagent returned, dispatch error past fallback, lock irrecoverable). Format '<phase>:<cause>'. Surfaced to the user and cleared on successful resume. See operations.md 'Halt visibility'."
106
106
  },
107
+ "siblings": {
108
+ "type": "array",
109
+ "maxItems": 10,
110
+ "description": "Repos the dev-context picker offered that this run does not modify: read-only siblings, plus any extra the user selected. Persisted at Phase 0 because the phases that consume them run much later - Phase 4's platform-parity cross-check reads this and nothing else, so a picker result that is not written here is a step that can never fire.",
111
+ "items": {
112
+ "type": "object",
113
+ "additionalProperties": false,
114
+ "required": ["name", "root", "stack"],
115
+ "properties": {
116
+ "name": {
117
+ "type": "string",
118
+ "description": "Repo name as the picker showed it."
119
+ },
120
+ "root": {
121
+ "type": ["string", "null"],
122
+ "description": "Absolute path to the local checkout, or null when the repo is known but not checked out. A null root is skipped by every consumer: nothing clones a repo to review a different one."
123
+ },
124
+ "stack": {
125
+ "type": "string",
126
+ "enum": ["ios", "android", "node", "python", "go", "unknown"],
127
+ "description": "Resolved from the checkout's marker files by the same table Phase 1 Step 2 uses (.xcodeproj/Package.swift -> ios, build.gradle(.kts) -> android, ...). 'unknown' when no marker matched or there is no checkout - never guessed from the repo name."
128
+ },
129
+ "canPush": {
130
+ "type": "boolean",
131
+ "default": false,
132
+ "description": "Carried from the picker. Informational here: a sibling is read-only to Phase 4 regardless."
133
+ }
134
+ }
135
+ }
136
+ },
107
137
  "rev": {
108
138
  "type": "integer",
109
139
  "minimum": 0,
@@ -55,11 +55,12 @@ 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
58
+ 4b. **Platform parity cross-check** (advisory, read-only) - when `state.siblings[]`
59
+ (written by the Phase 0 dev-context picker) holds a checked-out repo whose `stack` is
60
+ the other mobile platform and the diff touches a screen, a service, a request model
61
61
  or a localization file, compare the change against that repo on four axes: endpoints
62
62
  called, parameters sent, business rules around the call, localization keys used.
63
+ A standalone review with no state file has no siblings and skips the step.
63
64
 
64
65
  The counterpart is located through the code graph, capped at 8 files, and is **read
65
66
  only** - never edited, staged, committed, pushed or built. Output is its own