@mmerterden/multi-agent-pipeline 16.1.2 → 16.2.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 CHANGED
@@ -16,6 +16,57 @@ Internal file-layout changes that don't affect the slash-command surface are sti
16
16
 
17
17
  ## [Unreleased]
18
18
 
19
+ ## [16.2.0] - 2026-08-23
20
+
21
+ The analysis subsystem said things its gate did not enforce. `locked.md` carries 31 decisions; four of them ended with the sentence "fails the dispatch gate", and the dispatch gate implemented none of the four. This release makes three of them true and pulls the fourth back to what actually happens.
22
+
23
+ ### Fixed
24
+
25
+ - **The humanizer punctuation check flagged text the humanizer is documented to leave alone.** `analysis/render.md` exempts front-matter, fenced code, table rows and URLs; the validator split the whole file and scanned every line, so an em-dash inside a URL or a Swift snippet was a hard ERROR no humanizer pass could clear. Scope now mirrors the pass it enforces. The prose body is still checked, proven by a negative control rather than assumed.
26
+ - **An orphan code fence hid Section 16 from the model.** The Section 15 scaffold closed early, leaving 15.7 outside it, and the stray closing fence then opened a block that swallowed the Locked 31 dispatch rule, the Section 16 heading, its instructions and its entire scaffold. Sixty-three fences in a file that can only be even. Section 16's contract had been arriving as a code sample.
27
+ - **Phase 3's staleness check could not fire.** Step 3 compared `state.run.lastAnalysisDigest` against the document front-matter, and nothing in the pipeline ever wrote that key; the state schema did not declare it either. Every run took the absent branch and reported fresh. Phase 1 now persists it, plus a `base_commit` anchor, and the schema declares both containers.
28
+ - **The template attributed the Files-to-Add tag rule to Locked 15** (new assets default to SVG). It is Locked 16; the schema already had it right.
29
+ - **`filesToAdd` was typed `["object", "null"]` under a description reading "Never null."** Now `object`, matching its own sentence and its presence in `required`.
30
+ - The variant-coverage check anchored on a heading numbered literally `6.X`, while Locked 2 requires numbering to re-flow. Renumber the section and the check stopped running, silently. It now keys on the heading text.
31
+ - "23 main sections + 3 footer" counted the footers twice, and Lite mode advertised "7 main + 1 footer" above a list of eight numbers. Corrected across seven surfaces, both languages.
32
+
33
+ ### Added
34
+
35
+ - **The dispatch gate enforces Locked 16, 24 and 31.** Untagged Files-to-Add rows, concept-table rows that state no evidence, and business rules with no Section 15 scenario are now errors rather than sentences. The traceability check previously warned when a `BR-` id appeared fewer than twice anywhere in the document; it now resolves the actual chain, from the rule's definition to a test that covers it.
36
+ - **Section 15 must exist in Full mode.** It is what Phase 3 reads as the RED input, so a document without it hands development an empty test matrix - and the gate used to accept that with exit 0. A rule defined with no unit sub-table fails too. The omission table allows exactly one exception, a backend-only run with no contract testing planned, and the validator knows the platform, so that case warns instead of blocking.
37
+ - **Section 3 diagrams are checked.** A rendered section with no mermaid block is an error; an absent section is a warning, because the template's omission condition (single screen, single service, simple rule) is real and a blanket requirement would be wrong. The 3.3 state-machine sub-section gained the trigger it never had.
38
+ - **The humanizer knows what language it is writing.** It was 135 lines of English AI-slop patterns with no notion of `outputLanguage`, applied to Turkish analysis documents that stakeholders read in Confluence. Turkish fails differently: nominalization chains, clauses piled up before a sentence-final verb, calqued English structure. Those are now named, with the diacritic rule moved beside them instead of living only in the caller's doc.
39
+ - **The three tones the pipeline passes are defined.** `technical-explanatory`, `formal-stakeholder` and `informal-technical` appeared at seven call sites across two refs and in none of the skill; all three silently collapsed to the same default, so the stakeholder page and the ticket comment came out identical. `smoke-humanizer-contract.sh` harvests the tone names from the call sites and fails when one has no definition.
40
+ - **Section 14's tag reaches development.** Phase 2 carries it onto the todo as `sourceTag`; Phase 3 binds the existing file on a `Reuse` step instead of writing a new one, and Phase 4 checks the diff against it. The analysis had already settled that decision and the implementer was re-making it.
41
+ - **Repo drift is detectable.** `base_commit` in the front-matter lets Phase 3 diff the repo against the commit the spec was written from. This is the case a digest cannot see: a reused document keeps a matching `evidence_digest` precisely because its evidence inputs did not change, while the code underneath it moved. Recomputing the digest would mean re-running Phase 1b and 1c, which is why the anchor is a commit.
42
+ - The analysis ref tree is measured: 132138 bytes across seven files, and nothing had ever put a number on the largest reference the pipeline ships. Unlike `rules/`, this loads once per analysis run rather than once per session, so the ceiling exists to make growth visible, not to force a cut.
43
+ - `smoke-validate-analysis-doc.sh` grew from 13 assertions to 26, every one planted-and-proven: the bad document is fed in and the error text matched, with a negative control wherever a check could pass by never firing.
44
+
45
+ ### Known
46
+
47
+ - **The template prescribes two shapes for the Section 13.1 concept table and does not say which wins.** The scaffold uses explicit `Confidence` and `Evidence` columns; the Pass B footnote grammar puts the same facts in a `^[key confidence: source]` suffix, and its examples reuse the scaffold's own row names. Both carry the evidence, so the Locked 24 check accepts either and fails only a row carrying neither. Choosing one shape is a design decision for a follow-up, not something a gate should settle by rejecting half the template.
48
+ - The state schema declares `additionalProperties: false` while the phase docs write about twenty roots it does not define (`dev`, `plan`, `analysisSpec`, `taskType`, `maturity` and others). This release adds the two it touches, `analysis` and `run`. Nothing validates a state instance against the schema today, so the drift is latent rather than active.
49
+
50
+ ### Changed
51
+
52
+ - **Locked 18 no longer claims a gate it cannot have.** URL-only Figma references in Section 5 are a review finding, not a validator error: whether an attachment upload succeeded is known at the Confluence dispatch step, not by reading the markdown.
53
+ - Phase doc aggregate 56350 -> 56600. The baseline had nine tokens of headroom, so no addition of any size could fit; compression came first and took the four new blocks from 380 tokens to 214.
54
+
55
+ ## [16.1.3] - 2026-08-23
56
+
57
+ A dead-code and stale-name sweep. No dead symbols: every function and constant added this week is called from somewhere. Five stale names and one lie.
58
+
59
+ ### Fixed
60
+
61
+ - **The uninstall preview described the wrong MCP entry, and claimed to remove one it now keeps.** The dry-run text named `dev-toolkit` - the pre-v15.12.0 name - and listed it as removed, while a current install registers `multi-agent-toolkit` and 16.1.0 made that one survive. The preview is the last thing a user reads before confirming a destructive action, so being wrong there is worse than being wrong in a comment. Both host lines now say which entry goes and which is kept, and that `lib/` keeps the credential reader.
62
+ - `refactor`'s research ref was still `dev-toolkit-research.md`, two releases after the server was renamed. Renamed to `toolkit-research.md` with both SKILL trees updated. The file was never dangling - just carrying a name that stopped being true.
63
+ - `docs/architecture.md` listed `dev-toolkit-mcp` as a sync target; the repo is `multi-agent-toolkit-mcp`. The plugins repo README and two site comments named the old server too.
64
+ - The MCP registration header still said "80 tools"; it serves 83.
65
+
66
+ ### Added
67
+
68
+ - **Both READMEs and `docs/features.md` describe what 16.1.0 actually shipped.** They had been checked for stale `--dev` references and found clean, which is not the same as being current: the release's headline capability - the install being usable in an ordinary session - appeared in none of them. Now it does, in English and Turkish, including the part that constrains it: reads are ordinary work, writes route through the pipeline commands that carry the rules making them safe.
69
+
19
70
  ## [16.1.2] - 2026-08-23
20
71
 
21
72
  The rule reached all three hosts in 16.1.1. It only WORKED on one.
package/README.md CHANGED
@@ -133,6 +133,16 @@ says so.
133
133
 
134
134
  The **secret scan** runs as a `PreToolUse` hook on Claude Code (hard-blocks a commit on a hit) and as a pre-push check elsewhere.
135
135
 
136
+ ## Outside a pipeline run
137
+
138
+ Installing the pipeline is not only useful when you run it. Open an ordinary session and the same three things are available, announced by `rules/outside-the-pipeline.md` which loads with every conversation:
139
+
140
+ - **Services you already onboarded.** The token `setup` mapped is readable now - resolve the logical name through `credential-store.sh` and fetch the issue, the page, the log. **Reads are ordinary work; writes are not.** Posting a Jira comment, editing an issue or opening a PR goes through the pipeline commands, because the rules that make those safe (never auto-close, `Ref:` not `Closes:`, humanizer on outward prose) live there.
141
+ - **The stack skills `/multi-agent:stack` enabled for the repo.** Each toolkit's own `index` skill routes; the pipeline keeps no copy of that table.
142
+ - **The `multi-agent-toolkit` MCP.** 83 tools for a running app - screen state, crash logs, design comparison, store pre-submission.
143
+
144
+ Uninstall preserves this layer: the tokens, the reader that opens them, the mapping that names them, and the MCP registration. Removing the pipeline should not cost you the credentials you onboarded through it.
145
+
136
146
  ## Platform support
137
147
 
138
148
  Runs on **macOS**, **Linux**, and **Windows** (Git Bash / WSL). Shell and credential access go through a platform-agnostic layer - the keychain resolves automatically to **macOS Keychain**, **Linux libsecret** (`secret-tool`), or **Windows Credential Manager**, and scripts fall back between BSD and GNU tool variants. Node.js 20.11+ (tested on 20 and 22).
package/README.tr.md CHANGED
@@ -133,6 +133,16 @@ triage notu bunu belirtir.
133
133
 
