@mmerterden/multi-agent-pipeline 16.20.0 → 16.23.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 +231 -102
- package/README.md +6 -8
- package/README.tr.md +6 -8
- package/docs/architecture.md +3 -3
- package/docs/ecosystem.md +5 -5
- package/docs/features.md +1 -0
- package/install/templates/claude-hooks.json +12 -1
- package/install/templates/copilot-instructions.md +17 -2
- package/package.json +1 -1
- package/pipeline/agents/bulk-reader.md +57 -0
- package/pipeline/commands/multi-agent/SKILL.md +0 -5
- package/pipeline/commands/multi-agent/help/SKILL.md +0 -10
- package/pipeline/commands/multi-agent/ios-coding-standard/SKILL.md +2 -2
- package/pipeline/commands/multi-agent/local-autopilot/SKILL.md +1 -1
- package/pipeline/commands/multi-agent/resume-local/SKILL.md +2 -2
- package/pipeline/commands/multi-agent/setup/SKILL.md +7 -5
- package/pipeline/commands/multi-agent/sync/SKILL.md +13 -13
- package/pipeline/multi-agent-refs/cross-cli-contract.md +10 -12
- package/pipeline/multi-agent-refs/phases/modes.md +1 -1
- package/pipeline/multi-agent-refs/phases/phase-0-init.md +7 -2
- package/pipeline/multi-agent-refs/phases/phase-3-dev.md +1 -1
- package/pipeline/multi-agent-refs/phases/phase-7-report.md +8 -1
- package/pipeline/multi-agent-refs/picker-contract.md +1 -1
- package/pipeline/multi-agent-refs/tracker-contract.md +46 -0
- package/pipeline/schemas/agent-state.schema.json +1 -1
- package/pipeline/schemas/bulk-read-output.schema.json +52 -0
- package/pipeline/schemas/prefs.schema.json +74 -19
- package/pipeline/schemas/token-budget.json +3 -3
- 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/phase-tracker.sh +245 -3
- package/pipeline/scripts/pre-commit-check.sh +1 -0
- package/pipeline/scripts/uninstall.mjs +1 -0
- package/pipeline/skills/.skill-manifest.json +8 -24
- package/pipeline/skills/.skills-index.json +2 -46
- package/pipeline/skills/shared/README.md +4 -8
- package/pipeline/skills/shared/core/multi-agent-help/SKILL.md +0 -8
- package/pipeline/skills/shared/core/multi-agent-ios-coding-standard/SKILL.md +1 -1
- package/pipeline/skills/shared/core/multi-agent-resume-local/SKILL.md +1 -1
- package/pipeline/skills/shared/core/multi-agent-sync/SKILL.md +12 -12
- package/pipeline/skills/shared/external/backlog/SKILL.md +10 -6
- package/pipeline/skills/skills-index.md +2 -6
- package/pipeline/commands/multi-agent/dev/SKILL.md +0 -17
- package/pipeline/commands/multi-agent/dev-autopilot/SKILL.md +0 -23
- package/pipeline/commands/multi-agent/dev-local/SKILL.md +0 -17
- package/pipeline/commands/multi-agent/dev-local-autopilot/SKILL.md +0 -21
- package/pipeline/skills/shared/core/multi-agent-dev/SKILL.md +0 -19
- package/pipeline/skills/shared/core/multi-agent-dev-autopilot/SKILL.md +0 -25
- package/pipeline/skills/shared/core/multi-agent-dev-local/SKILL.md +0 -19
- package/pipeline/skills/shared/core/multi-agent-dev-local-autopilot/SKILL.md +0 -23
package/CHANGELOG.md
CHANGED
|
@@ -16,6 +16,65 @@ Internal file-layout changes that don't affect the slash-command surface are sti
|
|
|
16
16
|
|
|
17
17
|
## [Unreleased]
|
|
18
18
|
|
|
19
|
+
## [16.23.0] - 2026-09-09
|
|
20
|
+
|
|
21
|
+
### Fixed
|
|
22
|
+
|
|
23
|
+
- **The progress signal reached stdout and stopped there.** `phase-tracker.sh render` prints a bordered card at every phase boundary and it was always correct on disk. It was also invisible: the hosts collapse tool output into `Ran 8 shell commands`, so the card the contract calls "the last tool result in the chat" has not been in the chat for a while. A run showed its pickers, went quiet for forty minutes, and finished without ever drawing its shape.
|
|
24
|
+
|
|
25
|
+
Each host has a widget and now the tracker names its calls instead of hoping they are remembered. `phase-tracker.sh tiles` reads the phase set already registered by `add` and prints the registration calls for the host it runs from: a `TaskCreate` list on Claude Code, one `update_plan` payload on Codex, and on Copilot CLI - which has no task widget at all - the instruction to reprint the card inside the reply, plus the card. Every `update` then prints a `-- NEXT (required) --` block carrying that host's mirror call. Phase 0 Step −1 calls `tiles` right after the `add` loop; the Copilot instructions template does the same.
|
|
26
|
+
|
|
27
|
+
- **`phase-tracker.sh tokens` was documented, linted for, and never called.** Not once: no run in the local log tree had a `tokens_in`, `tokens_out` or `model` field on any phase, going back weeks. Every phase priced at `-`, every required completion line printed without its numbers, and every gate stayed green - because `smoke-tracker-tokens-invocation.sh` lints that the phase docs _mention_ the call, which is a claim about prose, not about a run. `payload-contracts.md` had already written that limitation down.
|
|
28
|
+
|
|
29
|
+
The gate moved to where the call would have landed: `update <N> completed` now **exits 3** for phases 1-4 when nothing was recorded, prints the two commands that clear it, and leaves the phase exactly as it was - record, then re-run, nothing lost. A phase that genuinely ran no LLM call completes with `--no-llm`, which is recorded so the report can tell "nothing" from "unknown". Phases 0 and 5-7 are orchestration and are not gated, and `skipped` never is, because Short skips 1 and 2 by design.
|
|
30
|
+
|
|
31
|
+
- **A full model id silently cost nothing.** `cost-table.json` is keyed by family (`opus`, `sonnet`, `gpt-5.6`) while the name an agent has at hand is `claude-opus-5`, and the mismatch priced the phase at `-` with no complaint anywhere. `model` now resolves the family and says so out loud, listing the priced names, when it cannot.
|
|
32
|
+
|
|
33
|
+
### Added
|
|
34
|
+
|
|
35
|
+
- **`phase-tracker.sh report` - the closing report the run never printed.** Per phase: status, elapsed, tokens in/out, model and USD; then the run total, and an explicit list of any phase it could not price rather than a silent gap. Phase 7 prints it beside `render-work-summary.sh` (scope delivered, changed files with line counts, PR and commit links) so the end of a run answers both questions at once - what the pipeline spent, and what it changed. `format_span` gives the total an hours bucket; the per-phase card keeps minutes.
|
|
36
|
+
|
|
37
|
+
- **`smoke-tracker-widget.sh`** - 31 checks over the parts that were failing quietly: `tiles` emits the right call for each of the three hosts and starts at phase 0, the accounting gate fires and is recoverable, `--no-llm` is honoured and recorded, a full model id resolves to a priced family, every `update` carries its host's mirror call, the report prices what it can and names what it cannot, and the phase docs actually make these calls.
|
|
38
|
+
|
|
39
|
+
### Removed
|
|
40
|
+
|
|
41
|
+
- **The four `dev` redirect stubs are gone from the command surface.** `16.0.0` turned pipeline depth into a question the run asks at Phase 0 Step 7.5 and left `multi-agent-dev`, `multi-agent-dev-autopilot`, `multi-agent-dev-local` and `multi-agent-dev-local-autopilot` behind as stubs that printed a redirect and nothing else. Each one said, in its own body, that it would be deleted in the next minor. Twenty-one minors later they were still in the picker: typing `/multi-agent:` still offered `dev`, still described it as removed, and the description was the only thing it did.
|
|
42
|
+
|
|
43
|
+
Deleted from every surface that carries them - Claude Code commands, the shared skill tree, the Copilot dash-command skills, the Codex refs mirror - along with the generated indexes (`.skills-index.json`, `skills-index.md`, `shared/README.md`, `.skill-manifest.json`, now 207 skills rather than 211) and the migration lines in `multi-agent-help` and the Copilot instructions template. `smoke-pipeline-surface.sh` check 5b, the gate that fails when a shipped file points a reader at a retired name, loses the four exemptions that existed only because the stubs and their generated index rows were allowed to name themselves; it is strictly tighter now.
|
|
44
|
+
|
|
45
|
+
Nothing about the surface changes for anyone who has already migrated: the break shipped in `16.0.0`, this is the tombstone coming down. `/multi-agent` and `/multi-agent:local` still ask Full or Short, and Short is still what the removed flag used to mean.
|
|
46
|
+
|
|
47
|
+
- **The four names themselves, everywhere they were still readable.** Deleting the directories left the names sitting in prose, and prose is what a user acts on. Gone from the dispatcher routing table (the `--dev` / `dev-*` redirect row), from `modes.md` and `phase-3-dev.md`, from `resume-local` and `local-autopilot` (which described themselves in terms of a command that no longer exists), and from the `ios-coding-standard` picker description, which had been telling readers to hand their remediation plan to `dev/dev-local` - a description is the one piece of a command everybody reads.
|
|
48
|
+
|
|
49
|
+
`examples/03-dev-mode-fast-path.md` was the worst of them and no gate could see it: `smoke-pipeline-surface.sh` check 2 scanned `pipeline/`, `docs/`, `install/` and `test/`, never `examples/`, so a whole worked example kept teaching `--dev` fourteen minors after the flag was removed - and contradicted itself while doing it, listing Phase 4 as skipped when Review has not been skippable since `14.0.0`. It is now `examples/03-short-run-fast-path.md`, written against the depth question, with the phase list and the transcript corrected. The `--dev` invocations in examples 01 and 02 and in the bug-report issue template went with it.
|
|
50
|
+
|
|
51
|
+
With nothing left to detect, the deprecation-era gates came out too: `smoke-pipeline-surface.sh` loses check 2 (the `--dev` flag scan), check 5b (the retired-name scan) and both planted probes, and `smoke-mode-dispatch-drift.sh` loses the two loops that named the four modes - the generator's unknown-mode guard already covers them. The gate is 203 lines down to 98 and every remaining check asserts something that can still be false.
|
|
52
|
+
|
|
53
|
+
Left alone on purpose: `CHANGELOG.md`, `CHANGELOG-archive.md`, `ROADMAP.md`, `docs/internal/` and the calibration log in `token-budget.json` are history, and rewriting them would misrepresent what shipped when. So is the runtime label `"dev"` that `state.onlyDevelop` still produces for the cost report and the component-dispatch payload: that is a run shape, not a command name, and renaming it would break the plugin contract and orphan every log already written.
|
|
54
|
+
|
|
55
|
+
## [16.21.0] - 2026-09-08
|
|
56
|
+
|
|
57
|
+
### Added
|
|
58
|
+
|
|
59
|
+
- **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.
|
|
60
|
+
|
|
61
|
+
`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.
|
|
62
|
+
|
|
63
|
+
**`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.
|
|
64
|
+
|
|
65
|
+
**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.
|
|
66
|
+
|
|
67
|
+
**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.
|
|
68
|
+
|
|
69
|
+
**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.
|
|
70
|
+
|
|
71
|
+
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.
|
|
72
|
+
|
|
73
|
+
### Changed
|
|
74
|
+
|
|
75
|
+
- **`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.
|
|
76
|
+
- **`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.
|
|
77
|
+
|
|
19
78
|
## [16.20.0] - 2026-09-07
|
|
20
79
|
|
|
21
80
|
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.
|
|
@@ -151,7 +210,6 @@ A review of the three repositories together (pipeline, toolkit MCP, plugin marke
|
|
|
151
210
|
|
|
152
211
|
- **Usage reporting only ever reported runs that finished.** The reporter was called from Phase 7, and Phase 7 is the phase a run is least likely to reach: across the whole local log history, exactly one run got there. So the admin dashboard read zero of everything while the table held real rows, and the question it exists to answer - who is using this - had no answer. Phase 0's exit gate now reports the run as started, on the same upsert key, so Phase 7 replaces that row with the final state and nothing is double-counted. The read side of the same bug is fixed in the dashboard: its rollup folded only `terminal` rows, and an unfinished run was scored `fail`.
|
|
153
212
|
|
|
154
|
-
|
|
155
213
|
### Changed
|
|
156
214
|
|
|
157
215
|
- **`/multi-agent:help` now covers the plugins and the toolkit MCP.** It named both in passing - a `refactor` line, a `sync` line, a `design-check` footnote - and never said what they are or how to call one. The catalog gained a Plugins & tools block in both languages: how a stack skill is invoked, which plugins are always on, and the MCP's 83 tools grouped by what they drive (device control, web, design comparison, store and accessibility audits), with the note that its registration survives uninstall. Paid for by compressing the `design-check` entry, which was restating its own contract in fifteen lines: 353 tokens reclaimed before a byte was added, so the file sits within its 8500 ceiling. The tool count that went in with it was wrong and is now absent: `rules/outside-the-pipeline.md` said 83 while the server serves 84, and the pipeline cannot check either number because it does not vendor the toolkit. Both places now say 80+, which stays true; the exact count lives in the toolkit's own README, where a gate boots the server and compares `tools/list` against it.
|
|
@@ -173,22 +231,21 @@ A review of the three repositories together (pipeline, toolkit MCP, plugin marke
|
|
|
173
231
|
|
|
174
232
|
### Added
|
|
175
233
|
|
|
176
|
-
- **`/multi-agent:graph`
|
|
234
|
+
- **`/multi-agent:graph` - a deterministic code graph, built without an LLM.** Phase 1 re-scanned the repo with grep and read on every task and defaulted to the "very thorough" tier on feature work; Phase 7 wrote `architecture.md` from one task's window and let it age for 90 days. Both wanted the same answer: where does this live, and what depends on it. `graph-build.mjs` extracts symbols, imports and references by regex over comment-stripped source into `~/.claude/knowledge/<project>/code-graph.json`; `graph-query.mjs` runs a token-budgeted traversal, `graph-affected.mjs` walks it backwards for impact, `graph-report.mjs` renders `GRAPH_REPORT.md`, and `validate-code-graph.mjs` fails a build whose edges point at missing nodes. Zero runtime dependencies, zero API cost, read-only on the repo. Design reference: `Graphify-Labs/graphify`; the reasoning, the trade and the numbers are in `docs/adr/0010-own-code-graph.md`.
|
|
177
235
|
- **Phase 1 Step 2.6 and Phase 7 graph refresh, behind `prefs.global.codeGraph.enabled` (default `false`).** When on, Phase 1 queries the graph and hands Explore a ranked starting set instead of a full scan, and Phase 7 rebuilds the graph after the branch changed code. Off, the pipeline behaves exactly as before. Measured on a 4,300-file Swift app at a fixed 30k retrieval budget: 80.4% coverage at 18,465 tokens against 66.0% at 24,555 for grep-and-read. The win is entirely in domain-word searches (63.3% vs 32.0% at under half the cost); when the task already names an exact type, `grep -lw` is still slightly better and slightly cheaper, and the command says so.
|
|
178
236
|
- **`_path-match.mjs`.** The glob matcher `test-gap-scan.mjs` carried inline is now shared with the graph engine, so the two cannot drift apart on what a repo excludes.
|
|
179
237
|
- **Code-graph rules for Android, Node and Python.** Four stacks now build: measured on a 4,229-file Kotlin app (25,234 nodes, 70,897 edges), this repo (126 sources) and a 43-file Python service, each validated and each hub list checked by hand rather than assumed correct. Two engine defects surfaced doing it, both of which iOS had been getting away with. Nesting was read from the pattern's match column, so `public final class Foo` counted as nested because the match starts at `class` seven columns in; it now reads the line's indentation. And the import pass read a fully stripped body, which blanks a JavaScript module specifier because the specifier IS a string literal - every import edge in that stack would have vanished with nothing to notice it. iOS was re-gated after both and scored identically (80.4% at 18,467 tokens).
|
|
180
238
|
- **A nested declaration is a node but never a reference target.** Kotlin sealed cases and Python inner classes are named after the concept they model - `Icon`, `Color`, `Success`, `Disabled` - and each is declared exactly once, so the ambiguity rule never caught them. Every Kotlin file that merely mentioned Compose's `Color` gained an edge to one app's nested case: 4,072 false edges out of 74,969, and four of the top eight architectural hubs were wrong. They stay findable by name through their `defines` edge.
|
|
181
|
-
- **`prefs.global.modelFallback.fableEnabled` (default `true`)
|
|
239
|
+
- **`prefs.global.modelFallback.fableEnabled` (default `true`) - the fable rung as a switch, not only as a fallback.** Every other trigger in the fallback contract reacts to something going wrong; this one asserts up front that a rung is not in play, so there is no dispatch attempt and no error to recover from. `false` starts `ios/android/backend-architect`, `code-reviewer` and triage on `opus`. Claude Code only: Copilot CLI does not offer Fable 5, and on Codex CLI the `fable` rung means `gpt-5.6 @ xhigh`, a different vendor's model on a different account, which the switch deliberately leaves alone. Turning it off also collapses the Phase 4 Claude Code panel to two reviewers, because Reviewer 1 lands on the `opus` Reviewer 2 already holds and one model dispatched twice is not cross-model review; `consensus.reviewerCount` records `2`. Set `costBudget.priceAt` to `opus` alongside it, or the estimate keeps pricing at a rung nothing runs on and trips the ceiling early.
|
|
182
240
|
|
|
183
241
|
### Fixed
|
|
184
242
|
|
|
185
243
|
- **`derivedSkillSources` could not say which repo held the derived copies.** `localPath` reads as relative to the current repo, so both entries pointed at the UPSTREAM tree and stayed wrong through a plugin rename: the drift check was comparing a path that did not exist. Added `localRepo`, corrected both entries, and re-derived their skill lists from the tree instead of from memory.
|
|
186
244
|
- **Two `excludePathGlobs` shapes were silently inert.** A pattern with a wildcard and no `**` fell through to a literal `endsWith` / `includes` test against the pattern text, which can never be true: nothing ends with the characters `*.d.ts`. So `*.d.ts` in the node rules and `*.egg-info/` in the python rules excluded nothing, and generated typings and build residue reached every consumer of those rules, `test-gap-scan.mjs` included. Both shapes now translate to an anchored regex, and eight glob cases are pinned by the smoke.
|
|
187
245
|
- **`--all-data` left the knowledge base behind.** Full uninstall removed the log root and the per-repo memory root but never `~/.claude/knowledge/`, which holds `architecture.md`, `patterns.md`, `gotchas.md`, `decisions.md` and now `code-graph.json`. That is prose about a private codebase plus every symbol name in it, and it is the data a user most likely means by "remove everything". A default uninstall still keeps all of it, and memory written inside a repo (`$PROJECT_ROOT/.multi-agent/memory/`) is still never touched by either mode: it lives in the user's working tree and may be committed.
|
|
188
|
-
- **`modelFallback.floorModel` could not be set.** The fallback contract has documented it since the two-step ladder landed, but it was absent from `prefs.schema.json`, whose `modelFallback` object forbids extra keys
|
|
246
|
+
- **`modelFallback.floorModel` could not be set.** The fallback contract has documented it since the two-step ladder landed, but it was absent from `prefs.schema.json`, whose `modelFallback` object forbids extra keys - so a prefs file that followed the documented example failed validation. Declared, defaulted to `haiku`, and added to the template.
|
|
189
247
|
- **The consensus rule still claimed two reviewers on Claude Code.** v16.12.0 added the third reviewer and updated the matrix but not the `reviewerCount` line 300 lines below it. `smoke-cross-cli-behavior.sh` reads the matrix, so it never noticed. The line now says what it should have said all along: the count is the reviewers that actually dispatched, not the configured maximum.
|
|
190
248
|
|
|
191
|
-
|
|
192
249
|
## [16.12.0] - 2026-08-27
|
|
193
250
|
|
|
194
251
|
### Added
|
|
@@ -217,14 +274,13 @@ A review of the three repositories together (pipeline, toolkit MCP, plugin marke
|
|
|
217
274
|
- The analysis ref ceiling moves 148000 -> 154000 across two raises in one session. Everything that could live outside the count already does: the scan in `figma-screenshot.sh`, the reviewer rubric in `analysis/review.md` which a subagent loads and the orchestrator does not, and all four new gates in `validate-analysis-doc.mjs`. The tree was measured for reclaimable duplication first and had none.
|
|
218
275
|
- `smoke-validate-analysis-doc.sh` replaces four section-number pairing assertions with the `AS-NN` contract in both directions.
|
|
219
276
|
|
|
220
|
-
|
|
221
277
|
## [16.11.0] - 2026-08-27
|
|
222
278
|
|
|
223
279
|
### Changed
|
|
224
280
|
|
|
225
281
|
- **Picker option labels now follow `outputLanguage`.** Only the `AskUserQuestion` `header` chip stays English, because it is capped at 12 characters and most Turkish equivalents overflow it. A Turkish run used to render a Turkish question with English buttons, which reads as a half-translated dialogue rather than a contract. `rules.md` carries the new per-field matrix; `picker-contract.md` carries what the caller now owns: branch on which option was picked, never on its rendered text, and pass `default` / `ASK_CHOICE_DEFAULT` as a 1-based index. The host's own **Other** row is injected in English and no run can localize it.
|
|
226
282
|
- **`Frontend` is `Web` across the pipeline** - the platform picker, the stack command, the schemas, the conventions tables, the phase docs and `frontend-guide.md`, now `web-guide.md`. The published `ai-frontend-toolkit` plugin id, the `frontendRepos` / `frontendRoots` prefs keys and the `frontend` stack alias all keep working: `web` is canonical and `frontend` still resolves, so nothing written before this release stops loading. `webRepos` / `webRoots` are the new spelling; the old pair is documented as deprecated rather than removed.
|
|
227
|
-
- **A repo-less analysis run keeps its channel split.** It used to flatten everything into one document because there were no repo conventions to project onto. But a phone screen and a browser screen carry different requirements whether or not a repository exists; only the
|
|
283
|
+
- **A repo-less analysis run keeps its channel split.** It used to flatten everything into one document because there were no repo conventions to project onto. But a phone screen and a browser screen carry different requirements whether or not a repository exists; only the _projection_ half of the split needed conventions. Channels are now derived from the evidence (`intake.md` Step 3 carries the signal table) and one document is emitted per channel. `mobile` stays one channel rather than iOS plus Android, since without conventions nothing tells the two apart.
|
|
228
284
|
|
|
229
285
|
### Fixed
|
|
230
286
|
|
|
@@ -246,7 +302,6 @@ A review of the three repositories together (pipeline, toolkit MCP, plugin marke
|
|
|
246
302
|
- The analysis ref ceiling moves 145000 -> 148000. Unlike the v16.6.0 raise this one is not compensating for a measurement error: the tree gained three features and the number is right. About 1.4 kB of new prose was trimmed back before the ceiling was touched.
|
|
247
303
|
- `smoke-language-matrix.sh` and `smoke-language-axis.sh` now assert the new rule in both directions - label follows `outputLanguage`, header stays English - and three more phrasings were added to the contradiction list after one slipped past the old set.
|
|
248
304
|
|
|
249
|
-
|
|
250
305
|
### Fixed
|
|
251
306
|
|
|
252
307
|
- **The website sync committed under whatever identity the run carried, and the site silently stopped updating.** Step 4 ran a bare `git commit`, so the commit took the active account's address. The deploy platform builds only a commit whose author is a contributor on the project; any other author is accepted by the push and then never built - the deployment is created, reports `readyState: BLOCKED` (rendered by the CLI as `UNKNOWN` with a 0ms build), and the live site keeps serving the previous version. v16.4.0 and v16.5.0 were both pushed that way, neither was ever built, and both syncs reported the website as done.
|
|
@@ -261,7 +316,7 @@ A review of the three repositories together (pipeline, toolkit MCP, plugin marke
|
|
|
261
316
|
|
|
262
317
|
### Fixed
|
|
263
318
|
|
|
264
|
-
- **`write-state.mjs` could delete a live lock and lose a writer's update.** The stale-lock reclaim deleted by path: between judging a lock stale and unlinking it, the holder can release and a third writer can acquire a fresh one, so the unlink removed a
|
|
319
|
+
- **`write-state.mjs` could delete a live lock and lose a writer's update.** The stale-lock reclaim deleted by path: between judging a lock stale and unlinking it, the holder can release and a third writer can acquire a fresh one, so the unlink removed a _live_ lock and two writers then held it. It is the same failure the PID-window comment in that file already describes, at a different point in the acquire loop, and it survived because it only reproduces under load - `smoke-write-state.sh` failed inside a full gate run and passed 12/12 when run alone. Reclaim is now by identity: the inode and mtime judged stale must still be the file at that path, otherwise it belongs to somebody else and is left alone. Twelve runs under artificial load are clean, which is evidence and not proof - a race cannot be proven absent.
|
|
265
320
|
|
|
266
321
|
- **Counts that had drifted from the tree.** `skills-index.md` and `skills/shared/README.md` still said 208 skills against 210 on disk; both are generated, so they were regenerated rather than hand-edited. `/multi-agent:update` quoted "245 scripts, 208 skills" for what an install lays down; it is 263 and 210. A comment in `smoke-command-inventory.sh` used "51 commands" as its example, which is the kind of number that goes stale the moment a command lands - it now says what it means without pinning a figure.
|
|
267
322
|
|
|
@@ -271,7 +326,7 @@ Three debts the last few releases kept naming, closed.
|
|
|
271
326
|
|
|
272
327
|
### Added
|
|
273
328
|
|
|
274
|
-
- **`smoke-help-sync.sh` pairs each command's own description with the line `/multi-agent:help` shows for it.** Three releases running shipped the same defect: 16.7.1 (two commands absent from help entirely), 16.8.1 (the analysis entry describing behaviour from two releases earlier), 16.9.0 (a telemetry block still saying "optional, opt-in" after the default flipped). Every other gate was green through all three, because none of them asked whether the sentence a user reads still matches what the command does. The gate hashes both sides and fails when one moved without the other. Its limit is written into the file: it cannot tell whether either text is
|
|
329
|
+
- **`smoke-help-sync.sh` pairs each command's own description with the line `/multi-agent:help` shows for it.** Three releases running shipped the same defect: 16.7.1 (two commands absent from help entirely), 16.8.1 (the analysis entry describing behaviour from two releases earlier), 16.9.0 (a telemetry block still saying "optional, opt-in" after the default flipped). Every other gate was green through all three, because none of them asked whether the sentence a user reads still matches what the command does. The gate hashes both sides and fails when one moved without the other. Its limit is written into the file: it cannot tell whether either text is _correct_ - a maintainer who edits both to say something equally wrong still passes. What it forces is that the pair gets looked at together, which is exactly what did not happen those three times.
|
|
275
330
|
|
|
276
331
|
### Changed
|
|
277
332
|
|
|
@@ -286,7 +341,7 @@ Three debts the last few releases kept naming, closed.
|
|
|
286
341
|
|
|
287
342
|
### Added
|
|
288
343
|
|
|
289
|
-
- **`/multi-agent:analysis` emits a run record.** It is a pipeline of its own now - its own phases, its own gates, its own report - but telemetry was only wired into the dev pipeline's Phase 7, so analysis runs were invisible. The panel showed dev work only, and the command people reach for
|
|
344
|
+
- **`/multi-agent:analysis` emits a run record.** It is a pipeline of its own now - its own phases, its own gates, its own report - but telemetry was only wired into the dev pipeline's Phase 7, so analysis runs were invisible. The panel showed dev work only, and the command people reach for _before_ writing any code did not exist in the usage data. Phase 5 now writes its own `agent-state.json` through `write-state.mjs` (atomic, lock-guarded, so concurrent runs cannot wipe each other) and calls the reporter. `mode` carries the profile, which is what tells one analysis run from another: a `global` run and a `corporate` run are different work. `project` is `null` on a stack-optional run - there is no repository to name - and is digested before it leaves the machine either way. The reporter stays best-effort: a failure there never touches the run, whose summary is already printed.
|
|
290
345
|
|
|
291
346
|
### Fixed
|
|
292
347
|
|
|
@@ -446,7 +501,7 @@ Four ideas taken from github/spec-kit, obra/superpowers, karpathy/llm-council an
|
|
|
446
501
|
platform's promised files enter one denominator instead of the first one
|
|
447
502
|
standing in for the run.
|
|
448
503
|
- **A plan with zero steps passed.** `todos: []` reported `0/0 steps accounted
|
|
449
|
-
|
|
504
|
+
for` and exited 0, so a Phase 2 that produced nothing - or a state whose todos
|
|
450
505
|
were cleared - read as a fully delivered plan. An empty plan is now exit 2,
|
|
451
506
|
the same as a missing one.
|
|
452
507
|
- **A malformed reviewer dispatch vanished.** A reviewer whose `findings` came
|
|
@@ -690,10 +745,12 @@ Found by reviewing v16.0.0 after it shipped. Four defects, three of them mine fr
|
|
|
690
745
|
## [15.21.0] - 2026-08-23
|
|
691
746
|
|
|
692
747
|
### Added
|
|
748
|
+
|
|
693
749
|
- **A confirmation pass that shows what was derived and asks only what was not.** Phase 2 Step 0.9 runs before planning: the platform set, the seven convention groups, the existing components, the localization keys and the analytics events all came out of the repos in Phase 1, so they are shown for confirmation rather than asked. Only Section 20 rows are asked, through the resolve engine, one row with at most three source-labeled candidates plus Defer - and never an invented one. It sits here rather than in Phase 4 because Phase 4 runs after development, where an answer arrives too late to change anything.
|
|
694
750
|
- A corrected derived value rewrites its Pass B footnote as `^[user-override: resolved <date>]` (Locked 24), so where a value came from stays traceable even after a human overrode it.
|
|
695
751
|
|
|
696
752
|
### Changed
|
|
753
|
+
|
|
697
754
|
- **The analysis stopped asking for the platform.** Every repo selected in Phase 0 already carries a stack tag from the project scan, so the platform set is the distinct tags of the selected repos. It is derived and shown in the breadcrumb; the question survives only as a fallback for an untaggable repo or a user who wants fewer platforms than the repos imply.
|
|
698
755
|
- **The analysis stopped asking for repos.** That was the third place asking the same thing - Phase 0 Step 2 selects projects, `_dev-context.md` adds editable siblings, and analysis re-derived its own list on top. Repos now come from Phase 0, and the platform-to-repo mapping falls out of the stack tags.
|
|
699
756
|
- `prefs.projects[<key>].frontendRepos[]` moved into `_dev-context.md`. Only the analysis command read it, which meant the pipeline's own dev-context picker could never offer a frontend repo - they are rarely submodules, so submodule detection never finds them.
|
|
@@ -702,45 +759,54 @@ Found by reviewing v16.0.0 after it shipped. Four defects, three of them mine fr
|
|
|
702
759
|
## [15.20.0] - 2026-08-23
|
|
703
760
|
|
|
704
761
|
### Added
|
|
762
|
+
|
|
705
763
|
- **The analysis can read a Word file now.** Nothing in the pipeline handled `.docx`, which is the format most feature specs actually arrive in - a spec had to be pasted or re-typed into Confluence before the analysis could cite it. `pipeline/lib/fetch-document.sh` handles `.docx`, `.pdf`, `.md` and `.txt`, as a local path or a URL, and the extractor gained a `document` type that recognises both. It is distinct from `generic-doc`, which is an HTML page: this one is a file that must be converted before it can be read.
|
|
706
764
|
- **No new dependency for the common case.** A `.docx` is a zip, so `word/document.xml` is parsed with the python3 standard library the lib layer already requires; the same code path runs on macOS, Linux and Windows. Requiring pandoc or libreoffice would have been the wrong dependency for a tool that must work everywhere. PDF has no stdlib path: `pdftotext` is used when present and its absence is a soft skip (exit 6, `converter-not-available`), which on Windows is the normal case, not an error. The converter binary is configurable via `DOCUMENT_PDFTOTEXT`, which is also how the smoke exercises the degrade path without breaking `PATH`.
|
|
707
765
|
- **The analysis test plan is now the TDD RED input.** Phase 3's pre-flight read the concept table and even claimed test method names come from the analysis, while nothing read Section 15 - so RED invented its own tests and the carefully written test matrix never reached development. Step 5b loads it into `state.dev.testPlan[]` and RED writes those rows. Phase 4 step 1.45 then cross-checks every planned row against a real test: missing is `important`, present-but-asserting-something-else is `blocking`. That is what makes "analysis quality is output quality" a finding rather than a slogan.
|
|
708
766
|
|
|
709
767
|
### Fixed
|
|
768
|
+
|
|
710
769
|
- The local-document matcher also matched the path inside a URL, so `https://x/api.pdf` produced a phantom local file `//x/api.pdf`. Matches overlapping a URL span are skipped; the smoke asserts a document URL yields exactly one entry.
|
|
711
770
|
|
|
712
771
|
## [15.19.0] - 2026-08-23
|
|
713
772
|
|
|
714
773
|
### Added
|
|
774
|
+
|
|
715
775
|
- **Business rules are written in EARS now.** Section 4.4 rule statements were free prose, so Locked 31's "two readers must not disagree on pass/fail" was carried only by the acceptance criterion, not by the rule it came from. EARS (Easy Approach to Requirements Syntax, IEEE RE'09, five patterns) fixes the clause order and the keyword set, which is what removes the ambiguity. EARS states the rule, Gherkin still states how you check it - Locked 13 widens, it does not change.
|
|
716
776
|
- **Section 15.7, manual test scenarios.** The pipeline already emitted this format as the Jira test-scenario comment from `resume-local`; the analysis had no place for it, so the document a QA engineer needs was the one thing the spec did not carry. Defined once, read by both. Every MT row carries its `BR-` id, and the validator enforces it: a scenario nobody can trace to a rule is a scenario nobody can tell is stale.
|
|
717
777
|
- **Section 6.X is the whole variant axis, not the part this screen used.** New Phase 1b.2 walks each Code Connect-bound instance to its main component and reads `componentPropertyDefinitions`, so "used subset" finally has a set to be a subset of. Locked 29 promised this table for four releases with no step that could produce it. It has to happen in Phase 1: Locked 30 forbids Figma access afterwards, so an axis missed here is missed for the run.
|
|
718
778
|
- **Three layer headings**: `Bölüm A - Analiz` (what to build), `B - Teknik Analiz` (what is true), `C - Geliştirme Analizi` (how to build it), with a boundary rule - remove the row, what becomes unclear - and the corollary that A carries no technology name and C no business rationale. Additive `#` headings only: section numbers are referenced in 172 places including two validators, so nothing renumbers, and Confluence gains a two-level table of contents for free.
|
|
719
779
|
|
|
720
780
|
### Fixed
|
|
781
|
+
|
|
721
782
|
- **A layer heading could have satisfied a required section.** `validate-analysis-doc.mjs` matched required sections by substring over every `#{1,3}` heading, so a layer named `Bölüm B - Mimari ve Teknik` would have reported the architecture requirement as met with Section 13 absent. The matcher now only reads numbered section headings. Caught while adding the headings, not after shipping them.
|
|
722
783
|
|
|
723
784
|
### Changed
|
|
785
|
+
|
|
724
786
|
- UI test scenarios default ON for `taskType == component` and for any task carrying a Figma reference. They were opt-in everywhere, so UI work started with UI tests switched off.
|
|
725
787
|
- The doc validator gained the 15.7 and 6.X rules; `smoke-validate-analysis-doc.sh` grew from 10 to 13 assertions, one per new contract, each planted-and-proven rather than asserted.
|
|
726
788
|
|
|
727
789
|
## [15.18.0] - 2026-08-22
|
|
728
790
|
|
|
729
791
|
### Added
|
|
792
|
+
|
|
730
793
|
- **`/multi-agent:analysis` is a pipeline mode now, not a command standing beside the pipeline.** It runs on the same 8-phase machinery - tracker tiles, `:resume`, the cost ledger, the channels report - with four phases reinterpreted the way `--dev` reinterprets Phase 3: Phase 3 and Phase 5 skip, Phase 4 reviews the document instead of a diff, Phase 6 publishes instead of committing. Phase set 0/1/2/4/6/7, generated by `gen-mode-dispatch.mjs --mode=analysis` and drift-checked like every other mode.
|
|
731
794
|
- Phase 4 in analysis mode asks reviewers one question: could an implementer build the right thing from this document alone? A finding is anything that would force them to guess. The Section 20 walk runs there too, and a deferred row reports `review_blocking` rather than quietly staying open.
|
|
732
795
|
- No `local` or `autopilot` variant, on purpose: worktree isolation buys nothing when no code is written, and the intake, the convention preview and the open-question walk are interactive by nature.
|
|
733
796
|
|
|
734
797
|
### Changed
|
|
798
|
+
|
|
735
799
|
- The engine keeps moving out of commands and into `multi-agent-refs/analysis/`: `intake.md` and `resolve.md` join `locked/evidence/synthesis/render`. `analysis-resolve` and pipeline Phase 4 now mount the same resolution walk instead of describing it twice, and `analysis/SKILL.md` fits under the 6000 hard cap that applied once its grace entry was retired.
|
|
736
800
|
- Phase-doc token budget: total 54900 -> 55250. Compression came first and three times, twice on the new prose and once on old: both mode branches shrank by pointing at the refs that hold the actual walks, and the front-matter parse contract stopped being spelled out identically in two pre-flights.
|
|
737
801
|
|
|
738
802
|
## [15.17.0] - 2026-08-22
|
|
739
803
|
|
|
740
804
|
### Fixed
|
|
805
|
+
|
|
741
806
|
- **The full pipeline demanded a document nothing produced.** Phase 2 and Phase 3 pre-flights have BLOCKED on `analysis/<feature-slug>-<platform>.md` since v9.0.0, and Phase 1 never wrote it - its output was `analysis.json`, a different artefact. So a full run either aborted at Phase 2 telling the user to go run `/multi-agent:analysis` by hand, or the model quietly ignored its own BLOCKING contract. Phase 1 Step 4 now produces the document, and both pre-flights read `state.analysis.docStatus` instead of guessing from the filesystem: `produced` / `reused` continue, `not-applicable` is a legitimate skip (bugfix or chore with no Figma reference), and only a contract breach aborts. Neither phase sends the user to another command any more, because producing the file is Phase 1's job.
|
|
742
807
|
|
|
743
808
|
### Changed
|
|
809
|
+
|
|
744
810
|
- **The analysis engine moved out of the command and into on-demand refs.** `multi-agent-refs/analysis/{locked,evidence,synthesis,render}.md` now carry the 31 Locked decisions, the evidence gathering, the two-pass synthesis and the render/publish flow. `/multi-agent:analysis` keeps them as its contract and Phase 1 loads the same four files, so there is one engine with two entry points rather than a command the pipeline cannot reach. Side effect worth naming: `analysis/SKILL.md` went from 18081 to 5974 tokens and its lint grace entry (ceiling 18500) is retired - the grace list only ratchets down.
|
|
745
811
|
- Whether the document is produced is decided from signals Phase 0 already computed, so no new question: `feature` / `refactor` / `component` always, `bugfix` / `chore` only with a Figma reference. An existing document whose `evidence_digest` still matches is reused rather than regenerated (Locked 27).
|
|
746
812
|
- `analysis-output.schema.json` gains `docStatus`, `docPath[]` and `openQuestions[]` - the fields the two pre-flights branch on.
|
|
@@ -749,18 +815,21 @@ Found by reviewing v16.0.0 after it shipped. Four defects, three of them mine fr
|
|
|
749
815
|
## [15.16.1] - 2026-08-22
|
|
750
816
|
|
|
751
817
|
### Fixed
|
|
818
|
+
|
|
752
819
|
- **The humanizer punctuation check never ran on macOS.** Two SKILL files told the agent to verify the emitted document with `grep -P '[\x{2013}...]'`. BSD grep has no `-P`, so on the pipeline's primary platform the command errored out and "returns zero matches" was trivially true - the policy's only mechanical check was a shipped no-op. Both now call the deterministic Node validator that already implements the same policy (`validate-analysis-doc.mjs`, `validate-complaint-doc.mjs`), which behaves identically on macOS, Linux and Windows.
|
|
753
820
|
- The repo already banned `grep -P` (`smoke-shell-portability.sh`, "no guarded form"), and that gate was green the whole time: it only scanned `*.sh`. A markdown instruction file is executed too - an agent reads `grep -P ...` and runs it verbatim - so the scanner now covers `commands/`, `multi-agent-refs/` and `skills/` markdown as well. It distinguishes a prohibition from an invocation, so a line that forbids the construct still passes. Adding it immediately surfaced a second instance in `complaint-analysis/SKILL.md` that no one had noticed, which is the argument for the gate.
|
|
754
821
|
|
|
755
822
|
## [15.16.0] - 2026-08-22
|
|
756
823
|
|
|
757
824
|
### Added
|
|
825
|
+
|
|
758
826
|
- **More than one Firebase project per team.** `keychainMapping.firebase` held exactly one service-account key, which is wrong for the normal case: a legacy app next to its redesign, or staging next to production, each with its own key. A crash URL from the project you did not pick failed the `project_id` check and reported it as a configuration error, which it was, but not the one the message suggested. `global.firebase.accounts[]` maps `projectId` to a keychain key, `fetch-crashlytics.sh` reads the projectId out of the console URL and picks the matching account, and the single slot stays the fallback so a one-project setup needs no config at all. `/multi-agent:setup` now loops the Firebase pass (`Add another Firebase project? [y/N]`), reading `project_id` from each decoded JSON rather than asking for it.
|
|
759
827
|
- A `project_id` mismatch now names the key it used and prints the `accounts[]` entry to add. With several projects in play, "project mismatch" alone does not say whether the URL is wrong or the mapping is incomplete.
|
|
760
828
|
|
|
761
829
|
- **Jira project keys are discovered instead of recalled.** The token is saved and the host is known by the time setup asks for a project key, so it now asks Jira: one search for issues the person assigned or reported, most-recently-updated first, and the distinct project keys become a picker. A corporate instance has thousands of projects and a typed key is a typo that routes branches and new issues at the wrong board. The free-text prompt stays as the fallback for no-VPN and fresh accounts, and the per-repo mapping offers the discovered keys rather than asking for them again.
|
|
762
830
|
|
|
763
831
|
### Changed
|
|
832
|
+
|
|
764
833
|
- `setup/SKILL.md` lost its third copy of the service-ID table and its second copy of the `keychainMapping` shape; both live in `refs/keychain.md`, which the flow already cites. What stayed is the column nothing else had: where to generate each token. The Firebase host-exemption note also stopped being stated twice, two paragraphs apart.
|
|
765
834
|
- The App Store Connect tier reasoning moved into the ref that owns that flow, and `refs/keychain.md` gained the four App Store Connect standard key names so it is now the complete answer for every service setup points at.
|
|
766
835
|
- `smoke-url-enrichment.sh` follows the type label to where it now lives and adds eight assertions: five for the multi-account contract (including that the single-slot fallback survives) and three for Jira discovery and the completeness of the key-name reference.
|
|
@@ -768,30 +837,36 @@ Found by reviewing v16.0.0 after it shipped. Four defects, three of them mine fr
|
|
|
768
837
|
## [15.15.0] - 2026-08-22
|
|
769
838
|
|
|
770
839
|
### Added
|
|
840
|
+
|
|
771
841
|
- **Graylog has two instances now, because it always did.** Test and production are separate Graylog deployments, and a trx id minted by a tester does not exist in production - so searching production alone answered "no logs" for a complaint that was fully logged one host over, and that answer was indistinguishable from a genuine miss. `hosts.graylogTest` and the optional `keychainMapping.graylog_test` (which falls back to the production key, correct for shared-token deployments) make the second instance addressable. `fetch-graylog.sh --env auto` is the new default: production first, test when production returns nothing or is unreachable. `--env prod` / `--env test` pin one.
|
|
772
842
|
- **The payload names the instance that answered** (`source.environment`, `source.searchedEnvironments[]`), and `/multi-agent:complaint-analysis` now has to cite it. A production complaint corroborated only by test logs is `insufficient-evidence`, not a confirmed `bff` fault, and the old payload gave the triage no way to tell those apart.
|
|
773
843
|
- `/multi-agent:setup` asks for the two things the previous release added a consumer for but no collector: the Graylog test host plus its optional separate token, and `fortify.versionIds`. `versionIds` shipped in 15.14.0 as the only way to resolve an instance-id-only Fortify ticket, and nothing asked for it, so that path silently no-opped for everyone.
|
|
774
844
|
- **`smoke-graylog-environments.sh`**, 15 assertions over the resolution rules that are easy to get subtly wrong: auto stops at production when production answers, falls back on empty AND on unreachable, degrades (never blocks) when both are down, treats a pinned environment with no host as exit 6 rather than silently searching the other one, and lets a 401 on one instance fall through instead of masking a working answer from the other.
|
|
775
845
|
|
|
776
846
|
### Fixed
|
|
847
|
+
|
|
777
848
|
- A pinned `--env` with no configured host now exits 6 naming the exact pref, instead of falling back to whichever host happened to be set. Attaching test logs to a production complaint is worse than attaching none.
|
|
778
849
|
|
|
779
850
|
### Changed
|
|
851
|
+
|
|
780
852
|
- `fetch-graylog.sh` resolves host and token per environment instead of once at the top, and reads prefs through one helper rather than three near-identical inline python blocks.
|
|
781
853
|
|
|
782
854
|
## [15.14.0] - 2026-08-22
|
|
783
855
|
|
|
784
856
|
### Added
|
|
857
|
+
|
|
785
858
|
- **A release can now be required, not just available.** `/multi-agent:update` stays exactly what it was, and most releases change nothing: the run-start check keeps reading `dist-tags.latest` and keeps asking politely. What is new is a second tag. `npm dist-tag add <pkg>@<version> required` names the oldest version a user may run, and an install below that floor is not behind, it is wrong - it would produce work against a contract that no longer holds, which then has to be redone. Below the floor, Phase 0 Step 0.6 halts: it runs the update flow and stops, and the user re-issues the command on the new version. It does not continue on the freshly updated install, because this run's phase docs, refs and scripts were already loaded from the old one, and that is the drift the floor exists to prevent. Interactive and autopilot behave identically - there is nothing to decide.
|
|
786
859
|
- **`require-supported-version.sh`** turns the signal into an exit code for shell callers: 0 = proceed, 3 = halt, with `force|<local>|<latest>|<required>` on stdout and a human block on stderr. It shares `update-check.sh`'s cache, so a second command inside the TTL window costs no network call.
|
|
787
860
|
|
|
788
861
|
### Fixed
|
|
862
|
+
|
|
789
863
|
- **The Firebase Crashlytics fetcher called an endpoint that does not exist.** It built the app reference by hand as `<platform>:<bundle>` and asked for `/v1alpha/projects/<p>/apps/<ref>/issues/<issueId>`. The appId is opaque (`1:1234567890:ios:abcdef`) and cannot be derived from a bundle, and v1alpha has no get-issue-by-id route, so every fetch failed - and the failure was reported as `api-not-enabled`, which sent anyone debugging it to look at Google's API allowlist instead of at the URL. It now resolves the real appId through the Firebase Management API (`iosApps` / `androidApps`, matching `bundleId` / `packageName`), then reads `reports/topIssues` for the summary and metrics and `events?filter.issue.id=<id>` for the newest event. The payload gains what that event carries and the old shape could not: the full `stackTrace[]`, the breadcrumb and log timeline with screen names, session and occurrence counts, and the console URI. A multi-app project with no bundle match exits 3 as `app-not-found` rather than picking a neighbouring app.
|
|
790
|
-
- **Fortify findings that arrive without a URL are no longer invisible.** A scanner-to-tracker bridge writes the instance id and the `file:line` into the ticket and never writes the SSC link - it knows the id, and the person reading the ticket never needed the URL. The extractor was URL-only, so those tickets produced an empty `contextLinks[]`, Phase 0 skipped the deep fetch, and Phase 4's Fortify gate reported `n/a` on a ticket that exists
|
|
864
|
+
- **Fortify findings that arrive without a URL are no longer invisible.** A scanner-to-tracker bridge writes the instance id and the `file:line` into the ticket and never writes the SSC link - it knows the id, and the person reading the ticket never needed the URL. The extractor was URL-only, so those tickets produced an empty `contextLinks[]`, Phase 0 skipped the deep fetch, and Phase 4's Fortify gate reported `n/a` on a ticket that exists _because of_ a security finding. It now also matches a labelled `Fortify Instance ID` / `issue instance id` / `fortify id` and emits a URL-less entry, the same shape graylog trx ids already used. `fetch-fortify.sh --instance-id <id>` resolves the project version by asking each id in `prefs.global.fortify.versionIds` in order. To stay off prose, the id must be at least 16 characters and contain a digit, and the bare label `instance id` is deliberately not matched.
|
|
791
865
|
- **`prefs.global.fortify` did not exist.** Phase 4 Gate 5 documented `fortify.alwaysCheck` as its opt-in from the day it shipped, but `global` is closed to additional properties and the schema had no `fortify` object, so setting it failed validation - the gate could only ever run off a referenced URL. The object now exists with `alwaysCheck` and `versionIds`.
|
|
792
866
|
- Fortify URLs of the form `/ssc/html/ssc/version/<id>` and `#/version/<id>` now yield a version id. Only the API shape `/projectVersions/<id>` was matched before, so the UI links people actually paste parsed to `projectId: null`.
|
|
793
867
|
|
|
794
868
|
### Changed
|
|
869
|
+
|
|
795
870
|
- `update-check.sh` reads both tags in one call and now uses the abbreviated packument (60 kB instead of 250 kB for the same answer). Its own contract is unchanged and deliberately so: it still always exits 0, still says nothing when the registry is unreachable, and still emits `<local>|<latest>` for a plain update. The floor appends a third field, `force`, which a `cut -f1`/`-f2` reader ignores. The cache file grows a third field too; a two-field cache written by an older install still reads, and its missing floor means "unknown", never "none".
|
|
796
871
|
- **Fail-open, on purpose.** Offline, a blocked registry, an undeterminable local version, a `required` tag published above `latest`, or no tag at all: every one of these exits 0. A version gate that bricks the pipeline on a flaky network is worse than the drift it guards against.
|
|
797
872
|
- **Not opt-out.** `updateCheck.enabled: false` silences the advisory "update available" prompt, which is what it always meant; it does not lift a floor. The single override is the env var `MULTI_AGENT_ALLOW_OUTDATED=1`, which exits 0 with a warning and is logged in the run record, so a broken release cannot strand someone mid-incident. Exempt commands - `update`, `setup`, `uninstall`, `help`, `status`, `log`, `search`, `routines`, `forget`, `language` - are the remedy or cannot depend on a contract.
|
|
@@ -803,126 +878,151 @@ Found by reviewing v16.0.0 after it shipped. Four defects, three of them mine fr
|
|
|
803
878
|
## [15.13.0] - 2026-08-22
|
|
804
879
|
|
|
805
880
|
### Fixed
|
|
881
|
+
|
|
806
882
|
- **Three settings that were declared and did nothing are now wired up.** `learningsLedger.maxBriefEntries` had a default of 20 while both phase docs hardcoded `--max 20`, so raising it changed nothing. `testGap.scanTree` and `testGap.promoteSeverity` were declared in the schema AND implemented as `--scan-tree` / `--severity-promote` in the scanner, with nothing in between reading the pref and passing the flag: the plumbing existed at both ends and the middle was missing. A user who set any of the three got the default back with no error and no warning, and the schema told them they had done it right.
|
|
807
883
|
|
|
808
884
|
### Added
|
|
885
|
+
|
|
809
886
|
- **`smoke-prefs-consumed.sh`: every setting the schema declares must be read by something.** This class has now shipped five times - the two `contextOffload` fields fixed in 15.11.0 and the three above - which is enough to gate rather than to keep catching by hand. The check walks the nested schema and asserts each leaf key is mentioned as a whole word somewhere outside `schemas/`. Deliberately loose: it asks "did anyone wire this up", not "is the wiring correct", because a stricter rule would have to understand shell, JS and markdown, and a gate that is wrong is worse than one that is broad. `keychainMapping.*` is exempt with a reason - those are resolved dynamically, so the literal name never appears in code by design. Verified by planting a setting nothing reads and watching the gate go red.
|
|
810
887
|
|
|
811
888
|
### Changed
|
|
889
|
+
|
|
812
890
|
- Phase-doc token budget: total 53950 -> 54050. The 94 tokens are the wiring itself, not prose - two `--max` substitutions and a three-line flag block. Compression came first and twice: the rationale moved into the new gate's header, where it is enforced rather than described, and a `--severity-promote` table row was dropped because the invocation above it now shows the flag and names the pref that triggers it.
|
|
813
891
|
|
|
814
892
|
## [15.12.2] - 2026-08-22
|
|
815
893
|
|
|
816
894
|
### Fixed
|
|
895
|
+
|
|
817
896
|
- **`grep -P` is banned in shell, and the ban is enforced.** Unlike the other divergences the portability gate tracks, this one has no guarded form: BSD grep has no `-P` at all, so it exits 2 with "invalid option", and the `2>/dev/null` that nearly every check carries turns that error into an empty result, which reads as "found nothing". A check written that way passes on every input including the one it was meant to catch. Two gates in this repo did exactly that, were handed a file with the defect deliberately planted in it, and reported a clean tree. The scan covers every shell file under `scripts/` and `lib/`, not only the shipped ones, because the two that broke were smoke gates that never ship - and a gate that cannot fail is worse than no gate, since it is trusted. The check opens by proving its own detector fires on a planted invocation.
|
|
818
897
|
- **Always-loaded context is back under budget with its designed headroom.** The fixed per-run load had reached 60000 of a 60000 ceiling, so the next edit to either tracked file would have broken the gate. The cause was the pattern the gate exists to catch: `core/multi-agent/SKILL.md` carried a full transcription of the Phase 0 contract, restating all eight steps that `refs/phases/phase-0-init.md` already defines, while its own text said the transcription "does not replace the contract, read the ref". Its citations into that ref had also drifted - `L221` now points at the token pre-check, not the branch picker it claimed. Every rule was verified present in the ref before cutting (per-repo branch picker, shared branch name with per-repo collision, per-repo identity, serial per-repo worktrees). What stays in the always-loaded file is the part that enforces rather than describes: the blocking exit gate and the credential-inventory rule. 2422 bytes reclaimed, load now 57576 of 60000. The ceiling was not raised.
|
|
819
898
|
|
|
820
899
|
## [15.12.1] - 2026-08-22
|
|
821
900
|
|
|
822
901
|
### Fixed
|
|
823
|
-
- **The pre-push gate no longer runs inside the push.** Git opens the connection to the remote before the hook fires, so the six-minute chain 15.12.0 wired in idled that connection until the server dropped it: the first two attempts to push the rename died on a broken pipe with every gate green. The hook is now verify-only and instant - it checks a stamp keyed to the exact tree (HEAD plus a hash of the working tree) and refuses the push when there is none. `npm run gate` produces the stamp. Refusing is the point: no stamp means nothing has verified this tree, and the reason this file exists is that nothing else will.
|
|
824
|
-
|
|
825
902
|
|
|
903
|
+
- **The pre-push gate no longer runs inside the push.** Git opens the connection to the remote before the hook fires, so the six-minute chain 15.12.0 wired in idled that connection until the server dropped it: the first two attempts to push the rename died on a broken pipe with every gate green. The hook is now verify-only and instant - it checks a stamp keyed to the exact tree (HEAD plus a hash of the working tree) and refuses the push when there is none. `npm run gate` produces the stamp. Refusing is the point: no stamp means nothing has verified this tree, and the reason this file exists is that nothing else will.
|
|
826
904
|
|
|
827
905
|
## [15.12.0] - 2026-08-22
|
|
828
906
|
|
|
829
907
|
### Changed
|
|
908
|
+
|
|
830
909
|
- **The companion MCP server is now `@mmerterden/multi-agent-toolkit-mcp` (v3.0.0), registered as `multi-agent-toolkit`.** The old name read as internal scaffolding; the server is standalone (three runtime dependencies, 83 tools, no coupling to any orchestrator) and the name now says which family it belongs to. The MCP tool namespace moves with it: every `mcp__dev-toolkit__*` reference across 24 files is now `mcp__multi-agent-toolkit__*`, because a host derives the tool prefix from the server name and the old prefix would have addressed a server that no longer answers.
|
|
831
910
|
- **Existing registrations are migrated, not duplicated.** A host keys its registration by name, so a rename does not upgrade an entry in place: without a migration an install ends up with both `dev-toolkit` (pointing at the now-frozen 2.26.0) and `multi-agent-toolkit`, two servers advertising the same 83 tools with the host choosing between them. The installer removes the legacy entry before adding the new one, and `uninstall` clears both names - "removes the pipeline's footprint" has to mean the footprint it ever had.
|
|
832
911
|
- Declared minimums move to `v3.0.0+`; 2.x only ever existed under the old package name.
|
|
833
912
|
|
|
834
913
|
### Migration
|
|
914
|
+
|
|
835
915
|
- `@mmerterden/dev-toolkit-mcp` stays published at 2.26.0 and is deprecated with a pointer. Nothing is unpublished, so a pinned consumer keeps resolving. The toolkit also keeps `dev-toolkit-mcp` as a second `bin` alias.
|
|
836
916
|
- A hand-registered client that the pipeline installer does not manage needs `<cli> mcp remove dev-toolkit` once.
|
|
837
917
|
|
|
838
918
|
### Fixed
|
|
919
|
+
|
|
839
920
|
- **`pre-push-check.sh` ran three of the eleven gate steps.** It was missing both linters, three of the four evals, `validate-prefs` and `scorecard`, and drove the smoke suites through the bare `for f in smoke-*.sh` loop that `run-smokes.mjs` was written to replace - the loop that cannot tell a passing suite from one that exited 0 having asserted nothing. It now runs `npm test`, defined once in `package.json` so the hook cannot drift behind the chain, plus eslint and the personal-data scan. Because a full run takes about six minutes and git has already opened the connection to the remote by the time the hook fires, the verdict is cached against the exact tree that produced it (HEAD plus a hash of the working tree): re-pushing an unchanged tree is instant, one edited byte re-runs everything. Without that, the first push after the fix died on a broken pipe with every gate green. Verified by planting a defect that only the previously-missing steps catch: the old subset reported 434 unit tests passing and a clean tree; the new gate blocked the push. The hook's header also claimed the repo has no CI, which stopped being true some time ago.
|
|
840
921
|
|
|
841
922
|
## [15.11.0] - 2026-08-21
|
|
842
923
|
|
|
843
924
|
### Changed
|
|
925
|
+
|
|
844
926
|
- **Nothing the pipeline posts carries a decorative glyph any more.** The work summary rendered task marks and a phase strip in checkmarks and hourglasses, the PR review emitter prefixed every finding with a coloured dot and signed it with a robot, and the GitHub issue Progress table was three traffic lights. All of it now reads in words: `[done]` / `[pending]` for tasks, `done · active · failed · skipped · pending` for the phase strip, `done` / `partial` / `pending` for the issue flags, and the severity is the bold label it always was. `channels/jira.md` had banned decorative glyphs in a comment body for releases while the renderers filled it with them; the rule and the emitters now agree, and `smoke-channel-glyphs.sh` holds them to it. The pipeline's own terminal output is deliberately out of scope: a `✓` in a console summary is a UI affordance, not a document somebody reads later.
|
|
845
927
|
|
|
846
928
|
### Fixed
|
|
929
|
+
|
|
847
930
|
- **Jira no longer manufactures smileys the pipeline never typed.** Comments are posted as Jira wiki markup, and Jira's renderer converts `:)` `:D` `;)` and, far more easily hit in technical prose, `(x)` `(/)` `(!)` `(i)` `(y)` `(+)` `(on)` `(*)` into emoticon images at render time. Nothing escaped them. `channels/jira.md` now carries the escaping table and orders it after the markdown conversion and before the POST. This was never something the humanizer could fix: the text is legitimate, and `(x)` in a comparison table renders correctly on GitHub and Confluence - only the Jira conversion knows the target parser.
|
|
848
931
|
|
|
849
932
|
### Tests
|
|
933
|
+
|
|
850
934
|
- `smoke-channel-glyphs.sh` (8 checks) and a glyph assertion in `smoke-work-summary.sh`. Both detect with node's `\p{Extended_Pictographic}` rather than `grep -P`: the first draft of the gate used a PCRE class, reported a clean tree with a checkmark deliberately planted in an emitter, and passed. Under `bash` on a stock macOS `grep` is BSD grep, which has no `-P` at all - it exits 2 with "invalid option", the `2>/dev/null` swallowed the message, and an empty result read as "no glyphs". The gate now opens by proving its own detector fires on a planted glyph before it trusts any verdict, and both gates were re-checked by planting one and watching them go red.
|
|
851
935
|
|
|
852
936
|
## [15.10.1] - 2026-08-21
|
|
853
937
|
|
|
854
938
|
### Fixed
|
|
939
|
+
|
|
855
940
|
- **`uninstall --all-data` now removes the per-repo memory root.** `~/.claude/memory/multi-agent/` holds the learnings ledger and triage corpus: durable knowledge written in prose about the repos it was collected from, which on a corporate checkout is concrete information about the codebase. It survived even the full-cleanup mode, so "removes everything but your tokens" was not true in the one place a user is most likely to mean it. The default run still keeps it, alongside settings and logs, and both halves of that promise are now tested.
|
|
856
941
|
- **Offloaded tool payloads are reclaimable.** v15.10.0 added `offload-ref.sh` without a way to clean up after it. In worktree modes the payloads die with the worktree, but the `--local` modes write into the real checkout, and because `.multi-agent/refs/` is gitignored the files never appear in `git status` and nothing reclaims them. New `gc-refs.sh`, dispatched as a third phase of `/multi-agent:garbage-collect`, sweeps them with the same contract as the /tmp sweeper: dry-run until `--yes`, a root guard that refuses `/` and `$HOME`, a grace window so a sweep cannot pull a ref out from under a running phase, and node-id matching so a file the user put in that directory survives. `--all` sweeps every checkout under `$HOME`.
|
|
857
942
|
|
|
858
943
|
## [15.10.0] - 2026-08-21
|
|
859
944
|
|
|
860
945
|
### Added
|
|
946
|
+
|
|
861
947
|
- **Per-repo memory now recalls by relevance, not by recency.** Both memory stores ranked by something that was not relevance: `triage-memory.mjs query` scored a raw token overlap with no IDF, so a word present in every row ("view", "test", "error") counted as much as the one word that identified the bug, and `learnings-ledger.mjs brief` did not rank at all - it replayed the newest 20 entries. Past a few hundred rows both degrade the same way: the injected context stops being about the task in hand. New `pipeline/scripts/_retrieval.mjs` owns the arithmetic for both (the way `_cost.mjs` owns pricing): field-weighted BM25, exponential recency, and Reciprocal Rank Fusion with per-ranking damping so recency separates comparably relevant rows without ever promoting an unrelated one. The tokenizer indexes identifiers whole and split (`KeychainStore` is reachable from "keychain") and folds regular plurals, which is what lets a query phrased as prose reach a row that names a symbol. Zero dependencies: no embedding service, no vector store, no second model call. `prefs.global.memoryRecall.strategy: "legacy"` restores the old behaviour in one flag.
|
|
862
948
|
- **`learnings-ledger.mjs profile` and drill-down pointers.** Durable knowledge is now two blocks instead of one, because relevance and prompt-cache reuse pull against each other. `profile` emits a task-INDEPENDENT `<repo-profile>` ordered by confidence, then kind, then statement - byte-stable across runs, so it belongs at the head of a phase prompt where an unchanged prefix is served from cache and grows into an asset as a repo is learned. `brief --task` emits `<task-relevant-memory>`, ranked against the task, and goes after the task text where a per-run difference costs nothing. Every rendered line ends with an `L:<id>` pointer instead of spelling out its evidence; `learnings-ledger.mjs show --id` and `triage-memory.mjs show --id` return the full row. `multi-agent-refs/prompt-assembly.md` carries the placement contract.
|
|
863
949
|
- **`offload-ref.sh`: bulky tool payloads become a pointer plus a tail.** Phase 3 already teed its build output to a file, but nothing decided how much of that file reached the model, so in practice all of it did. The filter parks the full text at `.multi-agent/refs/<node_id>.md` (content-addressed, gitignored) and prints a `[[ref:<node_id>]]` stub with the last lines - where a failing build's error already is. The evidence gate keeps reading the whole log, so what counts as a verified pass is unchanged; only what reaches the prompt shrinks. Wired into Phase 3 builds and Phase 4 test output, opt-in via `prefs.global.contextOffload.enabled`, and a pass-through when off, so the pipe is always safe to write.
|
|
864
950
|
- **Recall precision is measured.** Phase 1 and Phase 4 emit `memory.injected` / `memory.hit`, and `learning-curve.mjs` trends the ratio alongside the existing KPIs. Without the pair, a ranking change that injects the right rows and one that injects noise are indistinguishable from outside: both return five hits and exit 0. `smoke-learnings-ledger.sh` holds the emitter and the consumer to the same event names, so renaming one side fails a gate instead of silently emptying the column.
|
|
865
951
|
|
|
866
952
|
### Security
|
|
953
|
+
|
|
867
954
|
- **Entry text cannot forge the boundary of the block it is injected into.** `from-triage` builds ledger statements out of a finding's own words, which are model output, so a statement is untrusted content placed inside a structure the reader parses. Statements are now stored as one line (the schema always said "in one line"; nothing enforced it), and the block delimiters are neutralised at render time in both the ledger blocks and `<repo-memory>`. Angle brackets that are not delimiters are untouched, so `Array<String>` still reads as itself.
|
|
868
955
|
|
|
869
956
|
### Changed
|
|
957
|
+
|
|
870
958
|
- `memory-load.sh` takes optional task text and ranks the MEMORY.md pointers against it. The previous `head -30` was a truncation, not a summary - the thirty-first pointer was invisible however precisely it matched, so the block got less useful the longer a repo was worked on. With no task text the index order is unchanged.
|
|
871
959
|
- Phase 4 prior-art lookup and the rejected-preference brief are both ranked against the findings under triage; a finding whose wording matches nothing now returns nothing instead of the three newest rows.
|
|
872
960
|
- `prefs.global.contextOffload.minLines` and `tailLines` are read by `offload-ref.sh`. They shipped in the schema and were honoured by nothing, so a user who set `tailLines: 50` got 20 with no way to tell; config that does nothing documents a control that is not there. An explicit flag still beats the pref, and a non-numeric or zero value falls back to the shipped default.
|
|
873
961
|
- Phase-doc token budget: total 53350 -> 53950. The new prose was compressed twice first (1168 tokens down to 580) by keeping the reasoning in `prompt-assembly.md` and the `offload-ref.sh` header, both outside the budget. Phase 3 and Phase 4 are left amber on their warn lines on purpose - that is the signal that those two docs are next for structural compression rather than another bump.
|
|
874
962
|
|
|
875
963
|
### Tests
|
|
964
|
+
|
|
876
965
|
- `test/retrieval.test.mjs` (20 unit assertions on the ranking primitives), `pipeline/scripts/eval-recall.mjs` + `pipeline/eval/recall-cases.json` (8 end-to-end recall cases against a deliberately noisy corpus, each reporting what the pre-ranking scorer would have returned), `smoke-offload-ref.sh`, and new coverage in `smoke-learnings-ledger.sh` and `smoke-per-repo-memory.sh`.
|
|
877
966
|
|
|
878
967
|
## [15.9.1] - 2026-08-20
|
|
879
968
|
|
|
880
969
|
### Changed
|
|
970
|
+
|
|
881
971
|
- **Telemetry logs the GitHub account name, never the git `identity.name`.** The reporter resolved the run's user to `identity.username || identity.name`, and since prefs identities carried no `username`, it fell back to `identity.name` - which can be a full corporate title/brand string, landing verbatim in the usage store. It now resolves to the identity's GitHub username, then the active `gh` account login resolved live, then null; the git `identity.name` is no longer a fallback. Self-registration (`/multi-agent:update` step 5b) resolves the same way.
|
|
882
972
|
|
|
883
973
|
## [15.9.0] - 2026-08-20
|
|
884
974
|
|
|
885
975
|
### Fixed
|
|
976
|
+
|
|
886
977
|
- **Telemetry emitter and run scripts: 21 verified defects from a refactor bug hunt.** The emitter now reads `usageLog.optOut` as a hard block, refuses non-TLS endpoints so the write-only token never travels in cleartext, resolves the credential store and version marker across all host trees (Copilot/Codex-only installs), prices each phase at its own model rate instead of opus-for-all, keeps hyphenated MCP server names, drops plugins mapped to `false`, and gates before touching the keychain. `phase-tracker.sh` uses a per-process temp file so the fail-open lock cannot publish a torn state, honors `$TRACKER_FILE` on init, and builds OTEL attrs with jq. `build-stack-plugins.mjs` aborts on a flag given without a value and reports content-only changes in `--dry-run`; `localize-commands.mjs` is Windows- and CRLF-safe; `account-resolver.sh`, `channels-multi-repo.sh` and `figma-mcp-refresh.sh` gaps closed. Covered by `test/usage-report.test.mjs`.
|
|
887
978
|
|
|
888
979
|
### Changed
|
|
980
|
+
|
|
889
981
|
- **`purge` and `uninstall` are no longer model-auto-invocable** (`disable-model-invocation: true`): the two irreversible, full-data-loss commands run only on an explicit user request.
|
|
890
982
|
- **`humanizer` skill (v1.1.0):** a self-critique pass re-verifies the rewrite against the original (meaning preserved, nothing invented, patterns actually gone); trailing-participle and connective-padding patterns added.
|
|
891
983
|
- Stale version tables refreshed: `SECURITY.md` supported-versions moves to the 15.x line; `ROADMAP.md` "Current Release" becomes a rolling "Recent Releases".
|
|
892
984
|
|
|
893
985
|
### Companion
|
|
986
|
+
|
|
894
987
|
- **`dev-toolkit-mcp` v2.26.0** (shipped alongside): CallTool boundary now validates arguments against each tool's inputSchema (lenient-but-safe), closing the command-injection class where a string reached a numeric shell interpolation; every caller-derived path is single-quoted; a new gate backstops it. Backward-compatible, 83 tools unchanged.
|
|
895
988
|
|
|
896
989
|
## [15.8.1] - 2026-08-19
|
|
897
990
|
|
|
898
991
|
### Fixed
|
|
992
|
+
|
|
899
993
|
- **Self-registration follows the endpoint redirect**: the default reporting host answers `/register` with a 308 to the canonical domain; the update step's curl now passes `-L`, so the token actually arrives instead of the redirect page. Without it, v15.8.0's self-registration silently reported "registration unreachable" on every machine.
|
|
900
994
|
|
|
901
995
|
## [15.8.0] - 2026-08-19
|
|
902
996
|
|
|
903
997
|
### Added
|
|
998
|
+
|
|
904
999
|
- **Operational reporting self-registers on update**: when no ingest token is onboarded, `/multi-agent:update` requests a per-machine write-only token from the reporting endpoint's `/register` route, stores it only in the OS credential store, and enables `usageLog`. Registration failing (offline, endpoint down, ingest disabled) leaves reporting off with a one-line notice - never an error. Hard opt-out via `usageLog.optOut: true` blocks both the registration and the auto-enable; setup Step 2.7 (admin-issued token) still takes precedence. The emitter's payload is unchanged: coarse run metadata only, never prompts, code, diffs, or paths.
|
|
905
1000
|
|
|
906
1001
|
## [15.7.0] - 2026-08-19
|
|
907
1002
|
|
|
908
1003
|
### Added
|
|
1004
|
+
|
|
909
1005
|
- **Setup walks missing credentials one by one**: Step 3 gained a strict sequential onboarding loop - fixed service order, one Token Save Flow prompt per service (token -> author -> host), per-service skips that never abort the loop, and `figma` / `figma_mcp` as distinct passes. The discovery summary can no longer end setup.
|
|
910
1006
|
- **Per-repo Jira project keys in setup**: the Jira pass closes with an optional multi-select mapping (repo -> project key) written to `prefs.projects[{slug}].jiraProjectKeys`; per-repo keys resolve before `global.defaultJiraKey` everywhere a key is needed. Re-open with `/multi-agent:setup jira-keys`.
|
|
911
1007
|
- **Figma MCP mode question**: the `figma_mcp` pass opens with Remote / Local. Remote generates the `figu_` OAuth token for the current user (Dynamic Client Registration + PKCE; `prefs.global.figmaMcp.remoteGeneratorScript` drives the flow when set); Local wires the PAT-based `@anthropic-ai/figma-mcp` server (`localGeneratorScript` supported). Prefs schema: new `global.figmaMcp` block plus `supabase_access` / `supabase_service_role` keychainMapping keys.
|
|
912
1008
|
|
|
913
1009
|
### Changed
|
|
1010
|
+
|
|
914
1011
|
- **Help spells out the --dev pipeline**: the Pipeline section now carries the dev chain (Phases 1-2 skipped, Review never skipped, Opus dev). Stale notes claiming Test or Review are skipped in --dev were corrected in both languages.
|
|
915
1012
|
- **Setup Step 5 (Repo Discovery) split to a reference**: the full contract moved to `multi-agent-refs/setup/repo-discovery.md`; the SKILL keeps the opt-in prompt and a summary.
|
|
916
1013
|
|
|
917
1014
|
### Fixed
|
|
1015
|
+
|
|
918
1016
|
- **build-stack-plugins.mjs dead import**: unused `APPLE_ONLY` import removed (superseded by the `STACK_ONLY` routing table).
|
|
919
1017
|
|
|
920
1018
|
## [15.6.1] - 2026-08-19
|
|
921
1019
|
|
|
922
1020
|
### Changed
|
|
1021
|
+
|
|
923
1022
|
- **`/multi-agent:update` installs from npm, not from a git clone**: the registry is the single update channel - latest published release resolved with a direct registry read (never `npm view`'s cache), downloaded via `npm pack` with the registry pinned, installed with `install.js --all`, changes rendered from the packaged CHANGELOG, smokes run from the tarball. A pipeline repo clone is now purely a maintainer workspace (synced by `/multi-agent:sync`); consumers need no git access at all, so collaborator grants on the private repo can stay read-only or be dropped.
|
|
924
1023
|
|
|
925
1024
|
### Fixed
|
|
1025
|
+
|
|
926
1026
|
- **`node --test` runs stop pinging the live dashboard**: the tracker-entities suite calls `phase-tracker.sh init` outside run-smokes' `MULTI_AGENT_SMOKE` guard, so every test run left a phantom "probe" row on the timeline. The suite now sets the flag itself, and `usage-report.mjs` refuses to emit under it as the last line of defense for any caller.
|
|
927
1027
|
- **Usage report reads the tracker as it is actually written**: `tracker-state.json` stores `phases` as an array, but the reporter iterated it with `Object.entries`, so dashboard phase ids were array indexes - every phase after a skipped one was mislabeled (Commit id "6" reported as Faz 5). Failed-phase error tags carried the same wrong ids.
|
|
928
1028
|
- **Run duration and terminal timestamp resolve from the tracker**: nothing stamps `state.finishedAt`, so every run reported `du=null` and a terminal emit was stamped with the reporter's wall clock (wrong for backfills). Both now fall back to the tracker's phase span (earliest start to latest completion).
|
|
@@ -931,28 +1031,34 @@ Found by reviewing v16.0.0 after it shipped. Four defects, three of them mine fr
|
|
|
931
1031
|
## [15.6.0] - 2026-08-18
|
|
932
1032
|
|
|
933
1033
|
### Fixed
|
|
1034
|
+
|
|
934
1035
|
- **The heart goes platform-blind** (platform-dynamic audit, 15 findings): Phase 3's RED run, target resolution and build verification become `case "$STACK"` arms (gradle/pytest/npm beside xcodebuild, with the Gradle build-lock decision stated); Phase 4 Gate 1 matches its own stack-generic Gates 2-3; Phase 2 dispatches the platform's architect agent; Phase 5's device-check table gains the Android MCP tools; the figma-config schema stops claiming SwiftUI as universal; wiki scope gains a `platform` value.
|
|
935
1036
|
|
|
936
1037
|
### Added
|
|
1038
|
+
|
|
937
1039
|
- **Per-stack routing hatches**: `STACK_ONLY` lists in `_stack-routing.mjs` so a stack-only skill (ktlint, hilt-di, ...) routes with one list entry instead of a regex widening - and `--check-routing` now FAILS on unrouted skills. `lint-skills` accepts `platform: backend|frontend`.
|
|
938
1040
|
|
|
939
1041
|
## [15.5.0] - 2026-08-18
|
|
940
1042
|
|
|
941
1043
|
### Added
|
|
1044
|
+
|
|
942
1045
|
- **`sharedUtilities` census bucket** - the bind-don't-rebuild inventory: formatter families, validation rule types + per-module facades and design-token namespaces living outside screen slices, counted with samples; Phase 3 treats a non-empty bucket as binding.
|
|
943
1046
|
|
|
944
1047
|
### Fixed
|
|
1048
|
+
|
|
945
1049
|
- **Smoke runs never touch the live dashboard** - run-smokes exports `MULTI_AGENT_SMOKE=1` and phase-tracker's live ping returns under it (test gates were leaving phantom "running" rows on the timeline).
|
|
946
1050
|
- **Routing resolves the multi-agent-plugins toolkit first** - the public toolkit family is the pipeline's standard companion; a corporate variant is the fallback, not the default.
|
|
947
1051
|
|
|
948
1052
|
## [15.4.0] - 2026-08-18
|
|
949
1053
|
|
|
950
1054
|
### Added
|
|
1055
|
+
|
|
951
1056
|
- **Per-project `testPolicy`** (`tdd` | `tests-after` | `none`): Phase 0 resolves it after project selection for every input type, asking once via a native picker when absent (autopilot defaults to `tdd` and notes it). Phase 3 gates the TDD cycle on it; Phase 5 skips the gap scan under `none` and runs only pre-existing targets. Prefs schema + template carry the field.
|
|
952
1057
|
- **Ordered stack-toolkit routing candidates**: the ios/android rows resolve the corporate `-engineering-` variant before its public derivation, and a full probe miss records every candidate tried. The conventions census learns a `CrossDomains` root; screen-creation tasks bind the routed toolkit's `create-screen` workflow.
|
|
953
1058
|
- **ios-module-structure 0.3.0 / ios-coding-standard 1.2.0** (authoring source): the settled architecture becomes the standard - UnitDialect slot, unit vocabulary roles, STRUCT-18..21 with checker support, UNIT-01..03 / SAFE-03 / MOD-08; the pre-conversion spellings are named residue.
|
|
954
1059
|
|
|
955
1060
|
### Fixed
|
|
1061
|
+
|
|
956
1062
|
- The test-policy step resolves for Jira-ID and URL inputs, not only free-text; STRUCT-18 reports an unbound contracts root as disabled coverage instead of passing silently.
|
|
957
1063
|
|
|
958
1064
|
## [15.3.2] - 2026-08-17
|
|
@@ -1030,7 +1136,7 @@ places at once.
|
|
|
1030
1136
|
delivered a different stack than the repo asked for. Repo settings are now read
|
|
1031
1137
|
first, user-global second, `--platform` last.
|
|
1032
1138
|
- **Copilot's skipped-stack prune could delete user-authored skills.** The prune
|
|
1033
|
-
was derived from catalog
|
|
1139
|
+
was derived from catalog _names_, so a user's own `~/.copilot/skills/<name>/`
|
|
1034
1140
|
sharing a catalog name was removed with no prompt. It is now scoped to the
|
|
1035
1141
|
previous delivery manifest (or, pre-manifest, to dirs byte-identical to the
|
|
1036
1142
|
catalog) - the same contract `uninstall` already used.
|
|
@@ -1131,7 +1237,6 @@ places at once.
|
|
|
1131
1237
|
were already at (or 193 bytes past) their limit; the always-on surface itself
|
|
1132
1238
|
shrank with the local copy gone.
|
|
1133
1239
|
|
|
1134
|
-
|
|
1135
1240
|
### Added
|
|
1136
1241
|
|
|
1137
1242
|
- **`/multi-agent:complaint-analysis`** — customer-complaint / customer-reported-error
|
|
@@ -1183,7 +1288,7 @@ places at once.
|
|
|
1183
1288
|
`gzip` preserves the source file's mtime by default, so rotating log
|
|
1184
1289
|
content already older than `KEEP_DAYS` produced a `.gz` that inherited
|
|
1185
1290
|
that old mtime - and the very next line's retention sweep (`find -mtime
|
|
1186
|
-
|
|
1291
|
+
+$KEEP_DAYS -delete`) deleted it in the same run, before it was ever read.
|
|
1187
1292
|
The archive's mtime is now reset to rotation time, so retention counts
|
|
1188
1293
|
from when it was archived, not from the age of the content inside it.
|
|
1189
1294
|
- The mode banner claimed pickers stay English when they didn't - language +
|
|
@@ -1204,26 +1309,26 @@ places at once.
|
|
|
1204
1309
|
|
|
1205
1310
|
- **`testflight-validation` merged into a new `/multi-agent:store-ready`, and the
|
|
1206
1311
|
Android side brought to parity.** The iOS archive audit existed twice with
|
|
1207
|
-
identical arguments
|
|
1312
|
+
identical arguments - `ios_app_store_audit({archive_path, rules: "all"})` in the
|
|
1208
1313
|
command's Gate 1 and again inside `sim-test.md`'s `store-ready` scenario. Two
|
|
1209
1314
|
copies of one call is how the second door grew with no Gate 2, no Gate 3 and no
|
|
1210
1315
|
Android equivalent. There is now one implementation.
|
|
1211
1316
|
Gates are symmetric per platform, because the failure modes are: a malformed
|
|
1212
1317
|
package, a package the store itself refuses, and a policy a human enforces.
|
|
1213
1318
|
|
|
1214
|
-
| Gate
|
|
1215
|
-
|
|
1216
|
-
| 1 Static
|
|
1217
|
-
| 2 Authoritative | `altool --validate-app`
|
|
1218
|
-
| 3 Policy
|
|
1319
|
+
| Gate | iOS | Android |
|
|
1320
|
+
| --------------- | ------------------------------- | -------------------------------------------------------- |
|
|
1321
|
+
| 1 Static | `ios_app_store_audit`, 18 rules | `android_apk_audit` + `google-play-compliance`, 21 rules |
|
|
1322
|
+
| 2 Authoritative | `altool --validate-app` | `SKIPPED` |
|
|
1323
|
+
| 3 Policy | `app-store-review` vs source | `play-store-review` vs source |
|
|
1219
1324
|
|
|
1220
1325
|
Gate 2's asymmetry is reported as an asymmetry rather than smoothed over: Play's
|
|
1221
1326
|
authoritative check exists only server-side, through a Publishing API draft edit,
|
|
1222
1327
|
and the pipeline ships no client for it. An Android run therefore clears at most
|
|
1223
1328
|
2 of 3 and never prints `passed`. `bundletool validate` is Gate 1 and is not
|
|
1224
1329
|
promoted to fill the hole.
|
|
1225
|
-
The running-app sweep became Step A rather than a separate errand
|
|
1226
|
-
be structurally perfect and still ship an unreadable screen
|
|
1330
|
+
The running-app sweep became Step A rather than a separate errand - a build can
|
|
1331
|
+
be structurally perfect and still ship an unreadable screen - and it degrades to
|
|
1227
1332
|
`SKIPPED (no booted device)` instead of halting the package validation.
|
|
1228
1333
|
|
|
1229
1334
|
Nothing was removed. `testflight-validation` is a thin iOS-pinned alias (removing
|
|
@@ -1254,7 +1359,7 @@ places at once.
|
|
|
1254
1359
|
- **Copilot's `purge` could not see a single worktree.** It discovered them with
|
|
1255
1360
|
`find {repo}/.worktrees/ -name "agent-state.json"`, and no worktree carries that
|
|
1256
1361
|
file: Phase 0 writes state to `$HOME/.claude/logs/multi-agent/{project}/{task-id}/`.
|
|
1257
|
-
Verified on a repo with two live task worktrees
|
|
1362
|
+
Verified on a repo with two live task worktrees - the marker scan returns zero
|
|
1258
1363
|
while `purge.sh`'s own directory enumeration finds both. So the skill reported
|
|
1259
1364
|
"nothing to purge" as success with real worktrees on disk. The Claude Code command
|
|
1260
1365
|
had already been fixed by delegating to `purge.sh`; the Copilot mirror never
|
|
@@ -1277,7 +1382,7 @@ places at once.
|
|
|
1277
1382
|
`.worktrees/PROJ-*/agent-log.md` and `agent-state.json`; Phase 0 has written both
|
|
1278
1383
|
to `$HOME/.claude/logs/multi-agent/{project}/{task-id}/` since the layout moved.
|
|
1279
1384
|
Against the current tree the scan matches zero files, so the op reported "logs
|
|
1280
|
-
cleared, deleted 0" as success while every real log stayed on disk
|
|
1385
|
+
cleared, deleted 0" as success while every real log stayed on disk - worse than a
|
|
1281
1386
|
missing command, because it reads as done. There was also no `clear-logs` command
|
|
1282
1387
|
directory, so the `/multi-agent:clear-logs` entry in the Copilot help pointed at a
|
|
1283
1388
|
slash command that was never installed.
|
|
@@ -1291,7 +1396,7 @@ places at once.
|
|
|
1291
1396
|
reaching either fell through to the general sweep and was reported as the scenario
|
|
1292
1397
|
asked for. Neither can be built symmetrically today: biometric has `ios_biometric`
|
|
1293
1398
|
and no Android counterpart, launch timing has `android_launch_time` and no iOS
|
|
1294
|
-
counterpart, and the file auto-detects platform
|
|
1399
|
+
counterpart, and the file auto-detects platform - so each would work on one
|
|
1295
1400
|
platform and silently do nothing on the other. Both rows are withdrawn with the
|
|
1296
1401
|
reason recorded in place, rather than shipped as half-features or left advertised.
|
|
1297
1402
|
Advertised scenarios and implemented sections now match one to one.
|
|
@@ -1388,7 +1493,7 @@ own toolkit says apply, and clean up after itself.
|
|
|
1388
1493
|
so `bugfix` / `feature` / `refactor` / `chore` had no skill dispatch at all:
|
|
1389
1494
|
whichever skills the host surfaced by description match were the ones used, and
|
|
1390
1495
|
nothing recorded or required any of them. That was the dev-side half of the gap
|
|
1391
|
-
v14.0.0 closed on the review side
|
|
1496
|
+
v14.0.0 closed on the review side - review asked "was this built to the rules it
|
|
1392
1497
|
was supposed to follow" while nobody had chosen any rules.
|
|
1393
1498
|
|
|
1394
1499
|
The routing table is NOT copied into this repo. A second copy would drift the
|
|
@@ -1398,7 +1503,7 @@ own toolkit says apply, and clean up after itself.
|
|
|
1398
1503
|
6-row table). Routed skills land in `telemetry.skillCalls[]` with
|
|
1399
1504
|
`routedBy: "<toolkit>:index@<version>"`, so Phase 4 conformance can hold the run to
|
|
1400
1505
|
what its own toolkit chose. An absent or disabled toolkit is a recorded no-op, not
|
|
1401
|
-
a halt
|
|
1506
|
+
a halt - a backend repo has no toolkit and must still run.
|
|
1402
1507
|
Contract: `refs/features/stack-skill-routing.md`.
|
|
1403
1508
|
|
|
1404
1509
|
- **Phase 6 removes a task's worktree once its PR is open** (`worktree-finalize.sh`,
|
|
@@ -1406,7 +1511,7 @@ own toolkit says apply, and clean up after itself.
|
|
|
1406
1511
|
salvages `agent-state.json`, `phase-tracker.json`, `triage-output.json`,
|
|
1407
1512
|
`.pipeline/`, `.build.log`, `.test.log` and `.review-diff.txt` into the log dir
|
|
1408
1513
|
first, because Phase 7's triage-memory ingest, the learnings-ledger distill,
|
|
1409
|
-
`render-work-summary.sh`, `:resume`, `:status` and `:log` all read them
|
|
1514
|
+
`render-work-summary.sh`, `:resume`, `:status` and `:log` all read them - and the
|
|
1410
1515
|
first three are `[ -f ]`-guarded, so a removal without salvage would have degraded
|
|
1411
1516
|
silently rather than failing.
|
|
1412
1517
|
|
|
@@ -1446,7 +1551,7 @@ own toolkit says apply, and clean up after itself.
|
|
|
1446
1551
|
`f.file` from the diff-risk report, which declares and emits `path`, so each
|
|
1447
1552
|
finding carried `file: undefined` and read "Test file 'undefined' shrinks". That
|
|
1448
1553
|
is useless to the developer and rejected by `reviewer-output.schema.json`, which
|
|
1449
|
-
requires `file` with `minLength: 1`
|
|
1554
|
+
requires `file` with `minLength: 1` - on the one gate that deliberately has no
|
|
1450
1555
|
opt-out. It stayed invisible because the smoke's own fixtures used `"file"`, the
|
|
1451
1556
|
key the bug read: the fixture matched the bug instead of the schema. Fixtures
|
|
1452
1557
|
corrected, and a new assertion checks the finding names a real path (verified by
|
|
@@ -1458,14 +1563,13 @@ own toolkit says apply, and clean up after itself.
|
|
|
1458
1563
|
elsewhere in those files' prose. Added check 4b: every name in an inventory must be
|
|
1459
1564
|
a command that exists in the tree (verified against a planted `ghostcmd`).
|
|
1460
1565
|
|
|
1461
|
-
|
|
1462
1566
|
## [14.0.0] - 2026-07-29
|
|
1463
1567
|
|
|
1464
1568
|
The `--dev` family reviews its own work, and review now checks the code against the
|
|
1465
1569
|
criteria it was supposed to be built to instead of general good taste.
|
|
1466
1570
|
|
|
1467
1571
|
Major because a command was renamed: `/multi-agent:finish` is now `/multi-agent:ship`.
|
|
1468
|
-
No alias is kept
|
|
1572
|
+
No alias is kept - `installCommands()` replaces the command tree wholesale, so a clean
|
|
1469
1573
|
cut leaves nothing half-migrated.
|
|
1470
1574
|
|
|
1471
1575
|
### Added
|
|
@@ -1478,7 +1582,7 @@ cut leaves nothing half-migrated.
|
|
|
1478
1582
|
without them, while review judges work that now exists and has no substitute. Accepted
|
|
1479
1583
|
blocking findings return to Phase 3 under the existing 3-iteration hard kill; the
|
|
1480
1584
|
autopilot variants auto-fix without prompting and halt on the existing rework-storm
|
|
1481
|
-
circuit breaker rather than committing. No new machinery for either
|
|
1585
|
+
circuit breaker rather than committing. No new machinery for either - both were already
|
|
1482
1586
|
built and became reachable the moment Phase 4 entered the phase set.
|
|
1483
1587
|
- **Phase 4 Step 1.78, criteria resolution** (`skill-conformance.mjs`, zero LLM). Resolves
|
|
1484
1588
|
which rule registries apply to this diff, scoped to its languages and paths, and writes
|
|
@@ -1493,7 +1597,7 @@ cut leaves nothing half-migrated.
|
|
|
1493
1597
|
- **Every registry declares its own `scope`** (`languages`, `paths`, `excludePaths`,
|
|
1494
1598
|
`notCovered`), and per-rule `scope` narrows it further. Measured before this landed: only
|
|
1495
1599
|
2 of the iOS registry's 99 rules carried any applicability field, and the rest wrote their
|
|
1496
|
-
scope as English prose inside `mechanism`
|
|
1600
|
+
scope as English prose inside `mechanism` - so an Objective-C or UIKit diff would have
|
|
1497
1601
|
collected all 99 SwiftUI-shaped rules, manufacturing findings and burying the real ones.
|
|
1498
1602
|
- `references/rules.yml` for `apple-archive-compliance` (18 rules) and
|
|
1499
1603
|
`google-play-compliance` (21), converted from their existing SKILL.md tables with IDs and
|
|
@@ -1502,7 +1606,7 @@ cut leaves nothing half-migrated.
|
|
|
1502
1606
|
- **Exception-marker audit**: expired, reason-less, expiry-less, or unknown-ID
|
|
1503
1607
|
`standard:exception(...)` markers become rule-ID-bearing findings. The marker template is
|
|
1504
1608
|
read from the registry, never hardcoded, so a registry with different comment syntax works.
|
|
1505
|
-
- `state.telemetry.skillCalls[]`
|
|
1609
|
+
- `state.telemetry.skillCalls[]` - Phase 3 records each skill, plugin skill and guide it
|
|
1506
1610
|
consulted, with the files it applied them to.
|
|
1507
1611
|
- `prefs.global.skillConformance.blockOnCoverageGap` (default **false**) and
|
|
1508
1612
|
`prefs.global.ship.autoFix`, the latter referenced by the tail command's spec since it
|
|
@@ -1522,13 +1626,13 @@ cut leaves nothing half-migrated.
|
|
|
1522
1626
|
- **Reviewers cite rule IDs.** `reviewer-output.schema.json` 1.0.0 -> 1.1.0 adds `ruleId`,
|
|
1523
1627
|
`criteriaSource` and the per-rule `conformance[]` array; `triage-output.schema.json`
|
|
1524
1628
|
3.2.0 -> 3.3.0 carries both through triage. `code-reviewer.md` gains a `${CRITERIA}`
|
|
1525
|
-
injection slot
|
|
1629
|
+
injection slot - the phase doc had claimed for some time that "skills are injected into
|
|
1526
1630
|
reviewer prompt context" while the agent definition had no slot for them, which is exactly
|
|
1527
1631
|
why review could not cite a rule.
|
|
1528
1632
|
- `validate-reviewer.mjs` enforces the checklist with `--criteria`: a selected ID with no
|
|
1529
1633
|
verdict, a verdict for an ID that was never selected, a `conformant` row with no file
|
|
1530
1634
|
evidence, and a `violated` row with no matching finding all fail. Without this the field
|
|
1531
|
-
would be decoration
|
|
1635
|
+
would be decoration - the validator is hand-written and does not apply
|
|
1532
1636
|
`additionalProperties`, so any array at all would have passed.
|
|
1533
1637
|
- `${CRITERIA}` lives in the shared cacheable prefix, identical for every reviewer.
|
|
1534
1638
|
Subsetting it per reviewer would invalidate the prefix for the whole panel and re-bill the
|
|
@@ -1550,7 +1654,7 @@ cut leaves nothing half-migrated.
|
|
|
1550
1654
|
|
|
1551
1655
|
- **`ios-coding-standard` in the repo was a version behind the installed copy** (95 rules
|
|
1552
1656
|
v1.0.0 vs 99 rules v1.1.0). Because `installSkills()` copies the repo over the
|
|
1553
|
-
destination, the next `/multi-agent:update` would have downgraded a user's registry
|
|
1657
|
+
destination, the next `/multi-agent:update` would have downgraded a user's registry -
|
|
1554
1658
|
harmless while nothing read it, a correctness regression the moment Phase 4 blocks on rule
|
|
1555
1659
|
IDs. Resynced to 99 rules.
|
|
1556
1660
|
- `modules/*.yml` overlays and `references/EXAMPLES.md` are deliberately NOT shipped: they
|
|
@@ -1576,8 +1680,8 @@ gates are named per item.
|
|
|
1576
1680
|
|
|
1577
1681
|
- **The Tier 2 Figma PAT could not be found on any migrated install.** `migrate-prefs.mjs`
|
|
1578
1682
|
consolidated `keychainMapping.figma_pat` into `.figma` and deleted the old key, but the
|
|
1579
|
-
setup wizard kept
|
|
1580
|
-
had just created), both Tier 2 fetchers kept
|
|
1683
|
+
setup wizard kept _writing_ `figma_pat` (so the next migration deleted the mapping it
|
|
1684
|
+
had just created), both Tier 2 fetchers kept _reading_ it, and the failure text told the
|
|
1581
1685
|
user to map the one key guaranteed not to survive. Tier 2 reported `missing-token` while
|
|
1582
1686
|
a valid PAT sat under the new name. Claude Code's MCP tier masked it; Copilot and Codex,
|
|
1583
1687
|
which serve no Figma MCP tools at all, fell straight to Tier 3. The lookup now lives once
|
|
@@ -1636,7 +1740,7 @@ gates are named per item.
|
|
|
1636
1740
|
written. Copilot now rewrites the trees it owns, and installs `rules/` as well, closing
|
|
1637
1741
|
the same silent-nothing fallback Codex's installer already documented.
|
|
1638
1742
|
- **`phase-tracker.sh` never reclaimed a stale lock on Linux.** It tried `stat -f %m`
|
|
1639
|
-
before `stat -c %Y`, and on GNU coreutils `stat -f` is a
|
|
1743
|
+
before `stat -c %Y`, and on GNU coreutils `stat -f` is a _valid_ flag (`--file-system`,
|
|
1640
1744
|
where `%m` is the mount point): it succeeds, returns something like `/`, the `||` never
|
|
1641
1745
|
fires, and the age arithmetic runs on a path. Every tracker call then spun the full ~5s
|
|
1642
1746
|
bound and fell open with a warning. Every other `stat` call site in the repo already had
|
|
@@ -1651,7 +1755,7 @@ gates are named per item.
|
|
|
1651
1755
|
the previous generation. Now `claude-opus-5` and `claude-sonnet-5`, with the rung/ID split
|
|
1652
1756
|
stated in the fallback contract. Gate: a generation guard in `smoke-model-fallback.sh`.
|
|
1653
1757
|
- **`rules/pipeline-output-formatting.md` did not exist.** Two shipped skills named it as
|
|
1654
|
-
the PR-body contract to follow. The install-layout smoke had been
|
|
1758
|
+
the PR-body contract to follow. The install-layout smoke had been _reporting_ paths that
|
|
1655
1759
|
exist on no host as a note rather than failing on them, which is how it survived; that
|
|
1656
1760
|
claim is now strict.
|
|
1657
1761
|
- **A pre-migration preferences file failed validation before the migration could fix it.**
|
|
@@ -1708,7 +1812,7 @@ gates are named per item.
|
|
|
1708
1812
|
|
|
1709
1813
|
- **Every fetcher died on a Copilot-only or Codex-only install.** Eleven runtime scripts
|
|
1710
1814
|
loaded `credential-store-resolver.sh` as `. "$HOME/.claude/lib/..." || . <next> || {
|
|
1711
|
-
|
|
1815
|
+
error }`, all of them under `set -e`. Sourcing a file that does not exist aborts the
|
|
1712
1816
|
shell outright - `||` included - so on a host without `~/.claude/lib` the chain reached
|
|
1713
1817
|
neither its later candidates nor its error branch: bare exit 1, no message. Reordering
|
|
1714
1818
|
does not help, because whichever candidate is absent aborts at that point. All eleven
|
|
@@ -1799,7 +1903,7 @@ gates are named per item.
|
|
|
1799
1903
|
`--dev` skips the LLM phases, not Phase 0's pickers.
|
|
1800
1904
|
- **An unreachable external source is announced instead of absorbed.** Exit code `3`
|
|
1801
1905
|
used to mean "mark it failed and continue", so an expired token and a VPN-off remote
|
|
1802
|
-
both reached the analysis phase as
|
|
1906
|
+
both reached the analysis phase as _no data_, indistinguishable from a ticket that
|
|
1803
1907
|
referenced nothing. The run then planned from a partial picture and reported success.
|
|
1804
1908
|
`external-context-injection.md` now classifies the stderr and surfaces a decision -
|
|
1805
1909
|
refresh the credential, connect the VPN and retry, supply a current URL, or continue
|
|
@@ -1821,7 +1925,7 @@ gates are named per item.
|
|
|
1821
1925
|
`api.figma.com` returned 403 for a healthy token and would have sent the user to
|
|
1822
1926
|
regenerate something that worked. It is now reported as not-probeable, with liveness
|
|
1823
1927
|
left to `figma-mcp-refresh.sh`, which owns the grant.
|
|
1824
|
-
- A failed `curl` wrote `000` through `write-out`
|
|
1928
|
+
- A failed `curl` wrote `000` through `write-out` _and_ triggered the `|| echo "000"`
|
|
1825
1929
|
fallback, producing `000000` and a bogus verdict for what was simply a closed VPN.
|
|
1826
1930
|
Any non-three-digit status now reads as `probe-error` rather than being dressed up as
|
|
1827
1931
|
a service verdict.
|
|
@@ -1858,7 +1962,7 @@ gates are named per item.
|
|
|
1858
1962
|
### Fixed
|
|
1859
1963
|
|
|
1860
1964
|
- **`build-stack-plugins.mjs` never propagated content edits.** It copied a skill only
|
|
1861
|
-
when the skill
|
|
1965
|
+
when the skill _set_ changed, so editing a routed skill in `shared/external` reached
|
|
1862
1966
|
no plugin while the generator reported "all plugins up to date" - which read as
|
|
1863
1967
|
confirmation. This falsified the single-authoring-source guarantee the whole
|
|
1864
1968
|
`shared/external` design rests on. Found by converting banned punctuation in
|
|
@@ -1890,7 +1994,7 @@ The iOS coding standard reaches all three hosts, and works outside the pipeline.
|
|
|
1890
1994
|
The 95-rule registry lived as a pipeline-local routine. Two consequences, both
|
|
1891
1995
|
measured: only Claude Code could reach it, because `local-only` commands are
|
|
1892
1996
|
deliberately never synced (verified absent on Copilot CLI and Codex CLI), and it
|
|
1893
|
-
applied only when the routine was invoked explicitly
|
|
1997
|
+
applied only when the routine was invoked explicitly - nothing pulled the rules in
|
|
1894
1998
|
while Swift was being written. The plugin's own `reference/code-style` skill is 154
|
|
1895
1999
|
lines of prose with zero rule IDs, so the registry was not reachable that way either.
|
|
1896
2000
|
|
|
@@ -1934,7 +2038,6 @@ lines of prose with zero rule IDs, so the registry was not reachable that way ei
|
|
|
1934
2038
|
predates this change and `tools/validate.py` warns on it; routing `knowledge/` behind
|
|
1935
2039
|
the plugin's `index` skill is the fix and is separate work.
|
|
1936
2040
|
|
|
1937
|
-
|
|
1938
2041
|
## [13.1.0] - 2026-07-27
|
|
1939
2042
|
|
|
1940
2043
|
Six gates, from one branch that spent half its commits on rework.
|
|
@@ -1944,7 +2047,7 @@ chain, measured from the run's own artefacts: Phase 0 reported `completed` havin
|
|
|
1944
2047
|
written only `tracker-state.json`, so `agent-state.json` and its `taskType` never
|
|
1945
2048
|
existed, so Phase 3's component dispatch could not fire. The stack plugin already
|
|
1946
2049
|
ships `create-screen`, `figma-validate` (7 criteria including design-token compliance
|
|
1947
|
-
and Code Connect strategy) and `figma-review` (14-item checklist)
|
|
2050
|
+
and Code Connect strategy) and `figma-review` (14-item checklist) - none of them ran.
|
|
1948
2051
|
Padding came out 16 where the frame said `Spacing/12`. Three of six commits were fixes,
|
|
1949
2052
|
the last a full sheet rebuild.
|
|
1950
2053
|
|
|
@@ -1961,7 +2064,7 @@ invokes a skill that was already written but never called.
|
|
|
1961
2064
|
gate is testable without reproducing a run.
|
|
1962
2065
|
- **Phase 4 Step 2.8, visual conformance gate.** Runs `figma-review` and
|
|
1963
2066
|
`/multi-agent:design-check` for component/screen work, with the coverage gate, and
|
|
1964
|
-
asserts Code Connect was **published** rather than merely written
|
|
2067
|
+
asserts Code Connect was **published** rather than merely written - a
|
|
1965
2068
|
`*.figma.swift` on disk with "Not published" in Figma is a binding that exists for
|
|
1966
2069
|
nobody. `design-check` had been a command with no phase invoking it, so the only
|
|
1967
2070
|
thing standing between a build and visual drift was the user opening the app.
|
|
@@ -1976,14 +2079,14 @@ invokes a skill that was already written but never called.
|
|
|
1976
2079
|
|
|
1977
2080
|
- **Component dispatch halts instead of degrading.** The contract used to send an
|
|
1978
2081
|
incomplete-state component task down the generic TDD path while the next sentence
|
|
1979
|
-
said "never silently skip the Figma work"
|
|
2082
|
+
said "never silently skip the Figma work" - taking the generic path _is_ skipping
|
|
1980
2083
|
it. That wording authorised the exact failure above.
|
|
1981
2084
|
- **Dispatch routes on scope, not just platform.** A screen and a component are
|
|
1982
2085
|
different jobs and the plugin ships a skill for each; routing a screen to the
|
|
1983
2086
|
component skill is why one run produced entities and a mapper but left the screen
|
|
1984
2087
|
half-wired. `figma-validate` now runs before the create skill.
|
|
1985
2088
|
- **Phase 1 captures spacing by token name, per atom.** Phase 3 is forbidden from
|
|
1986
|
-
calling Figma, so a pixel number
|
|
2089
|
+
calling Figma, so a pixel number - or a missing entry - is unrecoverable later. A
|
|
1987
2090
|
UI frame with no spacing entries is a capture failure, not an empty frame.
|
|
1988
2091
|
- **Phase 3 records that generated trees are not editable.** A mock fixture went into
|
|
1989
2092
|
the generated tree; the fix moved it to the custom tree and registered the scenario
|
|
@@ -1993,7 +2096,6 @@ invokes a skill that was already written but never called.
|
|
|
1993
2096
|
Planning by design, so there is no phase that turns a document into a plan. The doc
|
|
1994
2097
|
becomes context for one pass and work lands in whatever order it was read.
|
|
1995
2098
|
|
|
1996
|
-
|
|
1997
2099
|
## [13.0.0] - 2026-07-27
|
|
1998
2100
|
|
|
1999
2101
|
> **Why major and not minor.** The additions here are additive, but two defaults
|
|
@@ -2003,7 +2105,6 @@ invokes a skill that was already written but never called.
|
|
|
2003
2105
|
> comparing Codex on skill directories would read a correct install as drift).
|
|
2004
2106
|
> Per the versioning policy that is a changed default, not a new option.
|
|
2005
2107
|
|
|
2006
|
-
|
|
2007
2108
|
Codex CLI becomes a third supported host, and a new pre-submission validation command.
|
|
2008
2109
|
|
|
2009
2110
|
### Added
|
|
@@ -2014,19 +2115,19 @@ Codex CLI becomes a third supported host, and a new pre-submission validation co
|
|
|
2014
2115
|
with per-agent model and reasoning effort, hooks, MCP and a plugin marketplace,
|
|
2015
2116
|
so it earns the same treatment as the other two rather than an adapter.
|
|
2016
2117
|
`install/codex.mjs` writes `~/.codex/{skills/multi-agent,multi-agent-refs,
|
|
2017
|
-
|
|
2118
|
+
agents/*.toml,prompts/multi-agent.md,scripts,lib,schemas,rules}` plus a managed
|
|
2018
2119
|
span in `~/.codex/AGENTS.md`, and registers the dev-toolkit MCP server through
|
|
2019
2120
|
`codex mcp add` rather than hand-merging TOML that Codex owns.
|
|
2020
2121
|
- **`/multi-agent:testflight-validation`** (command 43). Three gates, each seeing
|
|
2021
2122
|
what the others structurally cannot: the static 18-rule archive audit, Apple's
|
|
2022
2123
|
own `altool --validate-app`, and a Review-Guidelines check against repo evidence.
|
|
2023
|
-
ITMS codes are mapped to the rule each implies. It validates only
|
|
2024
|
-
`--upload-app`
|
|
2124
|
+
ITMS codes are mapped to the rule each implies. It validates only - never
|
|
2125
|
+
`--upload-app` - so a validation run cannot ship a build by accident.
|
|
2025
2126
|
- **App Store Connect credentials in `/multi-agent:setup`**, inside the Step 1
|
|
2026
2127
|
discovery / Step 2 mapping / Step 3b onboarding flow alongside Jira and
|
|
2027
2128
|
Bitbucket, not as a late add-on: a user who already has one in their keychain
|
|
2028
2129
|
gets it mapped automatically. Tier 1 is an API key, tier 2 an Apple ID plus an
|
|
2029
|
-
app-specific password
|
|
2130
|
+
app-specific password - which matters because creating an API key needs an
|
|
2030
2131
|
Admin or App Manager role many developers on a corporate team do not have.
|
|
2031
2132
|
|
|
2032
2133
|
### Changed
|
|
@@ -2042,8 +2143,8 @@ Codex CLI becomes a third supported host, and a new pre-submission validation co
|
|
|
2042
2143
|
gpt-5.6 @ medium, triage at max) with two measured constraints written into the
|
|
2043
2144
|
contract: a `spawn_agent` that sets `model` without `fork_turns: "none"`
|
|
2044
2145
|
**silently inherits the parent model**, collapsing the panel onto one
|
|
2045
|
-
perspective; and 4 concurrency slots
|
|
2046
|
-
reviewers the ceiling. Single-vendor caveat recorded
|
|
2146
|
+
perspective; and 4 concurrency slots _including the orchestrator_ make three
|
|
2147
|
+
reviewers the ceiling. Single-vendor caveat recorded - consensus among three
|
|
2047
2148
|
OpenAI models is weaker evidence than the same consensus on a two-vendor host.
|
|
2048
2149
|
- `tracker-contract.md` gains the `codex` visual channel: the native `update_plan`
|
|
2049
2150
|
tool, with its no-parallel-call and no-plan-mode caveats.
|
|
@@ -2063,7 +2164,7 @@ Codex CLI becomes a third supported host, and a new pre-submission validation co
|
|
|
2063
2164
|
- **The Phase 0 branch-collision probe read a failed probe as "no collision".**
|
|
2064
2165
|
With `2>/dev/null` and an empty-output test, an auth or network failure was
|
|
2065
2166
|
indistinguishable from "the ref does not exist", so the run created a branch
|
|
2066
|
-
that already existed on the remote
|
|
2167
|
+
that already existed on the remote - surfacing as a rejected push at Phase 6,
|
|
2067
2168
|
far from its cause. Exit codes are now distinguished (0 exists, 2 free, anything
|
|
2068
2169
|
else unknown-and-recorded).
|
|
2069
2170
|
- **`/multi-agent:update` deleted the Codex prompt on every run**, pruning
|
|
@@ -2076,14 +2177,14 @@ Codex CLI becomes a third supported host, and a new pre-submission validation co
|
|
|
2076
2177
|
(added in v12.11.0) holds the banned characters as its own assertion list and
|
|
2077
2178
|
was never allowlisted.
|
|
2078
2179
|
- **Half-English pickers on Turkish runs: six shipped files contradicted the
|
|
2079
|
-
canonical language matrix.** `rules.md` is unambiguous
|
|
2180
|
+
canonical language matrix.** `rules.md` is unambiguous - `AskUserQuestion`
|
|
2080
2181
|
`question` and `options[].description` render in `outputLanguage`, only `label`,
|
|
2081
2182
|
`header` and host chrome are pinned to English. But `/multi-agent:setup` Step 0
|
|
2082
2183
|
claimed `promptLanguage` governs "interactive pickers and prompts ... Picker UI is
|
|
2083
2184
|
always English", `/multi-agent:language` claimed "confirmation prompts ... are
|
|
2084
2185
|
authored in English. Only the assistant's free-form replies follow
|
|
2085
2186
|
`outputLanguage`", and four more files said variations of the same. Those are the
|
|
2086
|
-
two commands a user goes to
|
|
2187
|
+
two commands a user goes to _configure_ this, so the model followed whichever
|
|
2087
2188
|
canonical-looking doc it read first and gate questions came out English. All six
|
|
2088
2189
|
corrected to describe `promptLanguage`'s real scope: the button and chip chrome,
|
|
2089
2190
|
never the question a user reads.
|
|
@@ -2093,7 +2194,7 @@ Codex CLI becomes a third supported host, and a new pre-submission validation co
|
|
|
2093
2194
|
- New `smoke-language-matrix.sh`: asserts `rules.md` still pins the per-field
|
|
2094
2195
|
matrix, then greps every shipped command / skill / ref for the seven phrasings
|
|
2095
2196
|
that actually shipped and contradicted it. Two authoritative docs giving opposite
|
|
2096
|
-
answers is a spec with two answers, not a wording nit
|
|
2197
|
+
answers is a spec with two answers, not a wording nit - the gate found a sixth
|
|
2097
2198
|
violation (`_input-parser.md`) that the manual sweep had missed.
|
|
2098
2199
|
|
|
2099
2200
|
### Gates
|
|
@@ -2105,7 +2206,7 @@ Codex CLI becomes a third supported host, and a new pre-submission validation co
|
|
|
2105
2206
|
- `smoke-install-layout.sh` extended to three targets, including a check that every
|
|
2106
2207
|
concrete `$HOME/.codex` reference **resolves on disk**. The earlier "no `.claude`
|
|
2107
2208
|
references remain" check was blind to a wrongly-rewritten path, which is how
|
|
2108
|
-
`commands/multi-agent.md` became `multi-agent-refs/commands.md`
|
|
2209
|
+
`commands/multi-agent.md` became `multi-agent-refs/commands.md` - well-formed,
|
|
2109
2210
|
pointing at nothing. A miss is classified by whether the Claude counterpart
|
|
2110
2211
|
exists, so broken-by-rewrite fails and broken-upstream is only reported.
|
|
2111
2212
|
- New `test/codex-install.test.mjs` (24 assertions) locks the path-rewrite map,
|
|
@@ -2138,11 +2239,11 @@ bug that produced it.
|
|
|
2138
2239
|
|
|
2139
2240
|
**All three encodings**, because a title can arrive in any of them:
|
|
2140
2241
|
|
|
2141
|
-
|
|
|
2142
|
-
|
|
2143
|
-
| named
|
|
2144
|
-
| decimal | `&`
|
|
2145
|
-
| hex
|
|
2242
|
+
| | ampersand | less-than | em-dash |
|
|
2243
|
+
| ------- | --------- | --------- | ---------- |
|
|
2244
|
+
| named | `&` | `<` | `—` |
|
|
2245
|
+
| decimal | `&` | `<` | `—` |
|
|
2246
|
+
| hex | `&` | `<` | `—` |
|
|
2146
2247
|
|
|
2147
2248
|
The first version of this fix handled only the named column, which is the same bug
|
|
2148
2249
|
fixed for one spelling out of three.
|
|
@@ -2360,7 +2461,7 @@ entry, so the count would have under-reported by 100+ files.
|
|
|
2360
2461
|
### Four gates that were tested, green, and never ran
|
|
2361
2462
|
|
|
2362
2463
|
Every gate in this repo checks its own behaviour. Nothing checked that a gate is
|
|
2363
|
-
|
|
2464
|
+
_reachable_. Four were not - each with a passing unit test and a passing smoke,
|
|
2364
2465
|
and no reference from `pipeline/commands/`, `multi-agent-refs/`, `agents/`,
|
|
2365
2466
|
`skills/` or `install/`:
|
|
2366
2467
|
|
|
@@ -2521,7 +2622,7 @@ while fixing them.
|
|
|
2521
2622
|
Two threads. The design-check command gains a scenario inventory, a coverage
|
|
2522
2623
|
gate and MCP-currency gating, and the refactor/sync pair learns to research,
|
|
2523
2624
|
audit and ship the companion dev-toolkit MCP server. Alongside that, a defect
|
|
2524
|
-
sweep found eight gates and features that exited 0 while doing nothing -
|
|
2625
|
+
sweep found eight gates and features that exited 0 while doing nothing - six
|
|
2525
2626
|
of them guarded by a smoke test whose fixture had the wrong shape, so the suite
|
|
2526
2627
|
stayed green the whole time.
|
|
2527
2628
|
|
|
@@ -2553,14 +2654,14 @@ Requires `@mmerterden/dev-toolkit-mcp` >= v2.9.0 for the App Store audit path.
|
|
|
2553
2654
|
`smoke-personal-data.sh --root`, keeping one pattern list.
|
|
2554
2655
|
- **shellcheck moves from `error` to `warning` severity.** `error` returns zero
|
|
2555
2656
|
findings across all 175 scripts, so the gate could not catch this repo's
|
|
2556
|
-
actual defect class -
|
|
2657
|
+
actual defect class - SC2046 is a warning. Noisy codes are excluded with a
|
|
2557
2658
|
per-code rationale. Four real findings surfaced and are fixed, including two
|
|
2558
2659
|
unguarded `cd` calls in `smoke-shadow-git.sh`, one preceding a relative
|
|
2559
2660
|
`rm -rf`.
|
|
2560
2661
|
- **`credential-store.sh` resolves logical keys through
|
|
2561
2662
|
`prefs.global.keychainMapping`.** `get github` searched the backend for a
|
|
2562
2663
|
credential literally named "github" and returned empty with exit 1 -
|
|
2563
|
-
indistinguishable from "no such credential" -
|
|
2664
|
+
indistinguishable from "no such credential" - because the entry is named by
|
|
2564
2665
|
the mapping. Applied in `get`/`set`/`delete`, falling back to the logical key
|
|
2565
2666
|
when no mapping exists.
|
|
2566
2667
|
|
|
@@ -2770,6 +2871,7 @@ all project specifics live in per-project `figma-config` / prefs.
|
|
|
2770
2871
|
## [12.2.0] - 2026-07-21
|
|
2771
2872
|
|
|
2772
2873
|
### Added
|
|
2874
|
+
|
|
2773
2875
|
- **Graylog log-fetch integration** — when a task's ticket/issue carries a transaction id (`trx`/`trxId`/`transaction id`) and/or a conversation id (`conversationId`/`convId`/`X-conversationId`), the pipeline fetches the matching Graylog log messages and injects them as advisory diagnostic context into Phase 1 analysis. Mirrors the Crashlytics analysis-context adapter (advisory only, no Phase-4 gate).
|
|
2774
2876
|
- New `lib/fetch-graylog.sh` adapter (mirrors the Fortify hosted-service shape): host from `prefs.global.hosts.graylog` (+ `GRAYLOG_HOST_OVERRIDE`), token via `prefs.global.keychainMapping.graylog` → `${USER}_Graylog_Access_Token` through the credential-store resolver. Graylog PAT auth is HTTP Basic `<token>:token` delivered only via a `curl -K` process-substitution config (never on argv). Universal/relative search by full-text OR of the ids, range + limit configurable via env.
|
|
2775
2877
|
- **Non-blocking by design:** any network/VPN failure degrades to an empty normalized result and exit 0 — a log fetch never blocks a run. Exit codes: 0 ok/degraded, 2 missing-token, 3 genuine auth rejection, 4 usage, 6 host-not-configured.
|
|
@@ -2778,6 +2880,7 @@ all project specifics live in per-project `figma-config` / prefs.
|
|
|
2778
2880
|
## [12.1.1] - 2026-07-21
|
|
2779
2881
|
|
|
2780
2882
|
### Changed
|
|
2883
|
+
|
|
2781
2884
|
- **Channel outputs no longer carry decorative/emotive emoji or smileys.** Jira/issue comments, Confluence & Wiki pages, and PR bodies are plain technical prose. Added an explicit no-emoji hard-rule to each channel template (`multi-agent-refs/channels/{jira,issue-comment,confluence,wiki}.md`) and an emoji-stripping pattern to the humanizer (`shared/external/humanizer`). Functional status/severity marks a fixed template defines (`✅/⏳` phase ticks, `🔴/🟡` severity labels) are unaffected.
|
|
2782
2885
|
|
|
2783
2886
|
---
|
|
@@ -2785,20 +2888,25 @@ all project specifics live in per-project `figma-config` / prefs.
|
|
|
2785
2888
|
## [12.1.0] - 2026-07-21
|
|
2786
2889
|
|
|
2787
2890
|
### Security
|
|
2891
|
+
|
|
2788
2892
|
- **`agent-guard.sh` is now wired by the default installer** (was opt-in via the setup template). A plain `install` now OS-enforces the two load-bearing git gates on every `Bash` tool call: no AI/assistant attribution in commit messages, and no force-push to a protected branch (`main`/`master`/`develop`).
|
|
2789
2893
|
- **Force-push protection now fails CLOSED.** A detected force-push that can't be tokenized, or a bare force-push while the current branch can't be confirmed non-protected, is blocked rather than allowed. (The general guard stays fail-open; only the data-loss path is fail-closed.)
|
|
2790
2894
|
- **Multi-repo clone hardening.** `cmd_prepare` disables git's `ext::`/`fd::` remote helpers (`protocol.ext.allow=never`, `protocol.fd.allow=never`) and ends options with `--`, closing an arbitrary-command-execution / option-injection vector on repo URLs sourced from `.gitmodules` suggestions. Local/file/https/ssh clones are unaffected.
|
|
2791
2895
|
|
|
2792
2896
|
### Changed
|
|
2897
|
+
|
|
2793
2898
|
- **Node floor raised to 20** (`.nvmrc`, `engines.node` → `>=20.0.0`). Node 18 was EOL and untested by CI; the matrix already covers 20/22.
|
|
2794
2899
|
|
|
2795
2900
|
### Refactored
|
|
2901
|
+
|
|
2796
2902
|
- **Token-cost pricing is now a single source.** The per-Mtok cost formula, previously copy-pasted across ~6 bash/mjs scripts, lives in `cost-lib.sh` (bash) + `_cost.mjs` (Node), both reading the shared `cost-table.json`. Zero runtime dependencies preserved.
|
|
2797
2903
|
|
|
2798
2904
|
### Added
|
|
2905
|
+
|
|
2799
2906
|
- **`smoke-source-parity.sh`** — guards feature-set drift between the two source trees (`commands/multi-agent/<name>` vs `skills/shared/core/multi-agent-<name>`); fails if a feature exists in one tree but not the other.
|
|
2800
2907
|
|
|
2801
2908
|
### Docs
|
|
2909
|
+
|
|
2802
2910
|
- Refreshed post-v12 doc drift: `SECURITY.md` + `ROADMAP.md` support/version markers → 12.x; `docs/features.md` smoke-suite count `10` → `100+`; ADR index now lists 0008 and 0008 carries a v10.7.0 amendment (the `_adapters.mjs` module was removed); `CONTRIBUTING.md` coverage claim clarified (local-only) and the stale phase-docs path corrected to `pipeline/multi-agent-refs/phases/`.
|
|
2803
2911
|
|
|
2804
2912
|
---
|
|
@@ -2918,7 +3026,7 @@ research, bug hunt, category scoring, upstream-drift check).
|
|
|
2918
3026
|
- **False-success family.** `multi-repo-pipeline.sh` no longer prints
|
|
2919
3027
|
"committed/pushed" on failure; `repo-cache.sh` keeps the previous cache when a
|
|
2920
3028
|
refresh fails instead of serving an empty file for the TTL; `review-watch.sh
|
|
2921
|
-
|
|
3029
|
+
--watch` survives transient gh failures and its cursor can no longer move
|
|
2922
3030
|
backwards.
|
|
2923
3031
|
- **`issue-fetcher.sh`** classifies bare `#316` / `316` correctly (repo picker
|
|
2924
3032
|
path instead of a malformed `//issues/` URL).
|
|
@@ -2928,7 +3036,7 @@ research, bug hunt, category scoring, upstream-drift check).
|
|
|
2928
3036
|
code, ballooning snapshots with DerivedData), and `restore --files` removes
|
|
2929
3037
|
files created after the snapshot instead of keeping half the change.
|
|
2930
3038
|
- **macOS bash 3.2 portability**: `${URL,,}` in `fetch-swagger.sh`, `date -r
|
|
2931
|
-
|
|
3039
|
+
<file>` in `audit-log-rotate.sh` (which also rotates atomically now).
|
|
2932
3040
|
- **Glob translation** in `triage-memory.mjs` / `test-gap-scan.mjs`: `**` no
|
|
2933
3041
|
longer breaks after the `*` pass (nested-path filters match again).
|
|
2934
3042
|
- **`migrate-prefs.mjs`** errors on unknown flags (a `--dry-rnu` typo used to
|
|
@@ -3024,7 +3132,7 @@ Self-audit patch (found by running `/multi-agent:refactor` on the pipeline itsel
|
|
|
3024
3132
|
lists it in the PRESERVED summary.
|
|
3025
3133
|
- **Fix (gate regression): `lint-skills` scoped to `pipeline/skills`.** The
|
|
3026
3134
|
v11.3.0 command-layout migration made command files match `find pipeline -name
|
|
3027
|
-
|
|
3135
|
+
SKILL.md`; slash commands have no `name:` frontmatter, so the skill linter
|
|
3028
3136
|
started erroring on all 37 of them (latent because CI is billing-paused and
|
|
3029
3137
|
releases were published manually). The linter now only checks actual skills.
|
|
3030
3138
|
- **Fix: `.skills-index.json` is idempotent** - dropped the `generatedAt`
|
|
@@ -3035,7 +3143,7 @@ Self-audit patch (found by running `/multi-agent:refactor` on the pipeline itsel
|
|
|
3035
3143
|
- **Fix: install "dev-only excluded" count** is now the real file count (the
|
|
3036
3144
|
`fixtures/` directory was under-counted as one entry).
|
|
3037
3145
|
- **Security (supply-chain):** `release.yml` publishes with `npm publish
|
|
3038
|
-
|
|
3146
|
+
--provenance` (`id-token: write`); all GitHub Actions pinned to commit SHAs;
|
|
3039
3147
|
added `.github/dependabot.yml` (actions + npm dev deps); `credential-store.sh`
|
|
3040
3148
|
escapes single quotes in the Windows PowerShell paths.
|
|
3041
3149
|
- **New: `eval-mine-corpus.mjs`** turns recorded triage decisions
|
|
@@ -3147,7 +3255,7 @@ command is a breaking surface change).
|
|
|
3147
3255
|
skeleton (Task/Story: Detailed Description, Scope, Acceptance Criteria, Test
|
|
3148
3256
|
Scenarios; Bug: Detailed Description, Steps to Reproduce, Expected/Actual
|
|
3149
3257
|
Result, Environment). Conditional sections (Design Reference, API Contract /
|
|
3150
|
-
Swagger, Screenshots, Notes) render only when their trigger is present
|
|
3258
|
+
Swagger, Screenshots, Notes) render only when their trigger is present - no
|
|
3151
3259
|
empty placeholder headings, nothing invented.
|
|
3152
3260
|
- **Test Scenarios pulled from Jira convention.** Detects linked Xray/Zephyr test
|
|
3153
3261
|
issues or a dominant test-scenario heading style and reuses it; falls back to an
|
|
@@ -3290,7 +3398,7 @@ Live tracker UX: per-tile cost, a real "currently doing X" line, and tracker con
|
|
|
3290
3398
|
history (elapsed, tokens, USD) survives, Phase 5 is closed with a Result
|
|
3291
3399
|
meta, the Claude Code TaskList is rebuilt from state, and one line
|
|
3292
3400
|
summarizes the inherited history (`Continuing <id>: phases 0-3 finished
|
|
3293
|
-
|
|
3401
|
+
earlier (12m, 38.4k tok, ~$0.74)`). `add` is idempotent to make this safe.
|
|
3294
3402
|
- **`/multi-agent:resume` rebuilds the phase tiles** from `tracker-state.json`
|
|
3295
3403
|
(the contract documented it; the command now actually does it).
|
|
3296
3404
|
- **Phase 0 + 7 token forwarding**: the clarifier call and the Phase 7 report
|
|
@@ -3591,7 +3699,7 @@ Generic SwiftUI interaction coverage for the figma-to-swiftui pipeline. Three
|
|
|
3591
3699
|
new cross-cutting integration skills (navigation, overlays, bottom sheets) plus
|
|
3592
3700
|
a reconcile-and-extend workflow, all native-SwiftUI-first with an optional
|
|
3593
3701
|
per-project `ui.*` config hook so the same capabilities work on any SwiftUI
|
|
3594
|
-
codebase
|
|
3702
|
+
codebase - no app-specific coupling. Phase 3D dev detection and Phase 4 review
|
|
3595
3703
|
both consume them.
|
|
3596
3704
|
|
|
3597
3705
|
### Added
|
|
@@ -3609,12 +3717,12 @@ both consume them.
|
|
|
3609
3717
|
component against current Figma (drift-heal) + additively extend it for a
|
|
3610
3718
|
need, behind a mandatory human gate; distinct from `figma-to-swiftui`
|
|
3611
3719
|
(build new), `figma-mend` (rebuild), and `figma-fix` (review bug).
|
|
3612
|
-
- **`animated-gradient-border` UI pattern** (`figma-ui-patterns/patterns/`)
|
|
3720
|
+
- **`animated-gradient-border` UI pattern** (`figma-ui-patterns/patterns/`) -
|
|
3613
3721
|
self-contained native-SwiftUI recipe (angular-gradient stroke + Reduce-Motion
|
|
3614
3722
|
gate), no external dependency.
|
|
3615
|
-
- **`ui` block in `figma-project-config.schema.json`**
|
|
3723
|
+
- **`ui` block in `figma-project-config.schema.json`** - optional
|
|
3616
3724
|
`navigationSystem` / `overlaySystem` / `sheetSystem` (`mode: native | custom`
|
|
3617
|
-
|
|
3725
|
+
- type names). Absent → native SwiftUI.
|
|
3618
3726
|
|
|
3619
3727
|
### Changed
|
|
3620
3728
|
|
|
@@ -3650,7 +3758,7 @@ stale worktrees, and validates state before resume.
|
|
|
3650
3758
|
Opus. This also resolves the prior CLAUDE.md-vs-phase-doc inconsistency
|
|
3651
3759
|
(CLAUDE.md already documented Opus for these stages).
|
|
3652
3760
|
- **Model fallback ladder is now `opus -> sonnet`** (was `fable -> opus ->
|
|
3653
|
-
|
|
3761
|
+
sonnet`). `modelFallback.fallbackModel` default is `sonnet`. The
|
|
3654
3762
|
`premiumTierUntil` date gate is kept as a generic mechanism for any future
|
|
3655
3763
|
plan-window-limited premium tier. `model-fallback.md` bumped to v10.1.0 and
|
|
3656
3764
|
`smoke-model-fallback.sh` updated to assert the new ladder + Opus personas.
|
|
@@ -3728,12 +3836,12 @@ token ledger agree on what an input token is.
|
|
|
3728
3836
|
- **Prompt-cache reuse ratio in metrics.** `aggregate-metrics.mjs` now sums
|
|
3729
3837
|
`tokens_cached` per model and reports `cache_ratio = cached / (in + cached)`
|
|
3730
3838
|
- the share of input tokens served from the host prompt cache - per model and
|
|
3731
|
-
|
|
3732
|
-
|
|
3733
|
-
|
|
3839
|
+
overall, in all three output modes (json / markdown / text). This is the
|
|
3840
|
+
single number that says whether cache-friendly prompt structuring is paying
|
|
3841
|
+
off. Backward-compatible: a phase that omits `tokens_cached` reads as 0%.
|
|
3734
3842
|
- **PR review iteration counter derived from the PR itself.** On a `needs_work`
|
|
3735
3843
|
post, the iteration number is re-derived as `max("iteration #N" already on the
|
|
3736
|
-
|
|
3844
|
+
PR) + 1` instead of trusting agent-state. Standalone `/multi-agent:review`
|
|
3737
3845
|
runs use a fresh task id each time, so the PR comments are the only reliable
|
|
3738
3846
|
cross-run source of truth.
|
|
3739
3847
|
|
|
@@ -3743,7 +3851,7 @@ token ledger agree on what an input token is.
|
|
|
3743
3851
|
`render-agent-log-cost.sh` treated `tokens_in` as cache-inclusive and
|
|
3744
3852
|
subtracted the cached count (`fresh = in - min(cached, in)`), while the new
|
|
3745
3853
|
`aggregate-metrics.mjs` treated `tokens_in` as cache-exclusive (`total =
|
|
3746
|
-
|
|
3854
|
+
in + cached`). Fed real data with high cache reuse (`cached > in`), the
|
|
3747
3855
|
renderer collapsed `fresh` to 0 and underpriced the row. Standardized on the
|
|
3748
3856
|
**cache-exclusive** convention that matches the host usage report
|
|
3749
3857
|
(`input_tokens` and `cache_read_input_tokens` are disjoint): the renderer no
|
|
@@ -3786,7 +3894,7 @@ reproduced locally by putting GNU coreutils' gnubin ahead of PATH.
|
|
|
3786
3894
|
`search-logs.sh` (since-filter, scoring, JSON/TSV output) and
|
|
3787
3895
|
`repo-cache.sh` TTLs. Probe order flipped to GNU-first (`stat -c` first;
|
|
3788
3896
|
BSD rejects `-c`, so the fallback chain is safe both ways). `date -r
|
|
3789
|
-
|
|
3897
|
+
<epoch>` display calls gained a GNU `date -d @` fallback.
|
|
3790
3898
|
- **Hardcoded maintainer layout `$HOME/multi-agent-pipeline` removed** from
|
|
3791
3899
|
`smoke-schema-validation.sh` (preferences-template path) and
|
|
3792
3900
|
`smoke-pat-audit.sh` (.gitignore audit-log check) - both now derive the
|
|
@@ -4138,10 +4246,12 @@ Disk hygiene + correctness hardening, all gate-backed.
|
|
|
4138
4246
|
Toward proven (not just designed): measure the features instead of asserting them, and ship the evidence-collection harness.
|
|
4139
4247
|
|
|
4140
4248
|
### Added
|
|
4249
|
+
|
|
4141
4250
|
- **Measured intent-guard accuracy** (`eval-intent.mjs` + `pipeline/eval/intent-cases.json`). 26 labeled EN+TR cases run through `classify-intent.sh`; the gate uses operationally-safe accuracy (the only dangerous errors are a task read as a question -> work skipped, or a question read as a task -> a spurious worktree; `ambiguous` proceeds as a task so it is safe for task cases). Currently 100% safe / 96.2% exact. Wired into `npm test`. Turns the heuristic into a number with a regression set.
|
|
4142
4251
|
- **Per-run outcome metrics** (`run-metrics.mjs` + fixture + `smoke-run-metrics.sh`). Parses an `agent-state.json` into the numbers that answer "did this run go well": review iterations (rework loops), first-pass-clean, reviewer signal-to-noise (accepted / raw findings), consensus verdict, build outcome. Phase 7 emits it; accumulating the output across real runs is the real-world validation corpus that golden tasks + benchmarks only approximate.
|
|
4143
4252
|
|
|
4144
4253
|
### Notes
|
|
4254
|
+
|
|
4145
4255
|
- These address the honest "measure, don't assume" gap from the self-review: the intent guard and review signal are now quantified, and the harness exists to turn real runs into evidence. The remaining step (running real tasks + a public benchmark) is the user's, and cannot be fabricated.
|
|
4146
4256
|
- CI auto-run stays disabled in `test.yml` (the maintainer paused it for GitHub Actions billing); re-enabling the push/PR triggers is a billing decision, not changed here.
|
|
4147
4257
|
|
|
@@ -4150,6 +4260,7 @@ Toward proven (not just designed): measure the features instead of asserting the
|
|
|
4150
4260
|
Closes the structural gaps the adversarial review surfaced: the deterministic gates now actually RUN on the three adapter platforms, and the multi-model review is restored there using each platform's real model lineup.
|
|
4151
4261
|
|
|
4152
4262
|
### Added
|
|
4263
|
+
|
|
4153
4264
|
- **Shared runtime so gates execute on Cursor / Antigravity / VS Code Copilot Chat.** The gate scripts + lib + schemas are installed once to `~/.multi-agent/` (dev-only / PII files excluded) and the emitted agents/commands/workflow reference them by absolute path (`installSharedRuntime` / `rewriteScriptRefs` in `_base.mjs`). Previously the emitted agents referenced `pipeline/scripts/...` which did not exist in the consumer project, so the deterministic gates could not run there at all. Uninstall removes the runtime. Enforced by `smoke-shared-runtime.sh`.
|
|
4154
4265
|
- **Cross-vendor 2-model review on the adapter platforms.** A second reviewer agent (`ma-code-reviewer-x`) is emitted pinned to a different vendor, using each platform's actual model lineup (researched mid-2026, centralized in `_base.mjs#REVIEWER_MODELS`): Cursor `inherit` + `gpt-5.5`; VS Code Copilot Chat `Claude Opus 4.8` + `GPT-5.5`; Antigravity documents a `Gemini 3 Pro` + `Claude Opus 4.6` pair (its models are dropdown-selected, not file-pinned). Restores the cross-model diversity that was Claude-Code / Copilot-CLI-only.
|
|
4155
4266
|
- **Recommended PreToolUse hooks template** (`install/templates/claude-hooks.json`) wiring the secret scan as a HARD pre-commit gate on Claude Code; `multi-agent:setup` Step 8 offers to merge it. The secret scan is the one gate that is OS-hookable (no run-specific args); the others are phase-invoked by contract. Enforced by `smoke-gate-hooks.sh`.
|
|
@@ -4157,9 +4268,11 @@ Closes the structural gaps the adversarial review surfaced: the deterministic ga
|
|
|
4157
4268
|
- **Reviewer-count contract checks** in `smoke-cross-cli-behavior.sh`: locks Claude=2 / Copilot=3 + the documented adapter-platform reviewer set against drift.
|
|
4158
4269
|
|
|
4159
4270
|
### Fixed
|
|
4271
|
+
|
|
4160
4272
|
- VS Code Copilot Chat agents emitted `model: inherit`, which is not a valid Copilot model (there is no `inherit` keyword; omitting `model` inherits the picker). Normal personas now omit `model`; the two reviewers pin a picker label.
|
|
4161
4273
|
|
|
4162
4274
|
### Notes (stated honestly)
|
|
4275
|
+
|
|
4163
4276
|
- The adapter platforms still have no `PreToolUse` equivalent, so their gates are workflow-enforced (run as steps) rather than OS-blocked.
|
|
4164
4277
|
- Pinned adapter models depend on the user's subscription; swap them in `REVIEWER_MODELS` / the Antigravity dropdown if a model is unavailable.
|
|
4165
4278
|
- Old PII-bearing versions (9.3.0-9.3.3) remain in the private registry: GitHub Packages does not support `npm deprecate` (E400), and deleting versions / rewriting git history are irreversible and were left to an explicit owner decision. The package + repo are private, so this is not a public exposure.
|
|
@@ -4169,12 +4282,14 @@ Closes the structural gaps the adversarial review surfaced: the deterministic ga
|
|
|
4169
4282
|
Second round of review-driven fixes - the lower-severity findings left open in 9.3.3, plus an honesty correction on the multi-platform claim.
|
|
4170
4283
|
|
|
4171
4284
|
### Fixed
|
|
4285
|
+
|
|
4172
4286
|
- **Arg parsers dropped values starting with `--`.** `learnings-ledger.mjs` and `evidence-gate.mjs` now accept the `--key=value` form, so a statement / pattern that begins with `--` (e.g. `--statement="-- prefer let"`) is preserved instead of silently failing.
|
|
4173
4287
|
- **Secret scan skipped filenames with spaces.** `pre-commit-check.sh` now iterates staged files NUL-delimited (`git diff --name-only -z`), closing a false-negative where a secret in `my file.txt` went unscanned.
|
|
4174
4288
|
- **`learnings-ledger forget` rewrite is now atomic** (temp file + rename) so a crash or concurrent reader never sees a half-written ledger.
|
|
4175
4289
|
- **`from-triage` scope for a top-level file** is now the filename itself, not a stray `./*` glob.
|
|
4176
4290
|
|
|
4177
4291
|
### Changed
|
|
4292
|
+
|
|
4178
4293
|
- **Honest multi-platform claim.** The README and the adapter-emitted orchestration commands now state plainly that Claude Code + Copilot CLI run the pipeline natively (gate scripts installed), while Cursor / Antigravity / VS Code Copilot Chat receive the workflow + subagents + MCP but run the deterministic gates as ADVISORY (the gate scripts are not copied into those projects). Making those gates execute on the three adapter platforms is tracked work (needs a uniform script-path resolution + per-platform testing), not yet shipped. Stale `cursor.mjs` header ("26 commands can't run there") corrected.
|
|
4179
4294
|
|
|
4180
4295
|
## [9.3.3] - 2026-05-30
|
|
@@ -4182,68 +4297,82 @@ Second round of review-driven fixes - the lower-severity findings left open in 9
|
|
|
4182
4297
|
A 4-agent adversarial review of the v9.3.x work surfaced real defects in the features just shipped; this release fixes them.
|
|
4183
4298
|
|
|
4184
4299
|
### Fixed
|
|
4300
|
+
|
|
4185
4301
|
- **evidence-gate was bypassable.** A failing build log that also contained the word "SUCCESS" (cached-step note, banner) passed because success and failure were weighed equally. Failure markers are now DECISIVE (a definitive failure marker fails the claim regardless of success text), success markers were narrowed (dropped the generic `\bSUCCESS\b`), and caller-supplied `--success/--failure-pattern` are length-capped + compiled in a try/catch so a bad pattern is a clean usage error, not a crash. (`evidence-gate.mjs`, `smoke-evidence-gate.sh`)
|
|
4186
4302
|
- **intent-guard misclassified questions as tasks.** "does it support offline mode", "should we enable caching" were read as tasks (the imperative check beat the interrogative) and would spin up a worktree. A strong question signal (interrogative lead / trailing `?` / TR particle) now wins over a bare imperative verb; an explicit polite request ("can you split this file") stays a task. (`classify-intent.sh`, `smoke-intent-guard.sh`)
|
|
4187
4303
|
- **consensus block was decorative.** `validate-triage.mjs` validated the v3.1.0 consensus block structurally but never cross-checked it: `unanimous-block` + `approved:true`, `unanimous-pass` + an accepted blocker, and a single-reviewer "unanimous" verdict now all fail validation. (`smoke-phase4-triage.sh`)
|
|
4188
4304
|
- **A malformed `tokens_cached` poisoned the whole tokens call.** `log-metric.sh` now sanitizes a non-integer cached count to 0 before forwarding, so the valid in/out counts still land. (`smoke-agent-log-cost.sh`)
|
|
4189
4305
|
|
|
4190
4306
|
### Security
|
|
4307
|
+
|
|
4191
4308
|
- **Stopped real maintainer/employer identifiers from shipping in the npm tarball.** The dev-only figma substitution map (a scrub table that by design holds real upstream values), the two personal-data scanners, and two internal planning docs were excluded from the package via negated `files` entries; stray corporate hosts / repo names / a private Jira key in CHANGELOG + docs examples were genericized. The leak gate now scans the published npm tarball (not just the install tree), closing the hole that let these ship in 9.3.0-9.3.2. The repo/package are private, so this was not a public exposure. (`smoke-install-leak-gate.sh`, `.npmignore`, `package.json` files)
|
|
4192
4309
|
|
|
4193
4310
|
### Changed
|
|
4311
|
+
|
|
4194
4312
|
- README "What's new" refreshed to v9.3.3; em-dashes removed from README and the `MANDATORY` keyword removed from `install/templates/copilot-instructions.md` (project style rules).
|
|
4195
4313
|
|
|
4196
4314
|
## [9.3.2] - 2026-05-30
|
|
4197
4315
|
|
|
4198
4316
|
### Fixed
|
|
4317
|
+
|
|
4199
4318
|
- **Cost-ledger cache pricing is now wired end-to-end.** v9.3.0 added `cacheReadPerMtok` pricing + a cache-reads line to `render-agent-log-cost.sh`, but nothing fed `tokens_cached` to the tracker, so the feature was dormant. `phase-tracker.sh tokens` now accepts an optional 4th `cached` arg (defaults to 0, fully back-compatible), `log-metric.sh` forwards `tokens_cached=` into it, and the Phase 4 telemetry doc documents passing the host's `cache_read_input_tokens`. Verified end-to-end in `smoke-agent-log-cost.sh`.
|
|
4200
4319
|
- `evidence-gate.mjs` made executable to match its sibling `.mjs` scripts.
|
|
4201
4320
|
|
|
4202
4321
|
### Changed
|
|
4322
|
+
|
|
4203
4323
|
- README "What's new" refreshed to v9.3.x (was stale at v8.8.1).
|
|
4204
4324
|
|
|
4205
4325
|
## [9.3.1] - 2026-05-30
|
|
4206
4326
|
|
|
4207
4327
|
### Fixed
|
|
4328
|
+
|
|
4208
4329
|
- **Learnings ledger no longer auto-suppresses rejected BLOCKING findings.** `learnings-ledger.mjs from-triage` previously distilled every rejected finding into a durable "do not re-flag" preference regardless of severity; a single wrong rejection of a blocking issue could permanently silence that class on future runs. Blocking-severity rejections are now skipped (reported as `skippedBlocking`); only lower-severity rejections become durable preferences, and they are recorded at `low` confidence.
|
|
4209
4330
|
|
|
4210
4331
|
### Added
|
|
4332
|
+
|
|
4211
4333
|
- **`learnings-ledger.mjs forget`** subcommand to remove a bad or stale ledger entry by statement substring and/or kind (the one non-append operation), so a wrong learning can be cleared instead of persisting forever. Enforced by `smoke-learnings-ledger.sh`.
|
|
4212
4334
|
|
|
4213
4335
|
## [9.3.0] - 2026-05-30
|
|
4214
4336
|
|
|
4215
4337
|
### Added
|
|
4338
|
+
|
|
4216
4339
|
- **Review consensus surfacing (anti-correlation).** Phase 4 triage now records an optional `consensus` block (triage-output schema v3.1.0): `reviewerCount`, a `verdict` (`unanimous-pass` / `unanimous-block` / `split` / `unverified`), and `disagreements[]`. Unanimous agreement among same-base-model reviewers on a judgment-heavy surface (security, auth, concurrency, money, migration) is marked `unverified` and surfaced to the user instead of being trusted as a pass. Disagreements are shown at the Step 4 checkpoint and written to the agent-log "Review Consensus" section. Validated by `validate-triage.mjs` + new fixtures in `smoke-phase4-triage.sh`.
|
|
4217
4340
|
- **Persistent learnings ledger** (`pipeline/scripts/learnings-ledger.mjs`, schema `learnings-ledger.schema.json`). A per-repo, append-only store of durable architectural facts, conventions, and explicitly rejected review preferences, stored next to the triage corpus. A compact `<repo-learnings>` brief is injected into Phase 1 analysis and Phase 4 triage so agents stop re-discovering structure and reviewers stop re-flagging rejected feedback (the most-cited cold-boot-amnesia complaint). Phase 7 distills each run's rejected findings into the ledger. On by default via `prefs.global.learningsLedger`; per-repo isolated. Enforced by `smoke-learnings-ledger.sh`.
|
|
4218
4341
|
- **Default-FAIL evidence gate** (`pipeline/scripts/evidence-gate.mjs`). A build/test/review "passed" claim is only trusted when a substantiating log artifact exists and shows success; the gate fails CLOSED on missing, empty, or contradicting evidence. Wired into Phase 3 (build), Phase 4 Stage 1 gates (build + test), and Phase 6 (commit). Enforced by `smoke-evidence-gate.sh`.
|
|
4219
4342
|
- **Conceptual-vs-edit intent guard** (`pipeline/lib/classify-intent.sh`). A deterministic, language-aware (EN + TR) classifier runs on free-text input at Phase 0; a question is answered in place instead of spinning up a branch/worktree. On by default via `prefs.global.intentGuard`. Enforced by `smoke-intent-guard.sh`.
|
|
4220
4343
|
|
|
4221
4344
|
### Changed
|
|
4345
|
+
|
|
4222
4346
|
- **Secret pre-commit gate** (`pre-commit-check.sh`) extended beyond pattern matching: high-signal provider-token prefixes (GitHub PAT, Slack, Google API key, Stripe, npm, GitLab), JWT detection, and a Shannon-entropy scan that catches custom/unknown secrets while exempting lockfiles, integrity hashes, source maps, and snapshots.
|
|
4223
4347
|
- **Per-phase cost ledger** (`render-agent-log-cost.sh`) now prices prompt-cache reads at the discounted `cacheReadPerMtok` rate (cost-table schema 1.1.0; backward-compatible, defaults to 0 cached), appends a "Top cost driver" line so the report shows where spend went, and surfaces a cache-reads line when the tracker recorded cache hits.
|
|
4224
4348
|
- Uninstall header and package description refreshed to the current 5-platform set (Cursor / Antigravity / VS Code Copilot Chat), replacing stale Windsurf/Cline references.
|
|
4225
4349
|
|
|
4226
4350
|
### Fixed
|
|
4351
|
+
|
|
4227
4352
|
- Cursor uninstall left an empty `.cursor/commands/` directory behind, and the `.cursor` parent-empty cleanup ran before orchestration teardown so the parent was never reclaimed. Both now clean up after the orchestration uninstall.
|
|
4228
4353
|
|
|
4229
4354
|
## [9.2.0] - 2026-05-30
|
|
4230
4355
|
|
|
4231
4356
|
### Added
|
|
4357
|
+
|
|
4232
4358
|
- **Full-pipeline orchestration on three more platforms** (previously knowledge-layer only). Cursor (`.cursor/agents/ma-*.md` subagents + `.cursor/commands/multi-agent.md` + `.cursor/mcp.json`), Antigravity (`.agent/workflows/multi-agent.md` + `.agent/rules/` + `AGENTS.md` + `.agent/mcp_config.json`), and VS Code Copilot Chat (`.github/agents/ma-*.agent.md` + `.github/prompts/multi-agent.prompt.md` + `.vscode/mcp.json`). Each adapter transforms the pipeline personas into the platform's subagent/agent format and registers the dev-toolkit MCP server. Install with `--cursor` / `--antigravity` / `--copilot-chat` (or `--all-tools`).
|
|
4233
4359
|
- **Picker contract** (`refs/picker-contract.md`) + `pipeline/lib/ask-choice.sh`: a cross-platform single-choice abstraction so confirmations degrade gracefully where there is no native `AskUserQuestion` (numbered-menu fallback; `ASK_CHOICE_DEFAULT` for autopilot/CI).
|
|
4234
4360
|
- **Proactive token-budget cap** (`prefs.global.costBudget` + `cost-budget-check.mjs`): prices the phase-tracker accumulators live and warns/halts before spend runs away.
|
|
4235
4361
|
- **Eval harness** expanded from 2 to 7 golden tasks across all stacks and every triage bucket.
|
|
4236
4362
|
|
|
4237
4363
|
### Changed
|
|
4364
|
+
|
|
4238
4365
|
- **Confirmations are now native pickers** instead of typed keywords (`AskUserQuestion` on Claude Code, degrading per the picker contract elsewhere). Removed the typed `y/N` / `onayla`/`iptal` prompts.
|
|
4239
4366
|
- **Command/skill instruction files are English** throughout (token efficiency + model comprehension); `outputLanguage` still governs all runtime user-facing text.
|
|
4240
4367
|
- Phase 5 (User Test) now runs only in interactive worktree-backed modes (`dev`, `full`); every autopilot/local variant skips it.
|
|
4241
4368
|
- Analysis->plan contract field names aligned across schema, validator, and phase docs; the "no MCP outside analysis" gate made enforceable (telemetry recorded + checked).
|
|
4242
4369
|
|
|
4243
4370
|
### Fixed
|
|
4371
|
+
|
|
4244
4372
|
- Command-injection vectors in `diff-explain.mjs` and `figma-screenshot.sh`; `review-watch` cursor loss (re-reviewed PRs forever); `diff-risk` / `classify-plan-safety` / `match-skills` logic defects; `write-state` stale-lock deadlock; several pre-existing test failures (mode-dispatch drift, README/install-layout counts, token budgets).
|
|
4245
4373
|
|
|
4246
4374
|
### Removed
|
|
4375
|
+
|
|
4247
4376
|
- Dead `--windsurf` / `--cline` / `--continue` / `--zed` install flags (the adapters were dropped in 8.5.4; only the advertising lingered).
|
|
4248
4377
|
|
|
4249
4378
|
## [9.1.1] - 2026-05-16
|
|
@@ -4257,7 +4386,7 @@ A 4-agent adversarial review of the v9.3.x work surfaced real defects in the fea
|
|
|
4257
4386
|
- `pipeline/commands/multi-agent/channels.md`: 103 chars
|
|
4258
4387
|
- `pipeline/skills/shared/core/multi-agent/SKILL.md`: 97 chars
|
|
4259
4388
|
- `pipeline/commands/multi-agent/setup.md`: 79 chars
|
|
4260
|
-
- Mapping: `U+2014` ->
|
|
4389
|
+
- Mapping: `U+2014` -> `-`, `U+2013` -> `-`, `U+2026` -> `...`, `U+201C/D` -> `"`, `U+2018/9` -> `'`, `U+00A7` -> `section`.
|
|
4261
4390
|
|
|
4262
4391
|
### Excluded from sweep
|
|
4263
4392
|
|
|
@@ -4301,13 +4430,13 @@ A 4-agent adversarial review of the v9.3.x work surfaced real defects in the fea
|
|
|
4301
4430
|
|
|
4302
4431
|
Six measurable improvements on the hot path:
|
|
4303
4432
|
|
|
4304
|
-
| Fix
|
|
4305
|
-
|
|
4306
|
-
| `smoke-personal-data.sh` pattern alternation (single grep vs 22 invocations)
|
|
4307
|
-
| `smoke-no-token-prompt.sh` multi-`-e` (single grep vs 7x7=49 invocations)
|
|
4308
|
-
| `phase-tracker.sh` render batched jq (U+001F separator preserves empty fields)
|
|
4309
|
-
| `issue-fetcher.sh` python3 batch (single inline vs 7 separate calls per fetch)
|
|
4310
|
-
| `md2confluence-v3.py` HTTP retry wrapper (3-attempt exponential backoff on 5xx / 429) + `ThreadPoolExecutor(max_workers=4)` paralel attachment
|
|
4433
|
+
| Fix | Before | After | Speedup |
|
|
4434
|
+
| ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------- | ------------------------------------------ | --------------------------------------------------------------------------------- |
|
|
4435
|
+
| `smoke-personal-data.sh` pattern alternation (single grep vs 22 invocations) | 3.348s | 1.545s | 2.2x |
|
|
4436
|
+
| `smoke-no-token-prompt.sh` multi-`-e` (single grep vs 7x7=49 invocations) | 0.485s | 0.014s | 35x |
|
|
4437
|
+
| `phase-tracker.sh` render batched jq (U+001F separator preserves empty fields) | ~7 jq calls per phase + ~3 per sub | 1 batch + 1 per active sub/meta | ~120 subprocess azalma per render |
|
|
4438
|
+
| `issue-fetcher.sh` python3 batch (single inline vs 7 separate calls per fetch) | 0.806s / 3 iter | 0.136s / 3 iter | 5.9x |
|
|
4439
|
+
| `md2confluence-v3.py` HTTP retry wrapper (3-attempt exponential backoff on 5xx / 429) + `ThreadPoolExecutor(max_workers=4)` paralel attachment | sequential N x ~1.5s | parallel ~max(individual) | up to 4x on multi-screenshot pages, plus transient-error resilience |
|
|
4311
4440
|
| `extract-conventions.sh` env override `EXTRACT_CONV_EXTRA_ROOTS` + auto-add `.gitmodules` paths, bucket timeout 30s -> 10s, `xargs basename` -> `awk -F/ '{print $NF}'` (8 callsites) | scan roots too narrow on monorepos with submodules; per-bucket 30s budget | submodule paths auto-detected, faster fail | resolves "confidence: none" on submodule-heavy repos; ~100-300ms saved per bucket |
|
|
4312
4441
|
|
|
4313
4442
|
### Verified
|