134
134
  **Secret scan**, Claude Code'da bir `PreToolUse` hook'u olarak (bulgu halinde commit'i sert-engeller) ve diğer yerlerde bir pre-push kontrolü olarak çalışır.
135
135
 
136
+ ## Pipeline koşusu dışında
137
+
138
+ Pipeline'ı kurmak yalnız onu çalıştırdığında işe yaramıyor. Sıradan bir oturum açtığında aynı üç şey elinin altında; her sohbette yüklenen `rules/outside-the-pipeline.md` bunları duyuruyor:
139
+
140
+ - **Zaten onboard ettiğin servisler.** `setup`'ın eşlediği token okunabilir durumda - mantıksal adı `credential-store.sh` ile çöz, issue'yu, sayfayı, logu getir. **Okuma sıradan iş, yazma değil.** Jira yorumu, issue düzenleme ve PR açma pipeline komutlarından geçer, çünkü onları güvenli kılan kurallar (issue asla otomatik kapanmaz, `Closes:` değil `Ref:`, dışa dönük metinde humanizer) orada yaşıyor.
141
+ - **`/multi-agent:stack`'in bu repo için açtığı stack skilleri.** Yönlendirmeyi her toolkit'in kendi `index` skill'i yapar; pipeline o tablonun kopyasını tutmaz.
142
+ - **`multi-agent-toolkit` MCP.** Çalışan uygulama için 83 araç - ekran durumu, crash logu, tasarım karşılaştırma, store ön-kontrolü.
143
+
144
+ Uninstall bu katmanı korur: token'lar, onları açan okuyucu, adlarını tutan eşleme ve MCP kaydı. Pipeline'ı kaldırmak, onun üzerinden onboard ettiğin credential'ları kaybetmek anlamına gelmemeli.
145
+
136
146
  ## Platform desteği
137
147
 
138
148
  **macOS**, **Linux** ve **Windows** (Git Bash / WSL) üzerinde çalışır. Shell ve credential erişimi platform-agnostik bir katmandan geçer - keychain otomatik olarak **macOS Keychain**, **Linux libsecret** (`secret-tool`) veya **Windows Credential Manager**'a çözülür, ve script'ler BSD ile GNU araç varyantları arasında fallback yapar. Node.js 20.11+ (20 ve 22'de test edildi).
@@ -164,7 +164,7 @@ User Input → Phase 0 (Init)
164
164
 
165
165
  `/multi-agent:sync` actually walks **five** targets, not the three shown in earlier
166
166
  revisions of this diagram - Codex CLI and the two independently-shipped repos
167
- (`multi-agent-plugins`, `dev-toolkit-mcp`) are real sync targets too:
167
+ (`multi-agent-plugins`, `multi-agent-toolkit-mcp`) are real sync targets too:
168
168
 
169
169
  ```mermaid
170
170
  graph TD
package/docs/features.md CHANGED
@@ -30,6 +30,16 @@ Each phase reads its own spec file under `pipeline/multi-agent-refs/phases/phase
30
30
 
31
31
  Depth is not a flag. `/multi-agent` and `/multi-agent:local` ask Full or Short at Phase 0 Step 7.5, recommending from the detected `taskType`; Short strips to Init → Dev(Opus self-contained) → Review → Test → Commit → Report. Autopilot never asks and always runs Full - "fast plus unattended" was removed in v16.0.0, because something has to choose when nobody is asked and unattended is the worst place to drop analysis and planning.
32
32
 
33
+ ### Outside a Pipeline Run
34
+
35
+ The install is not only useful while `/multi-agent` is running. `rules/outside-the-pipeline.md` loads with every session and announces three things a plain conversation would otherwise not know it had:
36
+
37
+ - **Onboarded service credentials.** Resolve the logical name through `credential-store.sh` and read the issue, page or log. Writes route through the pipeline commands, which carry the rules that make them safe - issues are never auto-closed, PR bodies use `Ref:`, outward prose goes through the humanizer.
38
+ - **The stack skills enabled for this repo.** Each toolkit's own `index` skill routes. The pipeline reads the effective `enabledPlugins` rather than keeping a stack table, so a seventh toolkit needs no code change.
39
+ - **The `multi-agent-toolkit` MCP.** 83 tools for a running app.
40
+
41
+ Uninstall preserves the whole layer - tokens, the reader that opens them, the mapping that names them, the MCP registration. It is 1.5 kB of always-loaded text; the detail lives in a ref that loads on demand, and a gate keeps both under a ceiling because every byte there is paid by every session.
42
+
33
43
  ### Stack Auto-Detection
34
44
 
35
45
  | Platform | Detection | Guide Loaded |
@@ -5,7 +5,7 @@
5
5
  *
6
6
  * Codex got MCP registration when its installer was written; Copilot never did, and
7
7
  * neither did Claude Code. The result was a host that carried the full pipeline skill
8
- * set and could not call a single one of the 80 dev-toolkit tools those skills depend
8
+ * set and could not call a single one of the 83 toolkit tools those skills depend
9
9
  * on - `design-check`, every `ios_*` / `android_*` simulator call, the archive audits.
10
10
  * Nothing failed at install time, and the skills only fail when a run actually reaches
11
11
  * for a tool.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mmerterden/multi-agent-pipeline",
3
- "version": "16.1.2",
3
+ "version": "16.2.0",
4
4
  "description": "8-phase AI development pipeline with full orchestration on Claude Code, Copilot CLI and Codex CLI. Analysis, planning, TDD, CLI-aware parallel review with consensus surfacing + Fable triage, default-FAIL evidence gates, secret + intent guards, per-phase cost ledger, persistent learnings memory, wiki generation, commit automation. Token-preserving uninstall.",
5
5
  "type": "module",
6
6
  "main": "index.js",
@@ -1,6 +1,6 @@
1
1
  ---
2
- description: "Standalone feature-spec analysis. Platform-agnostic concept layer with repo-driven convention extraction (Phase 1c) and per-platform Pass B render. 23 main sections + 3 footer in Full mode; 7 sections in Lite mode (auto for small features). Collects Figma / Swagger / Confluence / Jira / Standards (Confluence + Wiki + local file) / Firebase / repo inputs. Stops after emit - does not chain into a dev run. Use when a feature needs a written specification before any code, from Figma, Swagger, Confluence, Jira or repo inputs."
3
- description-tr: "Bağımsız özellik-spesifikasyonu analizi. Repo'dan konvansiyon çıkarımıyla (Faz 1c) platform-bağımsız kavram katmanı ve platform başına Pass B render. Full modda 23 ana + 3 dipnot bölümü; Lite modda 7 bölüm (küçük işlerde otomatik). Figma / Swagger / Confluence / Jira / Standartlar (Confluence + Wiki + yerel dosya) / Firebase / repo girdilerini toplar. Çıktıyı üretince durur - dev koşusuna zincirlenmez."
2
+ description: "Standalone feature-spec analysis. Platform-agnostic concept layer with repo-driven convention extraction (Phase 1c) and per-platform Pass B render. 23 sections in Full mode; 8 of them in Lite mode (auto for small features). Collects Figma / Swagger / Confluence / Jira / Standards (Confluence + Wiki + local file) / Firebase / repo inputs. Stops after emit - does not chain into a dev run. Use when a feature needs a written specification before any code, from Figma, Swagger, Confluence, Jira or repo inputs."
3
+ description-tr: "Bağımsız özellik-spesifikasyonu analizi. Repo'dan konvansiyon çıkarımıyla (Faz 1c) platform-bağımsız kavram katmanı ve platform başına Pass B render. Full modda 23 bölüm; Lite modda bunlardan 8'i (küçük işlerde otomatik). Figma / Swagger / Confluence / Jira / Standartlar (Confluence + Wiki + yerel dosya) / Firebase / repo girdilerini toplar. Çıktıyı üretince durur - dev koşusuna zincirlenmez."
4
4
  argument-hint: "[\"<analysis-name>\"] [--lite | --full] [--no-cache] [--preview-conventions]"
5
5
  ---
6
6
 
@@ -104,7 +104,7 @@ When `phase == "cancelled_at_pass_b_preview"`:
104
104
  | `$HOME/.claude/multi-agent-refs/channels/confluence.md` | Phase 4 Confluence dispatch |
105
105
  | `$HOME/.claude/multi-agent-refs/channels/jira.md` | Phase 4 Jira dispatch |
106
106
  | `$HOME/.claude/rules/tdd.md` | Section 15 test naming |
107
- | `$HOME/.claude/multi-agent-refs/analysis-template.md` | Template master copy + language matrix (v3 - 23 main sections + 3 footer) |
107
+ | `$HOME/.claude/multi-agent-refs/analysis-template.md` | Template master copy + language matrix (v3 - 23 sections) |
108
108
  | `$HOME/.claude/multi-agent-refs/conventions-defaults.md` | Pass B fallback defaults (4 platforms x 7 pattern groups) - applied when convention confidence is none AND standards binding is silent |
109
109
  | `$HOME/.claude/scripts/validate-analysis-doc.mjs` | Phase 4 pre-dispatch gate: deterministic check of the emitted per-platform doc (front-matter, never-omitted sections, humanizer punctuation, Full-mode BR traceability) |
110
110
  | a project-supplied Confluence-embedded API-table parser (optional) | Parse endpoints from a Confluence page's Request Path / Service Name / Response Body table columns |
@@ -112,7 +112,7 @@ Procedure:
112
112
 
113
113
  The pipeline's hands on devices and browsers are MCP tools served by a companion repo (`multi-agent-toolkit-mcp`): Phase 5 test, `manual-test`, `design-check` and `apple-archive-compliance` all call them, and several pipeline skills declare a minimum toolkit version (see `cross-cli-contract.md`). That repo therefore has to track the MCP field, not just its own README. This step researches what current practice is and audits the toolkit against it.
114
114
 
115
- Full procedure - resolution (configuration first, never a hardcoded path; skip when nothing resolves or `enabled` is false), the 5 research axes, the audit command block, and the band-E output table + rules - lives in `$HOME/.claude/multi-agent-refs/refactor/dev-toolkit-research.md`. Read it before running this step.
115
+ Full procedure - resolution (configuration first, never a hardcoded path; skip when nothing resolves or `enabled` is false), the 5 research axes, the audit command block, and the band-E output table + rules - lives in `$HOME/.claude/multi-agent-refs/refactor/toolkit-research.md`. Read it before running this step.
116
116
 
117
117
  ## Step 0d: RUN-ERRORS - what the pipeline actually failed on
118
118
 
@@ -35,7 +35,7 @@ When citing a Locked decision in code or docs, prefer `Locked <n> (<short label>
35
35
  15. **New assets default to SVG.** Section 8 entries marked `new` are SVG unless a documented exception is captured in the rationale column (Lottie for motion design, optimized PNG for raster-only icons). PDF, JPG, and unoptimized PNG are rejected.
36
36
  16. **Files-to-Add tag mandatory.** Every row in Section 14 carries one tag from `Reuse | Add new | Modify`. Untagged rows fail the dispatch gate.
37
37
  17. **API response variants exhaustive.** Section 9 lists every HTTP status code returned by the endpoint with at least one example body and the matching UI outcome. Phrases like "other errors" or "various 4xx" are rejected.
38
- 18. **Screenshots embedded, not linked.** Section 5 frame galleries reference local PNG files. Dispatch uploads them as Confluence multipart attachments and injects `<ac:image><ri:attachment ri:filename="..." /></ac:image>` into the page body. URL-only Figma references in Section 5 fail the dispatch gate.
38
+ 18. **Screenshots embedded, not linked.** Section 5 frame galleries reference local PNG files. Dispatch uploads them as Confluence multipart attachments and injects `<ac:image><ri:attachment ri:filename="..." /></ac:image>` into the page body. URL-only Figma references in Section 5 are a review finding, not a validator ERROR: the check belongs to the Confluence dispatch step, which is the only place that knows whether an attachment upload succeeded.
39
39
  19. **All Figma variants drilled.** When a Figma section URL is supplied, all child frames are drilled, not just the canonical default. The renderer enumerates child frames via `mcp__claude_ai_Figma__get_metadata` (Tier 1) or `figma-screenshot.sh --section` (Tier 2) and produces one Section 5.1 row per child frame.
40
40
  20. **Localization mode (ownership-aware).** Section 10's shape is driven by the project `figma-config` `localization.ownership` (default `in-repo`). The locale set comes from `localization.locales` (default `tr, en, ar, de, es, fr, it, ru`); do not hardcode a locale list in the render.
41
41
  - **`in-repo`** (default, historical behavior): new keys carry filled cells for every configured locale. Placeholder values `[bekleniyor: çeviri ekibi]` / `[pending: translation team]` are a soft state and the dispatch report flags `i18n_pending: <count>` as a blocker. Empty cells are rejected outright.
@@ -17,7 +17,7 @@
17
17
  content: <markdown>
18
18
  ```
19
19
 
20
- **Explicit punctuation policy** (enforced by `stripFancyPunctuation: true`): no em-dash (U+2014), no en-dash (U+2013), no horizontal ellipsis (U+2026), no curly quotes (U+2018, U+2019, U+201C, U+201D), no section sign (U+00A7). The humanizer replaces these with ASCII equivalents (`-`, `:`, `,`, `...`, `'`, `"`, and `bölüm` / `section` for the section sign per `outputLanguage`) before emit. Tables, code blocks, URLs, and front-matter YAML are exempt. Post-emit verification runs through `node $HOME/.claude/scripts/validate-analysis-doc.mjs <file>`, which checks this policy deterministically in Node on all three operating systems. Do NOT verify with `grep -P`: BSD grep (macOS, the pipeline's primary platform) has no `-P`, so that command never runs and "zero matches" is trivially true. **Diacritics are PRESERVED, not stripped: this policy targets ONLY the listed fancy-punctuation codepoints. Turkish letters (ş/Ş, ç/Ç, ğ/Ğ, ı/I, İ, ö/Ö, ü/Ü) and all other `outputLanguage` letters MUST stay verbatim. Never ASCII-fold the prose - emit `Geliştirme Özeti`, `için`, `Kullanıcı Hikayeleri`, NOT `Gelistirme Ozeti`, `icin`, `Kullanici`. ASCII-folded Turkish is a humanizer-skipped smell and fails review.**
20
+ **Explicit punctuation policy** (enforced by `stripFancyPunctuation: true`): no em-dash (U+2014), no en-dash (U+2013), no horizontal ellipsis (U+2026), no curly quotes (U+2018, U+2019, U+201C, U+201D), no section sign (U+00A7). The humanizer replaces these with ASCII equivalents (`-`, `:`, `,`, `...`, `'`, `"`, and `bölüm` / `section` for the section sign per `outputLanguage`) before emit. Tables, code blocks, URLs, and front-matter YAML are exempt. Post-emit verification runs through `node $HOME/.claude/scripts/validate-analysis-doc.mjs <file>`, which checks this policy deterministically in Node on all three operating systems. Do NOT verify with `grep -P`: BSD grep (macOS, the pipeline's primary platform) has no `-P`, so that command never runs and "zero matches" is trivially true. The per-language readability rules (Turkish sentence shape, nominalization chains, which terms stay untranslated) live in the humanizer skill itself, not here; this paragraph owns only the punctuation policy the validator enforces. **Diacritics are PRESERVED, not stripped: this policy targets ONLY the listed fancy-punctuation codepoints. Turkish letters (ş/Ş, ç/Ç, ğ/Ğ, ı/I, İ, ö/Ö, ü/Ü) and all other `outputLanguage` letters MUST stay verbatim. Never ASCII-fold the prose - emit `Geliştirme Özeti`, `için`, `Kullanıcı Hikayeleri`, NOT `Gelistirme Ozeti`, `icin`, `Kullanici`. ASCII-folded Turkish is a humanizer-skipped smell and fails review.**
21
21
 
22
22
  4. **Write scratch drafts**: create `/tmp/analysis-<feature-slug>-<UTC-iso8601>/` and write `<feature>-<platform>.md` for each selected platform. Update `state.analysisSpec.outputs.draftDir` with the path.
23
23
 
@@ -1,8 +1,8 @@
1
1
  ---
2
- description: "v3 canonical template for /multi-agent:analysis. 23 main sections + 3 footer sections. Platform-agnostic concept layer (Pass A) projected per-platform with repo-driven naming (Pass B). Includes Lite mode for small features."
2
+ description: "v3 canonical template for /multi-agent:analysis. 23 sections. Platform-agnostic concept layer (Pass A) projected per-platform with repo-driven naming (Pass B). Includes Lite mode for small features."
3
3
  ---
4
4
 
5
- # Analysis Template v3 - 23 Main Sections + 3 Footer
5
+ # Analysis Template v3 - 23 Sections
6
6
 
7
7
  `/multi-agent:analysis` renders every output against this template. Document language follows `prefs.global.outputLanguage` (`tr` or `en`). Tables use pipe-syntax markdown; the Confluence channel (`md2confluence-v3.py`) converts them to storage XML at emit time, embeds attachment images, and runs the humanizer punctuation gate before write.
8
8
 
@@ -18,8 +18,8 @@ The renderer picks Full or Lite mode automatically based on signals captured in
18
18
 
19
19
  | Mode | Sections | When |
20
20
  |---|---|---|
21
- | Full | 23 main + 3 footer | Default. Used when feature has multi-screen flow, external service contracts, or complex business rules. |
22
- | Lite | 7 main + 1 footer: 1, 2, 4, 9, 13, 14, 21, 23 | Used when (a) Confluence spec < 100 lines AND (b) Figma frames <= 1 AND (c) repo evidence direct-match >= 8. Manual override: user passes `--lite`. |
21
+ | Full | all 23 | Default. Used when feature has multi-screen flow, external service contracts, or complex business rules. |
22
+ | Lite | 8 of 23: 1, 2, 4, 9, 13, 14, 21, 23 | Used when (a) Confluence spec < 100 lines AND (b) Figma frames <= 1 AND (c) repo evidence direct-match >= 8. Manual override: user passes `--lite`. |
23
23
 
24
24
  Lite mode sections retain the same scaffold as Full mode; only the section set is reduced.
25
25
 
@@ -56,13 +56,14 @@ siblings:
56
56
  standards:
57
57
  - <absolute path or confluence:title or github-wiki:slug>
58
58
  evidence_digest: sha256:<digest>
59
+ base_commit: <git rev-parse HEAD at emit time>
59
60
  template_version: v3
60
61
  ---
61
62
  ```
62
63
 
63
64
  `ui_tests` and `a11y_depth` record the Phase 0 Step 5a opt-ins (defaults `false` / `basic`) so the coverage choice is auditable and the pre-dispatch validator can enforce it: `ui_tests: true` requires Section 15.6, `a11y_depth: full` requires the Section 16.2 walkthrough.
64
65
 
65
- The dev pipeline (`/multi-agent`, either depth) reads `platform` to verify file match, `evidence_digest` to detect stale specs, and `mode` to know which section set to expect.
66
+ Phase 1 compares `evidence_digest` against an existing document to decide whether to reuse it (Locked 27). Phase 3 reads `platform` to verify file match, `mode` to know which section set to expect, and both `evidence_digest` and `base_commit` to judge freshness: the digest says the evidence changed, `base_commit` says the repo moved. Phase 2 parses the block but gates only on `template_version`.
66
67
 
67
68
  ## Layer headings (A / B / C)
68
69
 
@@ -167,7 +168,7 @@ Each non-goal must say what it does NOT cover, not a vague "out of scope" (AI ca
167
168
 
168
169
  ## 3. Akış Diyagramı / Flow Chart
169
170
 
170
- Mermaid diagram(s). At least one is mandatory unless omission conditions hold (single screen + single service + simple rule).
171
+ Mermaid diagram(s). At least one is required unless the omission conditions hold (single screen AND single service AND simple business rule). 3.1 covers navigation, 3.2 covers service ordering, 3.3 covers state. Render each one whose subject the feature actually has; a rendered section with no mermaid block fails the dispatch gate.
171
172
 
172
173
  ```markdown
173
174
  ## 3. Akış Diyagramı <!-- TR -->
@@ -202,7 +203,9 @@ sequenceDiagram
202
203
  A->>U: rendered
203
204
  \`\`\`
204
205
 
205
- ### 3.3 Durum Makinesi / State Machine (optional)
206
+ ### 3.3 Durum Makinesi / State Machine (conditional)
207
+
208
+ Render when the screen holds more than one observable state (loading / loaded / empty / error, a multi-step form, or a retry path). A screen with a single state omits 3.3. Omitting it while state transitions exist is the same defect as omitting Section 3 entirely.
206
209
 
207
210
  \`\`\`mermaid
208
211
  stateDiagram-v2
@@ -704,7 +707,7 @@ Decisions cite their binding source (Locked 8):
704
707
 
705
708
  ## 14. Eklenecek Dosyalar / Files to Add
706
709
 
707
- Never omitted. Locked 15 - every row carries Reuse / Add new / Modify tag.
710
+ Never omitted. Locked 16 - every row carries Reuse / Add new / Modify tag.
708
711
 
709
712
  ```markdown
710
713
  ## 14. Eklenecek Dosyalar <!-- TR -->
@@ -785,7 +788,6 @@ Rendered when `state.analysisSpec.options.uiTests == true`. That option now **de
785
788
  | UI-<slug>-01 | <high-risk reason> | <ordered user actions> | <accessibilityIdentifier / testTag> | <visible state / navigation / error> | <seeded data / launch args / mocked network> | BR-<slug>-NN |
786
789
 
787
790
  Framework: iOS XCUITest (`waitForExistence`, identifier-driven); Android Compose UI test (`createComposeRule`, `onNodeWithTag`) or Espresso for View-based screens.
788
- ```
789
791
 
790
792
  ### 15.7 Manuel test senaryoları / Manual test scenarios
791
793
 
@@ -179,7 +179,7 @@ A fresh document is also skipped when one already exists for this feature and pl
179
179
 
180
180
  **How it runs.** Load `$HOME/.claude/multi-agent-refs/analysis/` on demand, in order: `locked.md` (the 31 binding decisions) then `evidence.md`, `synthesis.md`, `render.md`. Intake is NOT re-asked; platform, repos and account come from Phase 0 state. Autopilot auto-approves the Phase 2a convention preview and writes the local file, because it may not ask.
181
181
 
182
- **Where it lands.** `<worktree>/analysis/<feature-slug>-<platform>.md`, one file per platform in `state.analysisSpec.platforms[]`. Persist the paths to `state.analysis.docPath[]` and set `docStatus` to `produced` | `reused` | `not-applicable`. Whether the file is committed with the work is `prefs.global.analysisPhase.commitDoc` (default `true`), read at Phase 6.
182
+ **Where it lands.** `<worktree>/analysis/<feature-slug>-<platform>.md`, one file per platform in `state.analysisSpec.platforms[]`. Persist the paths to `state.analysis.docPath[]` and set `docStatus` to `produced` | `reused` | `not-applicable`. Also persist `state.run.lastAnalysisDigest` (this document's `evidence_digest`) and `state.run.analysisBaseCommit` (`git rev-parse HEAD`). Phase 3's freshness check reads both; unwritten, it has nothing to compare and passes silently. Whether the file is committed with the work is `prefs.global.analysisPhase.commitDoc` (default `true`), read at Phase 6.
183
183
 
184
184
  **The gate is not optional.** `node $HOME/.claude/scripts/validate-analysis-doc.mjs <file>` must exit 0 for every produced file; non-zero fails CLOSED like the JSON validator below (rework once, then halt).
185
185
 
@@ -20,7 +20,7 @@ Phase 2 Planning consumes the analysis document. MCP forbidden.
20
20
  - Section 1 Summary, Section 2 Goals + Non-Goals, Section 4 User Stories, Section 9 API Contracts, Section 13 Architecture Plan, Section 14 Files to Add, Section 20 Risks, Section 21 References
21
21
  - Missing -> WARN, plan is allowed to proceed but Phase 4 reviewer flags it.
22
22
 
23
- 4. **Convert analysis tasks to plan**: Section 14 Files-to-Add becomes the seed task list. Apply Reuse / Add new / Modify tags from the inventory column.
23
+ 4. **Convert analysis tasks to plan**: Section 14 Files-to-Add becomes the seed task list. Carry each row's tag onto its todo as `sourceTag` (`Reuse` | `Add new` | `Modify`); it is an instruction Phase 3 follows and Phase 4 checks, not a label.
24
24
 
25
25
  5. **MCP forbidden**: same rule as Phase 3.
26
26
 
@@ -17,7 +17,9 @@ Pre-flight steps (run in order, abort on failure).
17
17
 
18
18
  2. **Parse YAML front-matter** into `state.analysis.frontMatter`: `feature`, `platform`, `language`, `mode`, `evidence_digest`, `template_version`. **Abort** when `template_version` < `v3`; there is no degraded mode.
19
19
 
20
- 3. **Evidence digest match (cache validation)**: if `state.run.lastAnalysisDigest` is present AND matches `frontMatter.evidence_digest`, mark as fresh; otherwise WARN that analysis is stale (continue but flag).
20
+ 3. **Spec freshness**: two checks, both non-blocking, both flagged for Phase 4.
21
+ - **Digest**: `state.run.lastAnalysisDigest` against `frontMatter.evidence_digest`. Mismatch = written from different evidence. Key absent -> `not-verifiable`, never `fresh`.
22
+ - **Repo drift**: `git diff --name-only <state.run.analysisBaseCommit>..HEAD` intersected with Section 14 paths. Non-empty = the repo moved under the spec. This is the one that fires on a `reused` doc, where the digest still matches because the evidence inputs did not change.
21
23
 
22
24
  4. **Code Connect mapping lookup**: for each component named in analysis Section 6 (Bileşen Envanteri), search the repo for matching `*.figma.swift` / `*.figma.kt` files. Persist hits to `state.dev.codeConnect[<componentName>]`. Missing mappings are not blockers but the Phase 4 reviewer will flag them.
23
25
 
@@ -49,7 +51,7 @@ The analysis document is the SOLE design source in Phase 3. Variant choices, pad
49
51
 
50
52
  Phase 3 consumes the Phase 2 output object conforming to `$HOME/.claude/schemas/planning-output.schema.json` - the task graph (`tasks[]` with `id`, `subject`, `targetFiles`, `complexity`, `blockedBy`) plus the architecture review notes. Tasks execute in dependency order; the schema's `blockedBy` field drives the ready-task picker. In a Short run (no Phase 2), Opus generates the equivalent task list inline before entering the loop below.
51
53
 
52
- **Plan Todo iteration (opt-in)**: gated by `prefs.global.planTodos.enabled` (default: `false`). When enabled and Phase 2 Step 4.5 emitted a `plan.todos[]`, Phase 3 iterates via `$HOME/.claude/lib/plan-todos.sh next/start/complete/fail` instead of walking `tasks[]` directly. When disabled, the loop walks `tasks[]` from `planning-output` - TDD contract is unchanged. Full helper loop + state semantics: `$HOME/.claude/multi-agent-refs/features/plan-todos.md`.
54
+ **Plan Todo iteration (opt-in)**: gated by `prefs.global.planTodos.enabled` (default: `false`). When enabled and Phase 2 Step 4.5 emitted a `plan.todos[]`, Phase 3 iterates via `$HOME/.claude/lib/plan-todos.sh next/start/complete/fail` instead of walking `tasks[]` directly. When disabled, the loop walks `tasks[]` from `planning-output` - TDD contract is unchanged. Full helper loop + state semantics: `$HOME/.claude/multi-agent-refs/features/plan-todos.md`. A todo with `sourceTag: Reuse` binds the file analysis already found; `Modify` edits in place. Writing a new file over a `Reuse` step is a Locked 11 violation and Phase 4 flags it.
53
55
 
54
56
  **Shadow-Git checkpoints (opt-in)**: gated by `prefs.global.shadowGit.enabled` (default: `false`). When enabled, the orchestrator snapshots the worktree via `$HOME/.claude/lib/shadow-git.sh` so sub-phase rollback is possible without touching the project's real `.git` history. Lifecycle: `shadow-git.sh init` (Phase 0 baseline), `shadow-git.sh snapshot` (per step after `plan-todos complete`), `shadow-git.sh restore <sha> --files` (rollback). Modes: `per-todo-step` (default) or `per-tool-call`. Full wiring + storage cap: `$HOME/.claude/multi-agent-refs/features/shadow-git.md`.
55
57
 
@@ -195,6 +195,43 @@
195
195
  "type": ["string", "null"],
196
196
  "description": "Pipeline mode for this run (e.g. 'dev', 'local', 'design-check'). Absent = full pipeline."
197
197
  },
198
+ "analysis": {
199
+ "type": ["object", "null"],
200
+ "additionalProperties": true,
201
+ "description": "Phase 1 analysis-document outcome. Absent in Short runs, which produce no document by design.",
202
+ "properties": {
203
+ "docStatus": {
204
+ "type": "string",
205
+ "enum": ["produced", "reused", "not-applicable"],
206
+ "description": "Set by Phase 1 Step 4. Phase 2 and Phase 3 pre-flight on it."
207
+ },
208
+ "docPath": {
209
+ "type": "array",
210
+ "items": { "type": "string" },
211
+ "description": "One emitted path per selected platform."
212
+ },
213
+ "frontMatter": {
214
+ "type": ["object", "null"],
215
+ "additionalProperties": true,
216
+ "description": "Parsed YAML header of the active platform's document."
217
+ }
218
+ }
219
+ },
220
+ "run": {
221
+ "type": ["object", "null"],
222
+ "additionalProperties": true,
223
+ "description": "Cross-phase run bookkeeping that is not a phase record.",
224
+ "properties": {
225
+ "lastAnalysisDigest": {
226
+ "type": ["string", "null"],
227
+ "description": "The evidence_digest the analysis documents were written from, persisted by Phase 1. Phase 3 compares it against the document front-matter; absent means the freshness check is not-verifiable, never fresh."
228
+ },
229
+ "analysisBaseCommit": {
230
+ "type": ["string", "null"],
231
+ "description": "git rev-parse HEAD at analysis emit time. Phase 3 diffs it against HEAD to detect repo drift under a reused spec, which the digest alone cannot see."
232
+ }
233
+ }
234
+ },
198
235
  "figmaAccess": {
199
236
  "type": ["object", "null"],
200
237
  "additionalProperties": true,
@@ -3,7 +3,7 @@
3
3
  "$id": "https://github.com/{owner}/multi-agent-pipeline/pipeline/schemas/analysis-spec.schema.json",
4
4
  "version": "1.2.0",
5
5
  "title": "Multi-Agent Pipeline - /multi-agent:analysis spec output (v3 template)",
6
- "description": "Contract for the feature-spec analysis document generated by /multi-agent:analysis. Platform-agnostic concept layer + Pass B per-platform render with repo-driven conventions. 23 main sections + 3 footer in Full mode; 7 sections in Lite mode. Sections may be absent - omission is the policy when no evidence exists.",
6
+ "description": "Contract for the feature-spec analysis document generated by /multi-agent:analysis. Platform-agnostic concept layer + Pass B per-platform render with repo-driven conventions. 23 sections in Full mode; 8 of them in Lite mode. Sections may be absent - omission is the policy when no evidence exists.",
7
7
  "type": "object",
8
8
  "additionalProperties": false,
9
9
  "required": ["featureName", "language", "platforms", "repos", "evidence", "sections"],
@@ -36,7 +36,7 @@
36
36
  "type": "string",
37
37
  "enum": ["full", "lite"],
38
38
  "default": "full",
39
- "description": "Output mode. Full renders 23 main sections + 3 footer. Lite renders 1, 2, 4, 9, 13, 14, 21 + optional 23. Auto-resolved when both --lite and --full flags are absent."
39
+ "description": "Output mode. Full renders 23 sections. Lite renders 1, 2, 4, 9, 13, 14, 21 + optional 23. Auto-resolved when both --lite and --full flags are absent."
40
40
  },
41
41
  "liteModeAuto": {
42
42
  "type": "boolean",
@@ -587,7 +587,7 @@
587
587
  "sections": {
588
588
  "type": "object",
589
589
  "additionalProperties": false,
590
- "description": "v3 template - 23 main sections + 3 footer. Each section is either filled (object) or omitted (null). Omitted sections do not appear in the output document. Sections 1, 2, 4, 9, 13, 14, 20, 21 are never omitted (Locked 2).",
590
+ "description": "v3 template - 23 sections. Each section is either filled (object) or omitted (null). Omitted sections do not appear in the output document. Sections 1, 2, 4, 9, 13, 14, 20, 21 are never omitted (Locked 2).",
591
591
  "properties": {
592
592
  "summary": {
593
593
  "type": ["object", "null"],
@@ -639,7 +639,7 @@
639
639
  "description": "Section 13 - Mimari Plan. Never null. Concept table filled by Pass B (Locked 22 + 24)."
640
640
  },
641
641
  "filesToAdd": {
642
- "type": ["object", "null"],
642
+ "type": "object",
643
643
  "description": "Section 14 - Eklenecek Dosyalar. Never null. Every row carries Reuse / Add new / Modify tag (Locked 16)."
644
644
  },
645
645
  "testPlan": { "type": ["object", "null"], "description": "Section 15 - Test Planı." },
@@ -53,6 +53,11 @@
53
53
  },
54
54
  "failureReason": { "type": "string" },
55
55
  "skipReason": { "type": "string" },
56
+ "sourceTag": {
57
+ "type": "string",
58
+ "enum": ["Reuse", "Add new", "Modify"],
59
+ "description": "Carried from the analysis Section 14 row this step came from (Locked 16). Phase 3 reads it as an instruction: a Reuse step binds the existing file and must not write a new one. Phase 4 checks the diff against it. Absent when the step did not originate from a Files-to-Add row."
60
+ },
56
61
  "estimatedMinutes": {
57
62
  "type": "integer",
58
63
  "minimum": 1,
@@ -36,6 +36,6 @@
36
36
  "warn_tokens": 5600
37
37
  }
38
38
  },
39
- "total_max_tokens": 56350,
40
- "note": "Token estimate = ceil(chars / 4). Per-phase budget rule: warn = current+10% (rounded to nearest 50), max = current+25%. Gives ~6 edit cycles of headroom before warn trips - intentionally quiet under normal maintenance, loud when a phase grows unusually. Only the active phase is loaded (lazy). Recalibrated at v10.0.0 after the validator/consistency/simplifier/lesson gate contracts landed in phases 1-4. Recalibrated again at v10.9.0 after the verify-by-test (Phase 4 Step 3.7), update-check (Phase 0 Step 0.6), immutable-test (Phase 3 GREEN) and redTests re-entry contracts landed - Step 3.7 prose was compressed to a pointer into refs/features/verify-by-test.md before the recalibration. Total bumped 50000 -> 51000 at v12.5.0 after the worktree residue/traversal-prune contract (Phase 0 + Phase 5 heal) and the Reflexion causal-diagnosis contract (Phase 4 lesson memory) landed; the prose was compressed first (161 tokens reclaimed) and every per-phase max still passes - only the aggregate needed room. Recalibrated again at v13.6.0 after the install-relative path correction: an instruction that names `pipeline/scripts/x` resolves only from a repo checkout, and a run happens in the user's worktree, so 157 references across these docs moved to `$HOME/.claude/...` at +5 bytes each - 196 tokens of pure correctness cost. Same discipline as before: prose was compressed FIRST (149 tokens reclaimed, by pointing Phase 1's Figma tier table at the Phase 0 probe that already resolved it and Phase 4's Codex constraints at the always-loaded AGENTS.md block), and only then were the budgets moved. Five warn lines had been permanently amber, which makes the amber tier useless as a signal, so every warn was reset to the documented current+10% and the four maxes that the new warn would have collided with were reset to current+25%. Aggregate 51000 -> 51500. Total bumped 51500 -> 52200 at v14.0.0 after Phase 4 Review entered the four --dev mode phase sets and the criteria-resolution contract (Step 1.78) landed. Same discipline as every prior bump: prose was compressed FIRST, 820 tokens reclaimed, before the number moved. Two of those compressions are structural rather than cosmetic - the hardcoded SwiftUI interaction list in Step 1.5 and the SwiftUI convention paragraph in Step 2.8 were transcriptions of rules that now live in a scoped registry, so keeping them here would have re-created the drift this release exists to remove, and the third moved the Step 1.78 full contract into refs/features/skill-conformance.md leaving a pointer. What remains is contract text that cannot be inferred: the manifest's four consumer-visible parts, the conformance checklist the reviewers must return, and the fail-closed semantics. Every per-phase max still passes (phase-4 12405/14750); only the aggregate needed room. Total bumped 52200 -> 52700 at v14.1.0 after two more contracts landed: stack skill routing (Phase 3 pre-flight step 9) and worktree finalize (Phase 6 step 9). Compression came first, as always, and twice: 224 tokens out of Phase 3 by pointing its criteria-ledger and routing steps at their feature files instead of restating them, and 190 out of Phase 6 by moving the finalize contract into refs/features/worktree-finalize.md and leaving the invocation plus the exit-3 semantics. Both new contracts follow the pattern the earlier ones set: the phase doc carries the call and the decision, the feature file carries the reasoning, and the feature files are outside this budget because it loops only the eight phase-N-* keys. Every per-phase max still passes (phase-3 7677/8950, phase-6 5223/6150 and both under warn); only the aggregate needed room. Total bumped 52700 -> 52750 for the Phase 0 Step 3 branch-persistence correction: the step wrote the legacy `projects[].branches` while the TTL filter two sections below read `global.recentBranches`, and both spots named a `{name, lastUsed}` shape the schema rejects (`branch` required, `additionalProperties: false`), so the recent-branch picker option could never populate and a literal implementation would have failed prefs validation. Naming the right target, the right key and the legacy field to avoid costs 41 tokens over the one line it replaces. Compression came first and was applied three times to the replacement text itself, from 120 tokens down to 66, by moving the rationale out of the phase doc entirely: the reasoning now lives where it is enforced, in the migrate-prefs carry-forward comment and the smoke-pref-migration f7 block, leaving the phase doc with only the instruction. 50 was the smallest step that clears it; phase-0-init sits at 10893/12400, far under its own max, so this is purely an aggregate ceiling. v15.0.0: total 52750 -> 53100, the stack-skill tables in phase-1/2/4 now carry plugin-namespaced names (ai-<stack>-toolkit:<skill>) - functional prefixes, ~170 tokens. v15.10.0: total 53350 -> 53950 for the memory-recall + context-offload contracts (Phase 1 two-block durable-knowledge injection and its telemetry, Phase 3 build-log offload pipe, Phase 4 ranked prior art, offload pipe and recall telemetry). Compression came first and twice, taking the new prose from 1168 tokens to 580: the reasoning behind the two blocks lives in multi-agent-refs/prompt-assembly.md and the reasoning behind the offload filter lives in the offload-ref.sh header, both outside this budget, so the phase docs carry only the call, the pref that gates it and the one fact an agent cannot infer - that the evidence gate still reads the whole build log, so offloading changes what is read, never what counts as a verified pass. Every per-phase max still passes (phase-3 7985/8950, phase-4 12997/14750); phase-3 and phase-4 crossed their warn lines and are left amber on purpose, because that is the signal that those two docs are the next ones needing structural compression rather than another bump. v15.13.0: total 53950 -> 54050 for the prefs-to-flag bridges. Five settings had shipped declared-but-inert: contextOffload.minLines and .tailLines (fixed in 15.11.0), learningsLedger.maxBriefEntries, and testGap.scanTree and .promoteSeverity - the last two declared in the schema AND implemented as flags in the scanner, with nothing in between reading the pref and passing the flag. Wiring three of them costs the phase docs 94 tokens, which is the wiring itself and not prose: two `--max` substitutions and a three-line GAP_FLAGS block. Compression came first and twice, as always: the rationale that would have sat in phase-5 now lives in the header of smoke-prefs-consumed.sh, the gate that makes this class fail a build instead of shipping, and a `--severity-promote` table row was dropped because the invocation above it now shows the flag and names the pref that triggers it, which the row did not. 100 was the smallest step that clears it. Every per-phase max still passes; phase-3 and phase-4 remain amber on purpose. v15.14.0: total 54050 -> 54400 for the supported-version gate. Phase 0 Step 0.6 stopped being purely advisory: a release can now publish an npm dist-tag `required` that names the oldest runnable version, and below it the run halts instead of nagging. What the phase doc has to carry is the part an agent cannot infer - the third stdout field, that the halt is identical in autopilot, and that the run must NOT continue on the freshly updated install because its docs were already loaded from the old version. Compression came first, as always, and took the new prose from 469 tokens to 337: the rationale for the floor, the exemption list, the fail-open rules and the `npm dist-tag add` recipe all moved to multi-agent-refs/rules.md \"Supported Version Gate\" (loaded by 25 commands, outside this budget) and to the header of require-supported-version.sh, leaving the phase doc with the call, the decision table and the halt. 350 was the smallest step that clears it. Every per-phase max still passes (phase-0-init 11230/12400); phase-3 and phase-4 remain amber on purpose. v15.17.0: total 54400 -> 54900 for the Phase 1 analysis-document step. Phase 2 and Phase 3 pre-flights had BLOCKED on `analysis/<feature>-<platform>.md` since v9.0.0 while nothing produced it, so a full run either aborted at Phase 2 or the model ignored its own BLOCKING contract; Step 4 is the producer. What the phase doc carries is only what cannot be inferred: the when-table (taskType x Figma reference), the four refs in load order, the two artefacts, and that the doc validator fails closed. Compression came first and took the step from 745 tokens to 497: the history of why the gap existed moved to the CHANGELOG, the per-ref one-line descriptions moved into the refs' own headers, and the autopilot carve-out collapsed to one clause. The 17.4k-token analysis engine itself is NOT in this budget - it moved out of commands/ into multi-agent-refs/analysis/{locked,evidence,synthesis,render}.md, loaded on demand, which also took analysis/SKILL.md from 18081 to 5974 tokens and retired its lint grace entry. 500 was the smallest step that clears it; phase-1-analysis sits at 4338/4600 and is amber on purpose, like phase-3 and phase-4. v15.18.0: total 54900 -> 55250 for analysis mode. Three phase docs gained a mode branch that cannot be inferred: Phase 4 reviews a document instead of a diff (validator, the one question reviewers answer, the open-question walk), and Phase 6 publishes instead of committing. Compression came first and was applied twice to the new prose and once to old: the Phase 4 branch went from 320 tokens to 180 and the Phase 6 branch from 190 to 120 by pointing at multi-agent-refs/analysis/{resolve,render}.md, which now hold the walks themselves, and the front-matter parse contract stopped being spelled out in both pre-flights. The analysis engine keeps leaving this budget rather than entering it: intake joined locked/evidence/synthesis/render/resolve in multi-agent-refs/analysis/, which is what let analysis/SKILL.md drop under the 6000 hard cap after its grace entry was retired. 350 was the smallest step that clears it; phase-4 and phase-6 are amber on purpose, as phase-1 and phase-3 already were. v15.20.0: total 55250 -> 55500 for the TDD bridge. Phase 3 pre-flight read the analysis doc's concept table and even said test method names come from it, while nothing read Section 15 - so the RED step invented tests and the analysis test matrix never reached development. Phase 3 step 5b now loads it into state.dev.testPlan[] and Phase 4 step 1.45 cross-checks every planned row against a real test, which is what turns \"analysis quality is output quality\" from a slogan into a finding. Compression came first on both blocks, 300 tokens down to 175, by dropping the enumerated failure modes to one line each and the rationale to one clause; the reasoning lives in the CHANGELOG. 250 was the smallest step that clears it. v15.21.0: total 55500 -> 55800 for the post-analysis confirmation. Phase 2 gained Step 0.9, the last human checkpoint before Phase 3: derived values are shown for confirmation and only Section 20 rows are asked, through the resolve engine that already exists in refs. It belongs here rather than Phase 4 because Phase 4 runs after development, where an answer arrives too late to change anything. Compression came first and twice, 430 tokens down to 250, by collapsing the derived-vs-asked explanation to one sentence each and moving the walk itself to multi-agent-refs/analysis/resolve.md, which Phase 4 and analysis-resolve already mount. 300 was the smallest step that clears it. v15.22.0: total 55800 -> 55900 for the analyst-toolkit hooks. Phase 1 Step 4 now names the two prefs that decide whether a document is produced at all and how deep it goes (forceFull, mode) - the first of those had shipped declared-but-inert and smoke-prefs-consumed caught it - and Phase 4 triage gained one clause: a finding that blames a third-party library asks evidence-github whether it is already open upstream, which turns it into a deferred item with a citation instead of Phase 3 rework on code that is not ours. Compression came first and three times, taking the new prose from 220 tokens to 110, and the Phase 1d evidence contract itself never entered this budget - it lives in multi-agent-refs/analysis/evidence.md beside the phases it belongs to. 100 was the smallest step that clears it, leaving 34 tokens of headroom. phase-4 stays amber and the debt named at v15.10.0 stands: it is the doc that needs structural compression rather than another bump, and the two candidates are the inline triage JSON shape and the 3.4 telemetry block, both of which restate something already authoritative elsewhere. v16.0.0: total 55900 -> 56350 for the depth picker. `--dev` and the four dev-* commands are gone; depth is Phase 0 Step 7.5, which costs phase-0-init a step it did not have. Compression came first and three times, taking the step from 530 tokens to 300: the question wording, the per-taskType recommendation and the mode tables all live in phases/modes.md (outside this budget), so the phase doc carries only what an agent cannot infer - that the step runs after Step 7 and why, who is exempt, that ASK_CHOICE_DEFAULT must be passed explicitly because ask-choice.sh takes the FIRST option on a non-TTY, and that Short flips the Phase 1/2 tiles late rather than pre-marking them. The phase-4 telemetry block named as compression debt at v15.22.0 was collapsed to an emit() helper (-27) and the four dev-* mode files left the tree entirely, but neither offsets a genuinely new phase step. 450 was the smallest step that clears it, leaving 119 tokens of headroom. phase-4 remains amber and its other named candidate, the inline triage JSON shape, was left alone on purpose: it is the prompt the triage agent is handed, not a restatement for readers."
39
+ "total_max_tokens": 56600,
40
+ "note": "Token estimate = ceil(chars / 4). Per-phase budget rule: warn = current+10% (rounded to nearest 50), max = current+25%. Gives ~6 edit cycles of headroom before warn trips - intentionally quiet under normal maintenance, loud when a phase grows unusually. Only the active phase is loaded (lazy). Recalibrated at v10.0.0 after the validator/consistency/simplifier/lesson gate contracts landed in phases 1-4. Recalibrated again at v10.9.0 after the verify-by-test (Phase 4 Step 3.7), update-check (Phase 0 Step 0.6), immutable-test (Phase 3 GREEN) and redTests re-entry contracts landed - Step 3.7 prose was compressed to a pointer into refs/features/verify-by-test.md before the recalibration. Total bumped 50000 -> 51000 at v12.5.0 after the worktree residue/traversal-prune contract (Phase 0 + Phase 5 heal) and the Reflexion causal-diagnosis contract (Phase 4 lesson memory) landed; the prose was compressed first (161 tokens reclaimed) and every per-phase max still passes - only the aggregate needed room. Recalibrated again at v13.6.0 after the install-relative path correction: an instruction that names `pipeline/scripts/x` resolves only from a repo checkout, and a run happens in the user's worktree, so 157 references across these docs moved to `$HOME/.claude/...` at +5 bytes each - 196 tokens of pure correctness cost. Same discipline as before: prose was compressed FIRST (149 tokens reclaimed, by pointing Phase 1's Figma tier table at the Phase 0 probe that already resolved it and Phase 4's Codex constraints at the always-loaded AGENTS.md block), and only then were the budgets moved. Five warn lines had been permanently amber, which makes the amber tier useless as a signal, so every warn was reset to the documented current+10% and the four maxes that the new warn would have collided with were reset to current+25%. Aggregate 51000 -> 51500. Total bumped 51500 -> 52200 at v14.0.0 after Phase 4 Review entered the four --dev mode phase sets and the criteria-resolution contract (Step 1.78) landed. Same discipline as every prior bump: prose was compressed FIRST, 820 tokens reclaimed, before the number moved. Two of those compressions are structural rather than cosmetic - the hardcoded SwiftUI interaction list in Step 1.5 and the SwiftUI convention paragraph in Step 2.8 were transcriptions of rules that now live in a scoped registry, so keeping them here would have re-created the drift this release exists to remove, and the third moved the Step 1.78 full contract into refs/features/skill-conformance.md leaving a pointer. What remains is contract text that cannot be inferred: the manifest's four consumer-visible parts, the conformance checklist the reviewers must return, and the fail-closed semantics. Every per-phase max still passes (phase-4 12405/14750); only the aggregate needed room. Total bumped 52200 -> 52700 at v14.1.0 after two more contracts landed: stack skill routing (Phase 3 pre-flight step 9) and worktree finalize (Phase 6 step 9). Compression came first, as always, and twice: 224 tokens out of Phase 3 by pointing its criteria-ledger and routing steps at their feature files instead of restating them, and 190 out of Phase 6 by moving the finalize contract into refs/features/worktree-finalize.md and leaving the invocation plus the exit-3 semantics. Both new contracts follow the pattern the earlier ones set: the phase doc carries the call and the decision, the feature file carries the reasoning, and the feature files are outside this budget because it loops only the eight phase-N-* keys. Every per-phase max still passes (phase-3 7677/8950, phase-6 5223/6150 and both under warn); only the aggregate needed room. Total bumped 52700 -> 52750 for the Phase 0 Step 3 branch-persistence correction: the step wrote the legacy `projects[].branches` while the TTL filter two sections below read `global.recentBranches`, and both spots named a `{name, lastUsed}` shape the schema rejects (`branch` required, `additionalProperties: false`), so the recent-branch picker option could never populate and a literal implementation would have failed prefs validation. Naming the right target, the right key and the legacy field to avoid costs 41 tokens over the one line it replaces. Compression came first and was applied three times to the replacement text itself, from 120 tokens down to 66, by moving the rationale out of the phase doc entirely: the reasoning now lives where it is enforced, in the migrate-prefs carry-forward comment and the smoke-pref-migration f7 block, leaving the phase doc with only the instruction. 50 was the smallest step that clears it; phase-0-init sits at 10893/12400, far under its own max, so this is purely an aggregate ceiling. v15.0.0: total 52750 -> 53100, the stack-skill tables in phase-1/2/4 now carry plugin-namespaced names (ai-<stack>-toolkit:<skill>) - functional prefixes, ~170 tokens. v15.10.0: total 53350 -> 53950 for the memory-recall + context-offload contracts (Phase 1 two-block durable-knowledge injection and its telemetry, Phase 3 build-log offload pipe, Phase 4 ranked prior art, offload pipe and recall telemetry). Compression came first and twice, taking the new prose from 1168 tokens to 580: the reasoning behind the two blocks lives in multi-agent-refs/prompt-assembly.md and the reasoning behind the offload filter lives in the offload-ref.sh header, both outside this budget, so the phase docs carry only the call, the pref that gates it and the one fact an agent cannot infer - that the evidence gate still reads the whole build log, so offloading changes what is read, never what counts as a verified pass. Every per-phase max still passes (phase-3 7985/8950, phase-4 12997/14750); phase-3 and phase-4 crossed their warn lines and are left amber on purpose, because that is the signal that those two docs are the next ones needing structural compression rather than another bump. v15.13.0: total 53950 -> 54050 for the prefs-to-flag bridges. Five settings had shipped declared-but-inert: contextOffload.minLines and .tailLines (fixed in 15.11.0), learningsLedger.maxBriefEntries, and testGap.scanTree and .promoteSeverity - the last two declared in the schema AND implemented as flags in the scanner, with nothing in between reading the pref and passing the flag. Wiring three of them costs the phase docs 94 tokens, which is the wiring itself and not prose: two `--max` substitutions and a three-line GAP_FLAGS block. Compression came first and twice, as always: the rationale that would have sat in phase-5 now lives in the header of smoke-prefs-consumed.sh, the gate that makes this class fail a build instead of shipping, and a `--severity-promote` table row was dropped because the invocation above it now shows the flag and names the pref that triggers it, which the row did not. 100 was the smallest step that clears it. Every per-phase max still passes; phase-3 and phase-4 remain amber on purpose. v15.14.0: total 54050 -> 54400 for the supported-version gate. Phase 0 Step 0.6 stopped being purely advisory: a release can now publish an npm dist-tag `required` that names the oldest runnable version, and below it the run halts instead of nagging. What the phase doc has to carry is the part an agent cannot infer - the third stdout field, that the halt is identical in autopilot, and that the run must NOT continue on the freshly updated install because its docs were already loaded from the old version. Compression came first, as always, and took the new prose from 469 tokens to 337: the rationale for the floor, the exemption list, the fail-open rules and the `npm dist-tag add` recipe all moved to multi-agent-refs/rules.md \"Supported Version Gate\" (loaded by 25 commands, outside this budget) and to the header of require-supported-version.sh, leaving the phase doc with the call, the decision table and the halt. 350 was the smallest step that clears it. Every per-phase max still passes (phase-0-init 11230/12400); phase-3 and phase-4 remain amber on purpose. v15.17.0: total 54400 -> 54900 for the Phase 1 analysis-document step. Phase 2 and Phase 3 pre-flights had BLOCKED on `analysis/<feature>-<platform>.md` since v9.0.0 while nothing produced it, so a full run either aborted at Phase 2 or the model ignored its own BLOCKING contract; Step 4 is the producer. What the phase doc carries is only what cannot be inferred: the when-table (taskType x Figma reference), the four refs in load order, the two artefacts, and that the doc validator fails closed. Compression came first and took the step from 745 tokens to 497: the history of why the gap existed moved to the CHANGELOG, the per-ref one-line descriptions moved into the refs' own headers, and the autopilot carve-out collapsed to one clause. The 17.4k-token analysis engine itself is NOT in this budget - it moved out of commands/ into multi-agent-refs/analysis/{locked,evidence,synthesis,render}.md, loaded on demand, which also took analysis/SKILL.md from 18081 to 5974 tokens and retired its lint grace entry. 500 was the smallest step that clears it; phase-1-analysis sits at 4338/4600 and is amber on purpose, like phase-3 and phase-4. v15.18.0: total 54900 -> 55250 for analysis mode. Three phase docs gained a mode branch that cannot be inferred: Phase 4 reviews a document instead of a diff (validator, the one question reviewers answer, the open-question walk), and Phase 6 publishes instead of committing. Compression came first and was applied twice to the new prose and once to old: the Phase 4 branch went from 320 tokens to 180 and the Phase 6 branch from 190 to 120 by pointing at multi-agent-refs/analysis/{resolve,render}.md, which now hold the walks themselves, and the front-matter parse contract stopped being spelled out in both pre-flights. The analysis engine keeps leaving this budget rather than entering it: intake joined locked/evidence/synthesis/render/resolve in multi-agent-refs/analysis/, which is what let analysis/SKILL.md drop under the 6000 hard cap after its grace entry was retired. 350 was the smallest step that clears it; phase-4 and phase-6 are amber on purpose, as phase-1 and phase-3 already were. v15.20.0: total 55250 -> 55500 for the TDD bridge. Phase 3 pre-flight read the analysis doc's concept table and even said test method names come from it, while nothing read Section 15 - so the RED step invented tests and the analysis test matrix never reached development. Phase 3 step 5b now loads it into state.dev.testPlan[] and Phase 4 step 1.45 cross-checks every planned row against a real test, which is what turns \"analysis quality is output quality\" from a slogan into a finding. Compression came first on both blocks, 300 tokens down to 175, by dropping the enumerated failure modes to one line each and the rationale to one clause; the reasoning lives in the CHANGELOG. 250 was the smallest step that clears it. v15.21.0: total 55500 -> 55800 for the post-analysis confirmation. Phase 2 gained Step 0.9, the last human checkpoint before Phase 3: derived values are shown for confirmation and only Section 20 rows are asked, through the resolve engine that already exists in refs. It belongs here rather than Phase 4 because Phase 4 runs after development, where an answer arrives too late to change anything. Compression came first and twice, 430 tokens down to 250, by collapsing the derived-vs-asked explanation to one sentence each and moving the walk itself to multi-agent-refs/analysis/resolve.md, which Phase 4 and analysis-resolve already mount. 300 was the smallest step that clears it. v15.22.0: total 55800 -> 55900 for the analyst-toolkit hooks. Phase 1 Step 4 now names the two prefs that decide whether a document is produced at all and how deep it goes (forceFull, mode) - the first of those had shipped declared-but-inert and smoke-prefs-consumed caught it - and Phase 4 triage gained one clause: a finding that blames a third-party library asks evidence-github whether it is already open upstream, which turns it into a deferred item with a citation instead of Phase 3 rework on code that is not ours. Compression came first and three times, taking the new prose from 220 tokens to 110, and the Phase 1d evidence contract itself never entered this budget - it lives in multi-agent-refs/analysis/evidence.md beside the phases it belongs to. 100 was the smallest step that clears it, leaving 34 tokens of headroom. phase-4 stays amber and the debt named at v15.10.0 stands: it is the doc that needs structural compression rather than another bump, and the two candidates are the inline triage JSON shape and the 3.4 telemetry block, both of which restate something already authoritative elsewhere. v16.0.0: total 55900 -> 56350 for the depth picker. `--dev` and the four dev-* commands are gone; depth is Phase 0 Step 7.5, which costs phase-0-init a step it did not have. Compression came first and three times, taking the step from 530 tokens to 300: the question wording, the per-taskType recommendation and the mode tables all live in phases/modes.md (outside this budget), so the phase doc carries only what an agent cannot infer - that the step runs after Step 7 and why, who is exempt, that ASK_CHOICE_DEFAULT must be passed explicitly because ask-choice.sh takes the FIRST option on a non-TTY, and that Short flips the Phase 1/2 tiles late rather than pre-marking them. The phase-4 telemetry block named as compression debt at v15.22.0 was collapsed to an emit() helper (-27) and the four dev-* mode files left the tree entirely, but neither offsets a genuinely new phase step. 450 was the smallest step that clears it, leaving 119 tokens of headroom. phase-4 remains amber and its other named candidate, the inline triage JSON shape, was left alone on purpose: it is the prompt the triage agent is handed, not a restatement for readers. v16.2.0: total 56350 -> 56600 for the spec-freshness and reuse-tag contracts. Phase 3 step 3 had compared `state.run.lastAnalysisDigest` since it was written, against a key nothing ever set and that the state schema did not declare, so the staleness branch was unreachable and every run reported fresh by default. Phase 1 now persists the digest and a `base_commit` anchor, and step 3 gained the repo-drift half the digest cannot see: a reused document keeps a matching digest precisely because its evidence inputs did not change, while the code underneath it moved. The second contract is the Section 14 tag reaching development: Phase 2 carries it onto the todo as `sourceTag` and Phase 3 treats it as an instruction, which is what stops a Reuse row from being re-implemented. Compression came first and took the four additions from 380 tokens to 214, by moving every rationale clause out of the phase docs: why the commit anchor exists rather than a digest recomputation lives in this note and the CHANGELOG, and the schema descriptions carry the field semantics. The baseline had 9 tokens of headroom, so no addition of any size could have fit without a bump. 250 was the smallest step that clears it, leaving 45 tokens. phase-3 and phase-4 remain amber."
41
41
  }
@@ -277,7 +277,8 @@ function removeGeneratedCodexAgents(agentsDir) {
277
277
  }
278
278
 
279
279
  /**
280
- * Hand the dev-toolkit MCP registration back to the host CLI that owns it.
280
+ * Hand the RETIRED MCP registration back to the host CLI that owns it. The
281
+ * current one (multi-agent-toolkit) is preserved - see MCP_PRESERVED below.
281
282
  *
282
283
  * Best-effort: a missing binary or an already-absent entry is not an uninstall
283
284
  * failure. Never edits the host's config file directly - Codex keeps marketplace
@@ -699,7 +700,7 @@ export async function main() {
699
700
  console.log(" Targets:");
700
701
  if (forClaude)
701
702
  console.log(
702
- " - Claude Code (~/.claude/{commands/multi-agent, scripts, multi-agent-refs, schemas, lib} + pipeline skills + pipeline agent files + user-scope dev-toolkit MCP entry)",
703
+ " - Claude Code (~/.claude/{commands/multi-agent, scripts, multi-agent-refs, schemas, lib except the credential reader} + pipeline skills + pipeline agent files + the retired dev-toolkit MCP entry; the multi-agent-toolkit entry is KEPT)",
703
704
  );
704
705
  if (forCopilot)
705
706
  console.log(
@@ -717,7 +718,7 @@ export async function main() {
717
718
  );
718
719
  if (forCodex)
719
720
  console.log(
720
- " - Codex CLI (~/.codex: skills/multi-agent, multi-agent-refs, agents/*.toml, prompts/multi-agent.md, scripts, lib, schemas, rules, AGENTS.md block, dev-toolkit MCP entry)",
721
+ " - Codex CLI (~/.codex: skills/multi-agent, multi-agent-refs, agents/*.toml, prompts/multi-agent.md, scripts, lib except the credential reader, schemas, rules, AGENTS.md block, the retired dev-toolkit MCP entry; multi-agent-toolkit is KEPT)",
721
722
  );
722
723
  console.log("");
723
724
  if (allData) {
@@ -16,7 +16,14 @@
16
16
  // Goals, User Stories, API Contracts, Architecture, Files to Add, Risks,
17
17
  // References.
18
18
  // - Humanizer punctuation policy (Locked 7): no em-dash / en-dash / ellipsis /
19
- // section-sign / curly quotes anywhere in the body.
19
+ // section-sign / curly quotes in the prose body. Front-matter, fenced code
20
+ // blocks, table rows and URLs are exempt, matching the humanizer pass.
21
+ // - Opt-in coverage: ui_tests: true requires Section 15.6; a11y_depth: full
22
+ // requires the Section 16.2 walkthrough.
23
+ // - Section 15 present in Full mode (it is Phase 3's RED input), with a unit
24
+ // sub-table whenever business rules are defined.
25
+ // - Section 3 diagrams: a rendered section carries at least one mermaid block
26
+ // (ERROR); an absent section is a WARN, since omission can be legitimate.
20
27
  // - Manual scenarios (Section 15.7): every MT- row carries a BR- id.
21
28
  // - Variant coverage (Section 6.X): every axis row states the full axis and
22
29
  // the subset this screen uses; half a row cannot be audited.
@@ -87,6 +94,46 @@ function parseFrontMatter(text) {
87
94
  return { fm, bodyStart: end + 1 };
88
95
  }
89
96
 
97
+ function sectionBody(lines, keywords, level = 2) {
98
+ const head = new RegExp(`^#{${level}}\\s+\\d+(\\.\\d+)*\\.?\\s`);
99
+ let start = -1;
100
+ for (let i = 0; i < lines.length; i++) {
101
+ if (head.test(lines[i]) && keywords.some((k) => lines[i].includes(k))) {
102
+ start = i;
103
+ break;
104
+ }
105
+ }
106
+ if (start < 0) return null;
107
+ let end = lines.length;
108
+ for (let i = start + 1; i < lines.length; i++) {
109
+ if (head.test(lines[i])) {
110
+ end = i;
111
+ break;
112
+ }
113
+ }
114
+ return lines.slice(start + 1, end);
115
+ }
116
+
117
+ // Data rows are the pipe-rows that follow a table's separator row, which is the
118
+ // only shape that distinguishes them from the header without guessing at cell text.
119
+ function tableDataRows(bodyLines) {
120
+ const rows = [];
121
+ let afterSeparator = false;
122
+ for (const line of bodyLines) {
123
+ const t = line.trim();
124
+ if (!t.startsWith("|")) {
125
+ afterSeparator = false;
126
+ continue;
127
+ }
128
+ if (/^\|[\s\-:|]+\|$/.test(t)) {
129
+ afterSeparator = true;
130
+ continue;
131
+ }
132
+ if (afterSeparator) rows.push(t);
133
+ }
134
+ return rows;
135
+ }
136
+
90
137
  function main() {
91
138
  const text = readInput();
92
139
  const strict = process.argv.includes("--strict");
@@ -154,11 +201,114 @@ function main() {
154
201
  }
155
202
  }
156
203
 
157
- // 3. Humanizer punctuation
204
+ // 2c. Section 15 is Phase 3's RED input (phase-3-dev.md step 5b): the tests
205
+ // written first come from it. Full mode without it hands dev an empty matrix.
206
+ if (mode === "full") {
207
+ const hasTestPlan = ["Test Planı", "Test Plani", "Test Plan"].some((kw) =>
208
+ headingBlob.includes(kw),
209
+ );
210
+ if (!hasTestPlan) {
211
+ // The omission table allows exactly one case: a backend-only run with no
212
+ // contract testing planned. The validator knows the platform, so that case
213
+ // warns instead of blocking; every other platform hands dev an empty matrix.
214
+ const msg = "no Section 15 Test Plan; Full mode dev reads it as the RED input (Locked 31)";
215
+ if (parsed?.fm?.platform === "backend") {
216
+ warns.push(`${msg} - allowed for backend only when no contract testing is planned`);
217
+ } else {
218
+ errors.push(`missing Section 15 Test Plan; Full mode dev reads it as the RED input (Locked 31)`);
219
+ }
220
+ } else {
221
+ const hasUnit =
222
+ headingBlob.includes("15.1") ||
223
+ headingBlobLower.includes("birim test") ||
224
+ headingBlobLower.includes("unit test");
225
+ if (!hasUnit && /BR-[a-z0-9]+(?:-[a-z0-9]+)*-\d+/i.test(text)) {
226
+ errors.push(
227
+ "Section 15 has no unit-test sub-table while business rules are defined (Locked 31)",
228
+ );
229
+ }
230
+ }
231
+ }
232
+
233
+ // 2d. Section 3 carries the diagrams. Omission is legitimate under the
234
+ // template's conditions, so absence warns; a rendered section with no
235
+ // mermaid block is empty scaffolding and fails.
236
+ const hasFlowSection = ["Akış Diyagramı", "Akis Diyagrami", "Flow Chart"].some((kw) =>
237
+ headingBlob.includes(kw),
238
+ );
239
+ const hasMermaid = /^\s*```mermaid/m.test(text);
240
+ if (hasFlowSection && !hasMermaid) {
241
+ errors.push("Section 3 is rendered but carries no mermaid block");
242
+ } else if (!hasFlowSection && mode === "full") {
243
+ warns.push(
244
+ "no Section 3 flow chart; legitimate only for a single screen with a single service and a simple rule",
245
+ );
246
+ }
247
+
248
+ // 2e. Locked 16: every Files-to-Add row is tagged. The decision says untagged
249
+ // rows fail the dispatch gate, so this is where that sentence becomes true.
250
+ const allLines = text.split("\n");
251
+ const filesBody = sectionBody(allLines, ["Eklenecek Dosyalar", "Files to Add"]);
252
+ if (filesBody) {
253
+ const TAGS = ["Add new", "Reuse", "Modify"];
254
+ for (const row of tableDataRows(filesBody)) {
255
+ if (!TAGS.some((t) => row.includes(t))) {
256
+ errors.push(
257
+ `Files-to-Add row is untagged (Locked 16, needs Reuse|Add new|Modify): ${row.slice(0, 60)}`,
258
+ );
259
+ }
260
+ }
261
+ }
262
+
263
+ // 2f. Locked 24: every Pass B concept-table cell carries its footnote.
264
+ const conceptBody = sectionBody(allLines, ["Kavram tablosu", "Concept table"], 3);
265
+ if (conceptBody) {
266
+ // The template prescribes two shapes for this table and does not say which
267
+ // wins: the 13.1 scaffold uses explicit Confidence and Evidence columns, the
268
+ // Pass B footnote grammar puts the same facts in a `^[key conf: source]`
269
+ // suffix. Either carries the evidence, so accept both and fail only a row
270
+ // that carries neither.
271
+ for (const row of tableDataRows(conceptBody)) {
272
+ if (row.includes("^[")) continue;
273
+ const cells = row.split("|").map((c) => c.trim());
274
+ if (cells.length >= 6 && cells[3] && cells[4]) continue;
275
+ errors.push(`concept-table row states no evidence (Locked 24): ${row.slice(0, 60)}`);
276
+ }
277
+ }
278
+
279
+ // 2g. Locked 31 main clause: a rule with no test scenario fails the gate.
280
+ // The pre-existing occurrence-count heuristic below stays as the looser net.
281
+ if (mode === "full") {
282
+ const idRx = /BR-[a-z0-9]+(?:-[a-z0-9]+)*-\d+/gi;
283
+ const storyBody = sectionBody(allLines, ["Kullanıcı Hikayeleri", "Kullanici Hikayeleri", "User Stories"]);
284
+ const testBody = sectionBody(allLines, ["Test Planı", "Test Plani", "Test Plan"]);
285
+ if (storyBody && testBody) {
286
+ const defined = new Set((storyBody.join("\n").match(idRx) || []).map((x) => x.toUpperCase()));
287
+ const tested = new Set((testBody.join("\n").match(idRx) || []).map((x) => x.toUpperCase()));
288
+ for (const id of defined) {
289
+ if (!tested.has(id)) {
290
+ errors.push(`business rule ${id} has no Section 15 test scenario (Locked 31)`);
291
+ }
292
+ }
293
+ }
294
+ }
295
+
296
+ // 3. Humanizer punctuation. Scope mirrors the humanizer pass exactly
297
+ // (analysis/render.md): front-matter, fenced code blocks, table rows and
298
+ // URLs are exempt there, so flagging them here would raise an ERROR that no
299
+ // humanizer run can clear.
158
300
  const bodyLines = text.split("\n");
159
- for (let i = 0; i < bodyLines.length; i++) {
301
+ let inFence = false;
302
+ for (let i = parsed ? parsed.bodyStart : 0; i < bodyLines.length; i++) {
303
+ const raw = bodyLines[i];
304
+ if (/^\s*```/.test(raw)) {
305
+ inFence = !inFence;
306
+ continue;
307
+ }
308
+ if (inFence || raw.trim().startsWith("|")) continue;
309
+ const scanned = raw.replace(/\bhttps?:\/\/\S+/gi, "");
160
310
  for (const b of BANNED_PUNCT) {
161
- if (bodyLines[i].includes(b.ch)) {
311
+ if (scanned.includes(b.ch)) {
162
312
  errors.push(`banned punctuation ${b.name} at line ${i + 1} (Locked 7 humanizer policy)`);
163
313
  }
164
314
  }
@@ -208,7 +358,12 @@ function main() {
208
358
  // audited - "used subset" means nothing without the set it is a subset of.
209
359
  let inVariant = false;
210
360
  for (const line of text.split("\n")) {
211
- if (/^#{2,3}\s+6\.X\b/.test(line)) { inVariant = true; continue; }
361
+ // Keyed on the heading text, not the number: Locked 2 re-flows numbering, so
362
+ // a literal "6.X" match silently stops running the moment the section moves.
363
+ if (/^#{2,3}\s+\d+(\.[0-9X]+)*\.?\s/.test(line) && /Varyant|Variant/i.test(line)) {
364
+ inVariant = true;
365
+ continue;
366
+ }
212
367
  if (inVariant && /^#{1,3}\s/.test(line)) { inVariant = false; continue; }
213
368
  if (!inVariant || !/^\|/.test(line)) continue;
214
369
  const cells = line.split("|").map((c) => c.trim());
@@ -961,7 +961,7 @@
961
961
  },
962
962
  {
963
963
  "name": "multi-agent-analysis",
964
- "description": "Standalone feature-spec analysis (v3 template). Platform-agnostic concept layer with repo-driven convention extraction and per-platform Pass B render. 23 main sections + 3 footer in Full mode; 7 sections in Lite mode (auto for small features). Collects Figma / Swagger / Confluence / Jira / Standards",
964
+ "description": "Standalone feature-spec analysis (v3 template). Platform-agnostic concept layer with repo-driven convention extraction and per-platform Pass B render. 23 sections in Full mode; 8 of them in Lite mode (auto for small features). Collects Figma / Swagger / Confluence / Jira / Standards / Firebase / rep",
965
965
  "platform": null,
966
966
  "group": "core",
967
967
  "plugin": null,
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  name: multi-agent-analysis
3
3
  language: en
4
- description: "Standalone feature-spec analysis (v3 template). Platform-agnostic concept layer with repo-driven convention extraction and per-platform Pass B render. 23 main sections + 3 footer in Full mode; 7 sections in Lite mode (auto for small features). Collects Figma / Swagger / Confluence / Jira / Standards / Firebase / repo inputs, then stops. Does not chain into dev or create branches. Use when a feature needs a written specification before any code, from Figma, Swagger, Confluence, Jira or repo inputs."
4
+ description: "Standalone feature-spec analysis (v3 template). Platform-agnostic concept layer with repo-driven convention extraction and per-platform Pass B render. 23 sections in Full mode; 8 of them in Lite mode (auto for small features). Collects Figma / Swagger / Confluence / Jira / Standards / Firebase / repo inputs, then stops. Does not chain into dev or create branches. Use when a feature needs a written specification before any code, from Figma, Swagger, Confluence, Jira or repo inputs."
5
5
  user-invocable: true
6
6
  argument-hint: "[\"<analysis-name>\"] [--lite | --full] [--no-cache] [--preview-conventions]"
7
7
  ---
@@ -22,7 +22,7 @@ Produces a stakeholder-ready, platform-agnostic feature-spec document set (one m
22
22
 
23
23
  ## Template (v3)
24
24
 
25
- Full mode renders 23 main sections + 3 footer sections (Glossary, Changelog, References). Lite mode renders 7 sections (Summary, Goals + Non-Goals, User Stories, API Contracts, Architecture, Files to Add, References) and auto-activates for small features via three scored signals; `--lite` / `--full` flags always win.
25
+ Full mode renders 23 sections (Glossary, Changelog, References). Lite mode renders 7 sections (Summary, Goals + Non-Goals, User Stories, API Contracts, Architecture, Files to Add, References) and auto-activates for small features via three scored signals; `--lite` / `--full` flags always win.
26
26
 
27
27
  **Section omission**: zero-evidence sections are dropped entirely (no "TBD" placeholder); numbering re-flows to stay sequential. Sections 1, 2, 4, 9, 13, 14, 20, 21 are never omitted.
28
28
 
@@ -114,7 +114,7 @@ Procedure:
114
114
 
115
115
  The pipeline's hands on devices and browsers are MCP tools served by a companion repo (`multi-agent-toolkit-mcp`): Phase 5 test, `manual-test`, `design-check` and `apple-archive-compliance` all call them, and several pipeline skills declare a minimum toolkit version (see `cross-cli-contract.md`). That repo therefore has to track the MCP field, not just its own README. This step researches what current practice is and audits the toolkit against it.
116
116
 
117
- Full procedure - resolution (configuration first, never a hardcoded path; skip when nothing resolves or `enabled` is false), the 5 research axes, the audit command block, and the band-E output table + rules - lives in `$HOME/.claude/multi-agent-refs/refactor/dev-toolkit-research.md`. Read it before running this step.
117
+ Full procedure - resolution (configuration first, never a hardcoded path; skip when nothing resolves or `enabled` is false), the 5 research axes, the audit command block, and the band-E output table + rules - lives in `$HOME/.claude/multi-agent-refs/refactor/toolkit-research.md`. Read it before running this step.
118
118
 
119
119
  ## Step 0d: RUN-ERRORS - what the pipeline actually failed on
120
120
 
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  name: humanizer
3
- version: 1.1.0
3
+ version: 1.2.0
4
4
  description: |
5
5
  Remove AI-generated writing patterns from text. Makes output sound natural
6
6
  and human-written. Detects inflated language, filler phrases, AI vocabulary,
@@ -129,6 +129,48 @@ If the user provides a writing sample, match their style:
129
129
 
130
130
  When no sample is provided, default to clear, direct, slightly opinionated.
131
131
 
132
+ ## Output language
133
+
134
+ The caller passes `outputLanguage`; English is the default. Every pattern above is
135
+ an English failure mode. They do not transfer, so another language needs its own list.
136
+
137
+ Diacritics are preserved in every language. Never ASCII-fold prose: emit
138
+ `Geliştirme Özeti`, `için`, `Kullanıcı Hikayeleri`, never `Gelistirme Ozeti`, `icin`,
139
+ `Kullanici`. ASCII-folded text is a humanizer-skipped smell. The punctuation policy
140
+ targets fancy codepoints only (em dash, en dash, ellipsis, curly quotes, section
141
+ sign); it never touches letters.
142
+
143
+ ### Turkish (`tr`)
144
+
145
+ The dominant failure is calquing English sentence structure. Turkish puts the verb
146
+ last, so a long pre-verbal pile-up makes the reader hold every clause until the end.
147
+ The same shape reads fine in English, where the verb arrives early.
148
+
149
+ | Pattern | Example | Fix |
150
+ |---|---|---|
151
+ | Nominalization chain | "doğrulanmasının sağlanması gerekmektedir" | One finite verb: "doğrulanmalı" |
152
+ | Pre-verbal pile-up | three clauses before the verb in one sentence | Split it. One idea per sentence |
153
+ | Passive by default | "yapılmaktadır", "edilmektedir" | Active: "yapıyor", "ediyor" |
154
+ | Literal calque | "Bu, X'in Y olmasını sağlar" | "X böylece Y olur" |
155
+ | Invented Turkish for a technical term | "doğrulayıcı", "geçit" | Keep it: validator, gate, schema, front-matter |
156
+ | Aside squeezed between dashes | a clause wedged mid-sentence | Make it a new sentence |
157
+
158
+ Sentence length is the cheapest signal. A Turkish sentence past roughly 25 words is
159
+ usually two sentences.
160
+
161
+ ## Tones
162
+
163
+ The caller may pass a tone. It selects register, never accuracy.
164
+
165
+ | Tone | Audience | What changes |
166
+ |---|---|---|
167
+ | `technical-explanatory` | engineers reading a spec | Explain the mechanism. Identifiers, paths and code stay verbatim. No persuasion |
168
+ | `formal-stakeholder` | PM, designer, manager | No slang, no first person. Decision and impact lead; mechanism follows |
169
+ | `informal-technical` | teammates in a ticket thread | First person is fine, contractions are fine. Shortest form that stays precise |
170
+
171
+ An unrecognized tone name is worth surfacing, not silently absorbing: name the tones
172
+ that exist and ask which was meant.
173
+
132
174
  ## Output
133
175
 
134
176
  1. Rewrite the text