@mmerterden/multi-agent-pipeline 12.1.1 → 12.3.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
@@ -14,6 +14,66 @@ Internal file-layout changes that don't affect the slash-command surface are sti
14
14
 
15
15
  ---
16
16
 
17
+ ## [12.3.0] - 2026-07-23
18
+
19
+ `/multi-agent:analysis` overhaul: the feature-spec doc is now a development
20
+ handoff that both an AI implementer and a human reviewer can act on, bound by
21
+ one shared-ID traceability spine, with a deterministic pre-dispatch gate.
22
+ Researched against 2025-2026 spec-for-AI best practices. Repo stays generic;
23
+ all project specifics live in per-project `figma-config` / prefs.
24
+
25
+ ### Added
26
+
27
+ - **Figma Dev Mode annotations as authoritative copy.** `evidence.figma[]` gains
28
+ `annotations[]`; new `pipeline/lib/fetch-figma-annotations.sh` (Tier-2, token
29
+ off argv, config-driven `TR:/EN:` parser). The annotation is the copy; the
30
+ visible text layer is a placeholder. Never invent copy (blank beats a guess).
31
+ - **Localization ownership model.** `figma-config.localization`
32
+ (`in-repo` | `externally-owned`, `authoringPipeline`, `locales`, `baseLanguage`,
33
+ `keyPattern`). Section 10 renders a per-locale grid (in-repo) or key + status +
34
+ copy-source + base value with per-locale values deferred to the owning system
35
+ (externally-owned); new key = addition, existing = review-gated.
36
+ - **Business rules + rule-driven tests (Locked 31, the traceability spine).**
37
+ New Section 4.4 `BR-<slug>-NN` rules -> Given/When/Then acceptance criteria ->
38
+ Section 15.1 unit-test scenarios (happy/boundary/error/empty) with Swift
39
+ Testing (iOS) + JUnit5/MockK/Turbine (Android). One shared-ID vocabulary binds
40
+ rules -> tests -> UI flows -> a11y ids -> tokens -> Figma nodes.
41
+ - **Optional UI-test scenarios (Section 15.6)** and **optional VoiceOver/TalkBack
42
+ walkthrough (Section 16.2)** via Phase 0 Step 5a opt-ins (`ui_tests`,
43
+ `a11y_depth`), recorded in front-matter and enforced by the validator.
44
+ - **Layout & Scroll (Section 5.4):** auto-layout/padding/gap/sizing/position
45
+ tokens plus explicit scroll container / sticky / content insets / safe area /
46
+ keyboard avoidance (not inferable from a static frame) + Figma MCP capture
47
+ order. **Dark Mode (Section 7.4):** semantic light/dark token pairs, elevation,
48
+ contrast recheck. **Accessibility (16.1):** per-element table + WCAG 2.2 refs.
49
+ - **Deterministic pre-dispatch gate:** new `pipeline/scripts/validate-analysis-doc.mjs`
50
+ checks the emitted doc (front-matter completeness, never-omitted sections,
51
+ humanizer punctuation, Full-mode BR traceability, opt-in section presence);
52
+ wired as a BLOCKING Phase 4 gate. Turns prose "dispatch gate" claims into a
53
+ real, model-independent check. `smoke-validate-analysis-doc.sh` (10 cases).
54
+
55
+ ### Changed / Fixed
56
+
57
+ - Section 11 analytics events cite their triggering story / business rule.
58
+ - Platform coverage clarified: the analysis renders exactly the platforms whose
59
+ repos are provided (iOS only -> iOS doc, both -> both).
60
+ - Trim: Section 19 Alternatives + 22 Glossary default-drop; Section 18 Rollout
61
+ slimmed to a checklist.
62
+ - Fixed pre-existing template bugs: figma evidence schema reconciled with the
63
+ captured fields, locale-set `it`/`zh` mismatch, four undeclared `prefs.projects`
64
+ keys, duplicate Section 13.6 heading, off-by-one Locked-decisions summary, and
65
+ the Lite-mode Locked-31 contradiction (rule-to-test half is Full-mode only).
66
+ - Purged all airline/corporate example terms from the analysis surface (neutral
67
+ `UserProfile` domain); personal-data leak gate: 0 leaking.
68
+
69
+ ## [12.2.0] - 2026-07-21
70
+
71
+ ### Added
72
+ - **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).
73
+ - 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.
74
+ - **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.
75
+ - Config surface: `graylog` added to `keychainMapping` + `hosts` in `schemas/prefs.schema.json` and `preferences-template.json`; keychain doc row (non-critical service). Extraction branch added to `lib/context-link-extractor.sh`. Phase-0 deep-fetch step (`state.graylogContext`) + Phase-1 dispatch row + external-context-injection dispatch row. `multi-agent:setup` prompts for the Graylog host (like the Jira host) and discovers the token key. Offline smoke coverage in `scripts/smoke-fetchers-offline.sh`.
76
+
17
77
  ## [12.1.1] - 2026-07-21
18
78
 
19
79
  ### Changed
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mmerterden/multi-agent-pipeline",
3
- "version": "12.1.1",
3
+ "version": "12.3.0",
4
4
  "description": "8-phase AI development pipeline with full orchestration on Claude Code and Copilot 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",
@@ -20,15 +20,15 @@ These decisions are settled. Do not surface them as `AskUserQuestion` items, do
20
20
 
21
21
  ### Index by category (v9.1.0+)
22
22
 
23
- Browse-friendly grouping of the 30 Locked decisions. Numbering stays canonical (matches the list below); the index is read-only navigation.
23
+ Browse-friendly grouping of the 31 Locked decisions. Numbering stays canonical (matches the list below); the index is read-only navigation.
24
24
 
25
25
  | Category | Decisions | Concern |
26
26
  |---|---|---|
27
27
  | **A. Governance** | 1, 5, 6, 7, 10, 26, 27 | Run-level process rules: one feature per run, default output, auto-commit ban, punctuation policy, output picker timing, Pass B preview, evidence digest cache |
28
28
  | **B. Citation and Evidence** | 3, 4, 8, 11, 24, 30 | Every fact in the doc traces back to a source: citation discipline, forward-looking spec, standards binding, repo-evidence reuse-first, Pass B footnote mandatory, analysis self-contained (pipeline-wide) |
29
- | **C. Output Format and Structure** | 2, 9, 13, 14, 16, 17, 20, 21, 25 | How the document is laid out: section omission rule, per-platform output split, Gherkin user stories, Goals + Non-Goals paired, Files-to-Add tag, API response variants exhaustive, 8-locale full coverage, References at the bottom, Lite mode |
29
+ | **C. Output Format and Structure** | 2, 9, 13, 14, 16, 17, 20, 21, 25 | How the document is laid out: section omission rule, per-platform output split, Gherkin user stories, Goals + Non-Goals paired, Files-to-Add tag, API response variants exhaustive, localization mode (ownership-aware), References at the bottom, Lite mode |
30
30
  | **D. Design Source and Pipeline Architecture** | 12, 22, 23 | Where design comes from and how the pipeline renders: Figma 3-tier access (BLOCKING), platform-agnostic template + Pass B render, convention extraction (Phase 1c) |
31
- | **E. UI, Variant, and Test Coverage** | 15, 18, 19, 28, 29 | UI artefact rules: SVG default for new assets, screenshots embedded, all Figma variants drilled, SwiftUI Preview block (iOS), variant usage explicit |
31
+ | **E. UI, Variant, and Test Coverage** | 15, 18, 19, 28, 29, 31 | UI artefact rules: SVG default for new assets, screenshots embedded, all Figma variants drilled, SwiftUI Preview block (iOS), variant usage explicit, business-rule to acceptance-criterion to test traceability |
32
32
 
33
33
  When citing a Locked decision in code or docs, prefer `Locked <n> (<short label>)` form so the category is inferable (e.g. `Locked 30 (analysis self-contained, category B)`).
34
34
 
@@ -36,7 +36,7 @@ When citing a Locked decision in code or docs, prefer `Locked <n> (<short label>
36
36
 
37
37
  1. **One feature per run.** Every Figma URL, Confluence page, Jira ID, and Standards source the user supplies belongs to the **same feature**. The command never asks "which feature is this for?" or "which URL is primary?". Mixed inputs covering multiple features are treated as user error: surface the conflict, stop, and ask the user to split into separate runs.
38
38
  2. **Section omission rule.** Sections with zero evidence are dropped entirely; no `TBD` placeholder section. Numbering remains sequential `1..N` over the rendered set.
39
- 3. **Citation discipline.** Every quoted UI string, endpoint path, error code, or analytics event name in Sections 2-4 must carry an inline citation: `[Figma <nodeId>]` (MCP) or `[figma-export: <project-slug>/<screen-slug>:<nodeId>]` (local source) for design strings; `file:line` for repo evidence; `Confluence:<pageId>:<heading-slug>` for spec text. Uncited quotes are downgraded to `[label TBD - see Open Questions]` and a row is added to Section 7 Risks. Subagent prose and Code Connect snippets are not citations.
39
+ 3. **Citation discipline.** Every quoted UI string, endpoint path, error code, or analytics event name in Sections 2-4 must carry an inline citation: `[Figma annotation <nodeId>]` for copy taken from a Dev Mode annotation, `[Figma <nodeId>]` (MCP) or `[figma-export: <project-slug>/<screen-slug>:<nodeId>]` (local source) for design strings; `file:line` for repo evidence; `Confluence:<pageId>:<heading-slug>` for spec text. **Annotation-as-copy precedence:** when the project's `figma-config` has `annotations.enabled` and a node carries a Dev Mode annotation, that annotation is the authoritative copy for the node and the visible text layer is treated as a placeholder; cite the annotation, not the layer text. Never invent copy - blank beats a guess; a node whose annotation has the base language but is missing a target language emits a Section 20 (Risks) row rather than a fabricated value. Uncited quotes are downgraded to `[label TBD - see Open Questions]` and a row is added to Section 7 Risks. Subagent prose and Code Connect snippets are not citations.
40
40
  4. **The spec is forward-looking.** Section bodies describe the new feature as drawn / specified. Findings that exist only in legacy code or the existing branch appear as `> Legacy reference: <text> (file:line)` blockquotes inside the relevant section, never as the lead sentence or a primary table row. A legacy-only finding with no forward counterpart goes to Section 7 Risks as a decision item: "current code does X; should the new feature keep, change, or drop this?".
41
41
  5. **Output default = Local file.** The Phase 3.5 output picker keeps `Local file` pre-selected. Confluence and Jira outputs are never default-selected (see `analysis-output-confluence-on-request` memory).
42
42
  6. **No auto-commit.** Even after a successful local write or Confluence post, the command never runs `git add` or `git commit`. The user does that themselves if they want.
@@ -53,7 +53,9 @@ When citing a Locked decision in code or docs, prefer `Locked <n> (<short label>
53
53
  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.
54
54
  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.
55
55
  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.
56
- 20. **Localization 8-locale full coverage.** Section 10 new keys carry filled cells for all eight supported locales: TR, EN, AR, DE, ES, FR, RU, ZH. Placeholder values `[bekleniyor: çeviri ekibi]` / `[pending: translation team]` are accepted as a soft state and the dispatch report flags `i18n_pending: <count>` as a blocker. Empty cells are rejected outright.
56
+ 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.
57
+ - **`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.
58
+ - **`externally-owned`**: per-locale values are owned by the authoring system named in `localization.authoringPipeline` and MUST NOT be hand-filled. Section 10 lists `key | status | copy source | base value | ownership` only; the gate becomes "the `localization.baseLanguage` value is present (sourced from the Figma annotation, Locked 3) AND the ownership reference is cited". A key missing its base-language value is a blocker (it renders the raw key at runtime). Fabricated per-locale values are rejected.
57
59
  21. **References at the bottom.** The user-supplied input table is rendered as Section 21 References, not as Section 1. Readers see goals, flow, and design before sources.
58
60
  22. **Platform-agnostic template + Pass B render.** The template (`$HOME/.claude/multi-agent-refs/analysis-template.md`) describes concepts (state holder, view, navigator, use case, repository, DTO, state model, DI register, localization key, accessibility identifier, test method) without platform-specific class names. Pass B (Phase 2b) projects each concept onto the selected platform using conventions extracted at Phase 1c.
59
61
  23. **Convention extraction mandatory (Phase 1c).** After Phase 1b repo evidence, Phase 1c extracts seven pattern groups (folder structure, class naming, UI state model, test method naming, accessibility identifier, localization key, DI registration) per selected repo via `~/.claude/lib/extract-conventions.sh`. Output lands in `state.analysisSpec.evidence.conventions[<repo>]` with confidence levels (high / medium / low / none) and evidence file citations.
@@ -63,15 +65,16 @@ When citing a Locked decision in code or docs, prefer `Locked <n> (<short label>
63
65
  27. **Evidence digest caches Phase 1b and 1c.** `evidence_digest = sha256(featureName || sorted(platforms) || repoEvidence.summary || conventions.summary)`. When the same feature name is invoked again against the same set of repos and the digest matches, Phase 1b and 1c are skipped and the cached `evidence.repoEvidence` / `evidence.conventions` is reused. Cache TTL is 24 hours; manual invalidation via `--no-cache` flag.
64
66
  28. **SwiftUI Preview block mandatory (iOS projection, SwiftUI only).** When the iOS file is produced AND the affected view is a SwiftUI view (detected via `import SwiftUI` + `: View` protocol conformance in `evidence.repoEvidence[<repo>].buckets.uiComponents`), Section 13.6 renders a Preview block table covering at minimum: canonical default (LTR Light), Dark, RTL, Dynamic Type accessibilityLarge, and one error variant. Loading state and edge-case variants are added when distinct from canonical. UIKit-only features (no SwiftUI view artefact) drop Section 13.6 with note `(N/A: UIKit-only feature)`. Preview macro convention (`#Preview` for Swift 5.9+ vs legacy `PreviewProvider`) is read from `evidence.conventions[<repo>].previewMacro`. Each Preview variant listed in Section 13.6 must have a matching row in Section 15.2 Snapshot Tests; a Preview without a snapshot row triggers a Section 20 Risk.
65
67
  29. **Variant usage explicit and bounded.** Section 6 inventory rows list which variants this feature consumes per component (concrete enum case + bool value). New Section 6.X (Variant Usage Matrix) catalogues the full variant axis vs. used subset with a rationale per excluded variant. Sections 13.6 (Preview) and 15.2 (Snapshot) cover only the used subset; expanding the variant set requires updating Section 6.X first.
66
- 30. **Analysis as self-contained design bridge - no MCP outside analysis phase (BLOCKING, pipeline-wide, v9.0.0; legacy soft-skip v9.1.0).** The analysis document is the sole design source for every downstream phase. After Phase 1 of `/multi-agent:analysis` produces `analysis/<feature>-<platform>.md`, Phase 2 Planning, Phase 3 Dev, Phase 4 Review, Phase 5 Test, Phase 6 Commit, and Phase 7 Report consume only the analysis document plus repo Code Connect mappings (`*.figma.swift` / `*.figma.kt`). Calling `mcp__claude_ai_Figma__*`, hitting `api.figma.com`, or fetching a `figma.com/design/...` URL during Phase 2+ is a violation. Applies to every mode that runs Phase 2+: `/multi-agent`, `/multi-agent:autopilot`, `/multi-agent:local`, `/multi-agent:local-autopilot`, `/multi-agent:dev`, `/multi-agent:dev-autopilot`, `/multi-agent:dev-local`, `/multi-agent:dev-local-autopilot`. Hard requirement (v9.0.0): Phase 2 Pre-flight and Phase 3 Pre-flight (BLOCKING) abort the run when the analysis document is missing. **Legacy soft-skip (v9.1.0+):** existing v2 analyses (`template_version: v2`) emit `WARN: legacy v2 analysis doc detected; v3 expected. Re-run /multi-agent:analysis to regenerate. Continuing with reduced binding strength.` and the run continues when `prefs.global.legacyV2AnalysisAllowed == true` OR env `MULTI_AGENT_LEGACY_V2_ANALYSIS=allow` is set. The soft-skip degrades Pass B footnote enforcement to warning level and skips Phase 1c convention extraction (no `conventions[]` data in v2 docs). The escape hatch is removed in v9.2.0; users must regenerate v3 docs by then. Smoke gate `pipeline/scripts/smoke-no-mcp-in-dev-phases.sh` reads `state.telemetry.mcpCalls[]` and fails on any entry with `phase >= 2`. Halt condition: if a downstream phase needs design information not present in the analysis document, the run halts and the user re-runs `/multi-agent:analysis` to regenerate. Memory: `[[mcp-only-in-analysis]]`. Generic rule rationale and access matrix: see `pipeline/rules/figma-pipeline.md` "MUST: No MCP outside analysis phase".
68
+ 30. **Analysis as self-contained design bridge - no MCP outside analysis phase (BLOCKING, pipeline-wide, v9.0.0; legacy soft-skip v9.1.0).** The analysis document is the sole design source for every downstream phase. After Phase 1 of `/multi-agent:analysis` produces `analysis/<feature>-<platform>.md`, Phase 2 Planning, Phase 3 Dev, Phase 4 Review, Phase 5 Test, Phase 6 Commit, and Phase 7 Report consume only the analysis document plus repo Code Connect mappings (`*.figma.swift` / `*.figma.kt`). Calling `mcp__claude_ai_Figma__*`, hitting `api.figma.com`, or fetching a `figma.com/design/...` URL during Phase 2+ is a violation. Applies to every mode that runs Phase 2+: `/multi-agent`, `/multi-agent:autopilot`, `/multi-agent:local`, `/multi-agent:local-autopilot`, `/multi-agent:dev`, `/multi-agent:dev-autopilot`, `/multi-agent:dev-local`, `/multi-agent:dev-local-autopilot`. Hard requirement (v9.0.0): Phase 2 Pre-item and Phase 3 Pre-item (BLOCKING) abort the run when the analysis document is missing. **Legacy soft-skip (v9.1.0+):** existing v2 analyses (`template_version: v2`) emit `WARN: legacy v2 analysis doc detected; v3 expected. Re-run /multi-agent:analysis to regenerate. Continuing with reduced binding strength.` and the run continues when `prefs.global.legacyV2AnalysisAllowed == true` OR env `MULTI_AGENT_LEGACY_V2_ANALYSIS=allow` is set. The soft-skip degrades Pass B footnote enforcement to warning level and skips Phase 1c convention extraction (no `conventions[]` data in v2 docs). The escape hatch is removed in v9.2.0; users must regenerate v3 docs by then. Smoke gate `pipeline/scripts/smoke-no-mcp-in-dev-phases.sh` reads `state.telemetry.mcpCalls[]` and fails on any entry with `phase >= 2`. Halt condition: if a downstream phase needs design information not present in the analysis document, the run halts and the user re-runs `/multi-agent:analysis` to regenerate. Memory: `[[mcp-only-in-analysis]]`. Generic rule rationale and access matrix: see `pipeline/rules/figma-pipeline.md` "MUST: No MCP outside analysis phase".
69
+ 31. **Business-rule to acceptance-criterion to test traceability (AI + human spine).** The analysis is a development handoff that both an AI implementer and a human reviewer must act on, so it is bound by one shared-ID vocabulary. Every business rule carries a stable id `BR-<slug>-NN` (Section 4.4). Each rule maps to at least one acceptance criterion written Given / When / Then (binary - two readers must not be able to disagree on pass/fail). Each acceptance criterion maps to unit-test scenarios in Section 15.1, one row per case across happy / boundary / error / empty-nil (enumerate at least the failure modes; agents hallucinate error handling when it is omitted). The same ids thread onward: Section 15.6 UI-test flows reference the `BR-` ids and use stable selectors (accessibilityIdentifier / testTag), Section 16 accessibility items reuse those identifiers, Section 11 analytics events cite their triggering rule or story, and Section 5/7 layout cells carry token + Figma node refs. Never invent copy or values (blank beats a guess; a missing source becomes a Section 20 Open Question). **Mode-aware gate:** in Full mode a business rule with no acceptance criterion, or an acceptance criterion with no Section 15.1 scenario, fails the dispatch gate. In **Lite mode Section 15 is not rendered**, so the rule-to-test half does not apply - Section 4.4 still lists each rule with its Given/When/Then acceptance criterion (the acceptance criterion is itself the testable statement), and the 15.1 mapping is deferred to whenever the feature is later analyzed in Full or implemented via `/multi-agent:dev`. The rule-to-acceptance-criterion half always holds, in both modes.
67
70
 
68
71
  ## Input
69
72
 
70
- - `$ARGUMENTS` - optional analysis name (e.g. `"FlightStatus"`). If empty, asked at Phase 0 Step 1. Stored internally as `state.analysisSpec.featureName` for backward compatibility.
73
+ - `$ARGUMENTS` - optional analysis name (e.g. `"UserProfile"`). If empty, asked at Phase 0 Step 1. Stored internally as `state.analysisSpec.featureName` for backward compatibility.
71
74
 
72
75
  ## Template
73
76
 
74
- v3 template at `$HOME/.claude/multi-agent-refs/analysis-template.md`. Full mode renders 23 main sections + 3 footer sections (Glossary, Changelog, References-as-footer per Locked 21). Lite mode renders 7 main sections (1 Summary, 2 Goals + Non-Goals, 4 User Stories, 9 API Contracts, 13 Architecture, 14 Files to Add, 21 References) plus optional 23 Changelog. Section omission rule (Locked 2): zero-evidence sections drop entirely; numbering re-flows to stay sequential `1..N` over the rendered set.
77
+ v3 template at `$HOME/.claude/multi-agent-refs/analysis-template.md`. Full mode renders up to 23 main sections + footer, minus any dropped by the omission table. The analysis doc is a development handoff, so low-signal sections are default-drop even in Full: **19 Alternatives** (render only for a real 2+-option architectural decision), **22 Glossary** (render only on request or >5 unfamiliar domain terms), and **18 Rollout** (compact checklist only, dropped when the pipeline's own commit/PR/rollout phase covers it). Lite mode renders 7 main sections (1 Summary, 2 Goals + Non-Goals, 4 User Stories, 9 API Contracts, 13 Architecture, 14 Files to Add, 21 References) plus optional 23 Changelog. Section omission rule (Locked 2): zero-evidence and default-drop sections omit entirely; numbering re-flows to stay sequential `1..N` over the rendered set.
75
78
 
76
79
  Numbering is plain Arabic numerals: `## 1. Geliştirme Özeti` / `## 1. Summary`, `## 2. Hedefler ve Karşı Hedefler` / `## 2. Goals and Non-Goals`. No special section characters; the section sign codepoint (U+00A7) is banned by `feedback_no-section-sign`.
77
80
 
@@ -83,7 +86,7 @@ The template is platform-agnostic (Locked 22). It speaks in concepts (state hold
83
86
 
84
87
  Sequential `AskUserQuestion` chain. Each answer is written to state under `state.analysisSpec.*`.
85
88
 
86
- **Step narration (required, per `$HOME/.claude/multi-agent-refs/picker-contract.md`)**: the chain length is known up front - 1 analysis-name + 1 account + 1 platform + 1 repo-round per selected platform + 1 input-URL batch (so a single-platform run is 5 steps; account is skipped for local-only flows, which lowers the total). Before each step's `AskUserQuestion`, print the narrator line `<localized: "Step <i>/<n>: <what this step decides>">` in `outputLanguage`. Auto-resolved steps (single account, local-only) still print their breadcrumb with the resolution noted. This is what makes the picker show, step by step, what it is doing.
89
+ **Step narration (required, per `$HOME/.claude/multi-agent-refs/picker-contract.md`)**: the chain length is known up front - 1 analysis-name + 1 account + 1 platform + 1 repo-round per selected platform + 1 input-URL batch + 1 coverage-options batch (so a single-platform run is 6 steps; account is skipped for local-only flows, which lowers the total). Before each step's `AskUserQuestion`, print the narrator line `<localized: "Step <i>/<n>: <what this step decides>">` in `outputLanguage`. Auto-resolved steps (single account, local-only) still print their breadcrumb with the resolution noted. This is what makes the picker show, step by step, what it is doing.
87
90
 
88
91
  #### Step 0 - Language resolution (BLOCKING, runs before any picker)
89
92
 
@@ -112,6 +115,8 @@ options:
112
115
  ```
113
116
  Empty submit → re-ask. Result: `state.analysisSpec.platforms[]`.
114
117
 
118
+ **Platform coverage = provided platforms.** The analysis renders exactly one per-platform file (Locked 9) for each platform selected here and given a repo in Step 4: select iOS only -> a single iOS document; select iOS + Android -> one iOS and one Android document, each projected through that repo's own conventions (Phase 1c) and its own Code Connect index (Phase 1b.1, discovered from that repo's `*.figma.swift` / `*.figma.kt`). Do not analyze a platform the user did not select, and do not drop a selected platform that has a repo.
119
+
115
120
  #### Step 4 - Repo multi-select per platform
116
121
 
117
122
  For each selected platform, run one AskUserQuestion round. Reuse `_dev-context.md` logic:
@@ -167,7 +172,7 @@ Q6: header="Firebase"
167
172
  - label: "No Firebase input"
168
173
  - label: "Auto-detect from repo"
169
174
  description: "Greps Analytics.logEvent / firebaseAnalytics.logEvent / logEvent(analytics, ...) call sites in the selected repos and extracts event names"
170
- (Other: comma-separated mix of event names like 'flight.search,checkin.opened', a /path/to/events.json, or a console.firebase.google.com URL)
175
+ (Other: comma-separated mix of event names like 'profile.view,profile.opened', a /path/to/events.json, or a console.firebase.google.com URL)
171
176
  ```
172
177
 
173
178
  After submit, run `~/.claude/lib/context-link-extractor.sh` on each Other-provided string. Results are typed and written to `state.analysisSpec.contextLinks[]`. Q5 entries are additionally tagged `binding: true` so Phase 2 Section 7 treats them as hard constraints (see the Phase 1 type table and the Phase 2 Section 7 row).
@@ -179,7 +184,7 @@ After submit, run `~/.claude/lib/context-link-extractor.sh` on each Other-provid
179
184
  | Starts with `/` or `~` and ends with `.md` / `.markdown` / `.txt` | `local-file` | `Read` tool on the absolute path (tilde-expanded) |
180
185
  | Host = `github.com` AND path matches `/<owner>/<repo>/wiki/<PageName>` (no `.md`) | `wiki` | `git clone --depth 1 https://github.com/<owner>/<repo>.wiki.git /tmp/<repo>-wiki && Read /tmp/<repo>-wiki/<PageName>.md` (URL `-` to ` ` decoding) |
181
186
  | Host matches `confluence*.<tld>` AND path contains `/display/` or `/pages/viewpage.action?pageId=` | `standards-confluence` | Same fetcher as `confluence` but bucket goes to `evidence.standards[]` |
182
- | Comma-separated lowercase tokens with `.` or `_` (e.g. `flight.search,screen_view`) and no slash / no scheme | `firebase-events:names` | Scaffold rows from names alone |
187
+ | Comma-separated lowercase tokens with `.` or `_` (e.g. `profile.view,screen_view`) and no slash / no scheme | `firebase-events:names` | Scaffold rows from names alone |
183
188
  | Starts with `/` or `~`, ends with `.json`, path contains `events` or `analytics` | `firebase-events:schema` | `Read` + JSON parse `events[]` |
184
189
  | Host `console.firebase.google.com` with `/analytics/` in path | `firebase-events:console` | Reference-only; INFO warning printed, no fetch |
185
190
  | Any other `http(s)://` URL | `generic-doc` | `WebFetch` |
@@ -195,9 +200,29 @@ Q6 Auto-detect mode probe order (option 2):
195
200
  2. Generated `AnalyticsEvents/*.swift` / `AnalyticsEvents/*.kt` if present (treat each public struct conforming to `AnalyticsEvent` as one event)
196
201
  3. Repo-level `firebase-events.json` / `analytics/events.json` files
197
202
 
203
+ #### Step 5a - Coverage options (opt-in, 2 questions)
204
+
205
+ One `AskUserQuestion` call with 2 parallel yes/no questions. These are opt-INs, not source intake: an empty answer is NOT consent (per `feedback_no-inferred-defaults-from-empty-answer`) - re-ask on empty rather than defaulting silently once the picker is shown.
206
+
207
+ ```
208
+ Q1: header="UI Tests"
209
+ question: <localized: "Should the analysis include UI test scenarios (XCUITest / Compose UI test)? Optional; unit + snapshot coverage is always included.">
210
+ options:
211
+ - label: "No UI tests" -> state.analysisSpec.options.uiTests = false (default)
212
+ - label: "Write UI test scenarios" -> state.analysisSpec.options.uiTests = true
213
+
214
+ Q2: header="A11y depth"
215
+ question: <localized: "How detailed should accessibility be? Basic checklist always ships; full adds a VoiceOver / TalkBack reading-order walkthrough.">
216
+ options:
217
+ - label: "Basic checklist" -> state.analysisSpec.options.a11yDepth = "basic" (default)
218
+ - label: "Full walkthrough" -> state.analysisSpec.options.a11yDepth = "full"
219
+ ```
220
+
221
+ `options.uiTests` gates Section 15.6 (UI test flows); `options.a11yDepth` gates the Section 16 VoiceOver / TalkBack walkthrough. Both default to the lighter choice so the doc stays lean unless the user opts in.
222
+
198
223
  #### Step 5b - Repo-evidence collector (automatic, no prompt)
199
224
 
200
- Runs after Step 5 submits and before Phase 1 begins. Reads from `state.analysisSpec.repos[]`. For each repo, walks the platform whitelist and produces a 13-bucket evidence catalogue. No user interaction. Output: `state.analysisSpec.evidence.repoEvidence[<repo>]`. See Phase 1b for the bucket list and tagging rules.
225
+ Runs after Step 5a submits and before Phase 1 begins. Reads from `state.analysisSpec.repos[]`. For each repo, walks the platform whitelist and produces a 13-bucket evidence catalogue. No user interaction. Output: `state.analysisSpec.evidence.repoEvidence[<repo>]`. See Phase 1b for the bucket list and tagging rules.
201
226
 
202
227
  #### Step 6 - REMOVED in v8.10.0
203
228
 
@@ -211,7 +236,7 @@ For each entry in `state.analysisSpec.contextLinks[]`, fan out by `type`. Entrie
211
236
  |------|---------|---------------|
212
237
  | swagger | `~/.claude/lib/fetch-swagger.sh <url>` | `state.analysisSpec.evidence.swagger[]` |
213
238
  | confluence | `~/.claude/lib/fetch-confluence.sh <url>` | `state.analysisSpec.evidence.confluence[]` |
214
- | figma | **MUST** establish the Figma access tier per Locked decision #12. Tier 1 (preferred): call `mcp__claude_ai_Figma__get_design_context` (primary), `mcp__claude_ai_Figma__get_screenshot`, `mcp__claude_ai_Figma__get_metadata` for every node ID; auth failure runs `authenticate` + `complete_authentication` then retries. Tier 2 (fallback): `GET https://api.figma.com/v1/files/{fileKey}/nodes?ids={nodeId}` for design context and `GET /v1/images/{fileKey}?ids={nodeId}&format=png&scale=2` for screenshots, with PAT from `~/.claude/lib/credential-store.sh get <logical-key>` (logical key = `prefs.global.keychainMapping.figma_pat`); canonical component resolves via repo `*.figma.swift` / `*.figma.kt` mapping. Tier 3 (last resort): user-attached screenshot, `codeConnectSnippets: []`, forced Open Question. Capture each `CodeConnectSnippet` block verbatim when on Tier 1 (component name + modifier chain). Persist `state.figmaAccess.tier`. See Locked decision #12 and `pipeline/rules/figma-pipeline.md` "MUST: Figma access - 3-tier fallback chain". | `state.analysisSpec.evidence.figma[]` (records: `nodeId`, `screenshotUrl`, `codeConnectSnippets[]`, `tokens[]`, `textLayers[]`, `tier`) |
239
+ | figma | **MUST** establish the Figma access tier per Locked decision #12. Tier 1 (preferred): call `mcp__claude_ai_Figma__get_design_context` (primary), `mcp__claude_ai_Figma__get_screenshot`, `mcp__claude_ai_Figma__get_metadata` for every node ID; auth failure runs `authenticate` + `complete_authentication` then retries. Tier 2 (fallback): `GET https://api.figma.com/v1/files/{fileKey}/nodes?ids={nodeId}` for design context and `GET /v1/images/{fileKey}?ids={nodeId}&format=png&scale=2` for screenshots, with PAT from `~/.claude/lib/credential-store.sh get <logical-key>` (logical key = `prefs.global.keychainMapping.figma_pat`); canonical component resolves via repo `*.figma.swift` / `*.figma.kt` mapping. Tier 3 (last resort): user-attached screenshot, `codeConnectSnippets: []`, forced Open Question. Capture each `CodeConnectSnippet` block verbatim when on Tier 1 (component name + modifier chain). **Annotation capture (when the project `figma-config` has `annotations.enabled`):** on Tier 1, walk the `annotations[]` the `get_design_context` payload returns for each node (read `label` / `labelMarkdown`); on Tier 2, run `~/.claude/lib/fetch-figma-annotations.sh --file-key <fileKey> --node-id <ids> --lang-prefixes <config.annotations.langPrefixes>`. Parse each annotation by the configured language prefixes (prefixed `TR:/EN:` wins, else line1/line2, else single) and persist to `annotations[]`. The annotation is the authoritative copy for its node (Locked 3); the visible text layer is a placeholder. Persist `state.figmaAccess.tier`. See Locked decision #12 and `pipeline/rules/figma-pipeline.md` "MUST: Figma access - 3-tier fallback chain". | `state.analysisSpec.evidence.figma[]` (records: `nodeId`, `screenshotUrl`, `codeConnectSnippets[]`, `tokens[]`, `textLayers[]`, `annotations[]`, `tier`; see `analysis-spec.schema.json`) |
215
240
  | jira | `gh api` or Jira REST API for issue summary | `state.analysisSpec.evidence.jira[]` |
216
241
  | generic-doc | WebFetch on demand | `state.analysisSpec.evidence.confluence[]` (generic bucket) unless `binding: true` -> `evidence.standards[]` |
217
242
  | `local-file` | `Read` (no fetch) on tilde-expanded absolute path | `state.analysisSpec.evidence.standards[]` |
@@ -248,7 +273,7 @@ find "$REPO_PATH" -name '*.figma.swift' -o -name '*.figma.kt'
248
273
 
249
274
  Results go to `state.analysisSpec.evidence.repo[]` (presence flags only).
250
275
 
251
- **Confluence-embedded API table detection**: if a Confluence page body contains `Request Path` / `Service Name` / `Response Body` table columns, set `embeddedApiTable=true` and parse endpoints using the pattern ported from `~/.claude/skills/checkin-confluence-mirror/sync.py`. Do not also trigger a separate Swagger fetch.
276
+ **Confluence-embedded API table detection**: if a Confluence page body contains `Request Path` / `Service Name` / `Response Body` table columns, set `embeddedApiTable=true` and parse the endpoints from those columns (a project may supply its own parser for this). Do not also trigger a separate Swagger fetch.
252
277
 
253
278
  ### Phase 1b - Repo-evidence collector (parallel, per repo)
254
279
 
@@ -269,7 +294,7 @@ Skip dirs (always): `.build`, `DerivedData`, `Pods`, `node_modules`, `.next`, `b
269
294
 
270
295
  ```bash
271
296
  slugs=$(echo "$featureName" | tr '[:upper:]' '[:lower:]' | sed 's/[^a-z0-9]/ /g')
272
- # e.g. FlightStatus -> "flight status flightstatus"
297
+ # e.g. UserProfile -> "user profile userprofile"
273
298
  grep -rilE "$slugs" $WHITELIST --include="*.swift" --include="*.kt" --include="*.ts" --include="*.tsx" --include="*.py" --include="*.go" | head -200 > $CANDIDATES
274
299
  ```
275
300
 
@@ -307,7 +332,7 @@ If `wc -l < $CANDIDATES` exceeds 200, record `fetchWarnings += "feature-name too
307
332
  {
308
333
  "buckets": {
309
334
  "services": [
310
- {"name": "FlightStatusService", "file": "Domains/FlightStatus/Services/FlightStatusService.swift", "line": 12, "tag": "direct-match"},
335
+ {"name": "UserProfileService", "file": "Domains/UserProfile/Services/UserProfileService.swift", "line": 12, "tag": "direct-match"},
311
336
  {"name": "LoggingService", "file": "Common/Logging/LoggingService.swift", "line": 8, "tag": "cross-cutting"}
312
337
  ]
313
338
  },
@@ -403,7 +428,7 @@ synthesizedSections = {
403
428
  |---------|------------------|
404
429
  | 1. Scope | Always present. Derive in-scope / out-of-scope, audience from Jira summary + Confluence title + feature name. LLM inference allowed. Shared across all per-platform files verbatim. |
405
430
  | 2. Design | If `evidence.figma[]` is empty AND no `evidence.repoEvidence[*].buckets.uiComponents` direct-match → `byPlatform[*]` = null. Otherwise produce frame gallery (shared) + per-platform component inventory (rows from `evidence.repoEvidence[<repo>].buckets.uiComponents`). |
406
- | 3. Localization | If both Figma text layers and `evidence.repoEvidence[*].buckets.localizationKeys` are empty → `byPlatform[*]` = null. Otherwise produce the key table; per-platform `Source` column derives from the platform's localization file convention. Reuse the 8-locale set (ar, de, en, es, fr, it, ru, tr) with standard localization-key naming (RTL for ar). |
431
+ | 3. Localization | If both Figma annotations/text layers and `evidence.repoEvidence[*].buckets.localizationKeys` are empty → `byPlatform[*]` = null. Otherwise produce the key table per the project `localization.ownership` mode (Locked 20): `in-repo` fills the configured locale set (default `ar, de, en, es, fr, it, ru, tr`, RTL for ar); `externally-owned` lists key + status + copy source + base value and defers per-locale values. Base copy is sourced from the Figma annotation when present (Locked 3). |
407
432
  | 4. API Contracts | If `evidence.swagger[]` is empty AND no Confluence embedded API table AND no `evidence.repoEvidence[*].buckets.services` direct-match → null. Otherwise produce endpoint summary + per-endpoint tables (shared verbatim across files). |
408
433
  | 5. Deeplink / Push | Per-platform: iOS uses Universal Links / `UNUserNotificationCenter`; Android uses `intent-filter` / FCM; Frontend uses web URL routing; Backend file omits this section entirely. |
409
434
  | 6. Business + Tests | If sections 2 and 4 are both `null` AND `evidence.firebase[]` is empty → null. Otherwise produce use-case + mock stubs + per-platform test skeletons + shared Firebase events table. Reuse Red-Green-Refactor naming from `pipeline/rules/tdd.md`. |
@@ -420,13 +445,13 @@ Convention preview - Pass B will render with:
420
445
 
421
446
  | Concept | iOS | Android |
422
447
  |---|---|---|
423
- | Module folder | Domains/Checkin/.../Screens/PassengerAndFlightSelection/ ^[C1 high] | feature/checkin/.../passengerflight/ ^[C1 high] |
424
- | State holder | PassengerFlightViewModel ^[C2 high: 8 examples] | PassengerFlightViewModel ^[C2 high: 5 examples] |
425
- | State model | sealed enum PassengerFlightUIState ^[C3 high] | sealed interface PassengerFlightUiState ^[C3 high] |
448
+ | Module folder | Domains/Profile/.../Screens/ProfileEditor/ ^[C1 high] | feature/profile/.../userprofile/ ^[C1 high] |
449
+ | State holder | UserProfileViewModel ^[C2 high: 8 examples] | UserProfileViewModel ^[C2 high: 5 examples] |
450
+ | State model | sealed enum UserProfileUIState ^[C3 high] | sealed interface UserProfileUiState ^[C3 high] |
426
451
  | Test naming | @Test func scenario_expected() ^[C4 medium: 4 examples] | fun scenario_expectedBehavior() ^[C4 high] |
427
- | Identifier | passengerFlight.continueButton ^[C5 high] | passengerFlightContinueButton ^[C5 medium] |
428
- | Localization key | PassengerFlight.ContinueButton ^[C6 high] | passenger_flight_continue_button ^[C6 high] |
429
- | DI | PassengerFlightDependencyConfigurator ^[C7 high] | PassengerFlightModule (Hilt) ^[C7 fallback: defaults] |
452
+ | Identifier | userProfile.continueButton ^[C5 high] | userProfileContinueButton ^[C5 medium] |
453
+ | Localization key | UserProfile.ContinueButton ^[C6 high] | user_profile_continue_button ^[C6 high] |
454
+ | DI | UserProfileDependencyConfigurator ^[C7 high] | UserProfileModule (Hilt) ^[C7 fallback: defaults] |
430
455
 
431
456
  Confidence summary:
432
457
  iOS: 7/7 high, 0 medium, 0 low, 0 fallback
@@ -465,7 +490,7 @@ For each `platform` in `state.analysisSpec.platforms[]`:
465
490
  - `frontend` → `evidence.standards[]` entries matching `react`, `vue`, `next`, `sveltekit` → `~/.claude/rules/code-style.md`
466
491
  2. **Apply per-platform omission rules.** Backend-only file drops Sections 5, 6, 7, 8, 16. Frontend with no UI inventory still keeps 5 (UI exists in code). Sections 1, 2, 4, 9, 13, 14, 20, 21 always present per Locked decision 2 + 13.
467
492
  3. **Resolve mode.** If user passed `--lite` → Lite. If user passed `--full` → Full. Otherwise use `state.analysisSpec.liteModeAuto`. Lite mode renders only Sections 1, 2, 4, 9, 13, 14, 21 plus optional 23.
468
- 4. **Produce YAML front-matter header** (see `$HOME/.claude/multi-agent-refs/analysis-template.md`). Include `mode: full | lite`.
493
+ 4. **Produce YAML front-matter header** (see `$HOME/.claude/multi-agent-refs/analysis-template.md`). Include `mode: full | lite`, plus `ui_tests: <state.analysisSpec.options.uiTests | false>` and `a11y_depth: <state.analysisSpec.options.a11yDepth | basic>` so the pre-dispatch validator can enforce the opt-in coverage (15.6 present when ui_tests, 16.2 walkthrough present when a11y_depth is full).
469
494
  5. **Read conventions for this platform's repo.** For each cell Pass B fills in Section 13 and in any per-platform projection (Sections 5, 6, 7, 8, 10, 11, 13, 14, 15, 16, 17), read `state.analysisSpec.evidence.conventions[<repo>].<field>` and emit the value with a footnote (Locked 24). If `conventionOverrides` has an entry for that field, use the override and footnote with `^[user-override: <reason>]` instead of evidence path.
470
495
  6. **Concatenate non-null sections in canonical order.** Numbering stays sequential `1..N` over the rendered set (omitted sections do not create gaps).
471
496
  7. **Schema validation** on the per-platform spec object:
@@ -496,9 +521,9 @@ For each `platform` in `state.analysisSpec.platforms[]`:
496
521
  5. **Surface the draft tree to the user**:
497
522
  ```
498
523
  Drafts ready (3 files, 6.4 KB):
499
- /tmp/analysis-FlightStatus-20260514T1015/FlightStatus-ios.md
500
- /tmp/analysis-FlightStatus-20260514T1015/FlightStatus-android.md
501
- /tmp/analysis-FlightStatus-20260514T1015/FlightStatus-backend.md
524
+ /tmp/analysis-UserProfile-20260514T1015/UserProfile-ios.md
525
+ /tmp/analysis-UserProfile-20260514T1015/UserProfile-android.md
526
+ /tmp/analysis-UserProfile-20260514T1015/UserProfile-backend.md
502
527
  ```
503
528
  User can inspect drafts before choosing output destinations in Phase 3.5.
504
529
 
@@ -524,6 +549,16 @@ Result: `state.analysisSpec.outputs.requested[]`.
524
549
 
525
550
  ### Phase 4 - Dispatch & report
526
551
 
552
+ **Pre-dispatch gate (BLOCKING).** Before writing to any destination, run the deterministic doc validator on every per-platform draft:
553
+
554
+ ```bash
555
+ for f in /tmp/analysis-<feature-slug>-<ts>/*.md; do
556
+ node "$HOME/.claude/scripts/validate-analysis-doc.mjs" "$f" || GATE_FAILED=1
557
+ done
558
+ ```
559
+
560
+ `validate-analysis-doc.mjs` enforces the mechanically-checkable Locked decisions on the emitted markdown itself (front-matter completeness, never-omitted sections per Locked 2, humanizer punctuation per Locked 7, and Full-mode business-rule traceability per Locked 31). Any ERROR blocks dispatch: fix the draft and re-validate. Warnings are advisory (run with `--strict` to treat them as blocking). This turns the "fails the dispatch gate" prose into a real, model-independent check.
561
+
527
562
  Iterate `state.analysisSpec.outputs.requested`. For each target:
528
563
 
529
564
  | Target | Action |
@@ -566,9 +601,9 @@ Sections (per platform):
566
601
  Backend: [1 Scope, 4 API, 6 Business+Tests, 7 Dev Plan] (Sections 2/3/5 omitted - no UI)
567
602
 
568
603
  Outputs:
569
- - analysis/FlightStatus-ios.md (my-ios-app)
570
- - analysis/FlightStatus-android.md (my-android-app)
571
- - analysis/FlightStatus-backend.md (my-backend-api)
604
+ - analysis/UserProfile-ios.md (my-ios-app)
605
+ - analysis/UserProfile-android.md (my-android-app)
606
+ - analysis/UserProfile-backend.md (my-backend-api)
572
607
  - Confluence (3 pages):
573
608
  https://{CONFLUENCE_HOST}/pages/viewpage.action?pageId=... (iOS)
574
609
  https://{CONFLUENCE_HOST}/pages/viewpage.action?pageId=... (Android)
@@ -634,7 +669,8 @@ When `phase == "cancelled_at_pass_b_preview"`:
634
669
  | `pipeline/rules/tdd.md` | Section 15 test naming |
635
670
  | `$HOME/.claude/multi-agent-refs/analysis-template.md` | Template master copy + language matrix (v3 - 23 main sections + 3 footer) |
636
671
  | `$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 |
637
- | `~/.claude/skills/checkin-confluence-mirror/sync.py` | Confluence-embedded API table parser pattern |
672
+ | `$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) |
673
+ | a project-supplied Confluence-embedded API-table parser (optional) | Parse endpoints from a Confluence page's Request Path / Service Name / Response Body table columns |
638
674
  | `~/<project>-Standards.md` | Canonical home-dir standards reference (auto-detected at Q5 option 2; exact filename from `prefs.projects[<project>].standardsFile`) |
639
675
  | `~/.claude/rules/*.md` | Fallback rules when `evidence.standards[]` is empty |
640
676
 
@@ -657,7 +693,7 @@ Token miss handling: surface a single line `WARN: Confluence token not configure
657
693
  - The minimum possible output (per per-platform file) is `1. Scope` + `7. Development Plan` (both always-present).
658
694
  - If Confluence or Jira POST returns 401 / 403 during Phase 4, surface the error and offer Local fallback (the local drafts in `/tmp/` are still on disk; copying them into the repo working tree is always available).
659
695
  - The `analysis/` directory is not in `.gitignore`; the user can `git add analysis/` manually. No auto-commit.
660
- - **Per-platform file naming**: `analysis/<feature>-<platform>.md`. The `<platform>` slug is lowercase, one of `ios | android | backend | frontend`. The `<feature>` slug preserves the user's feature name with whitespace replaced by `-` (e.g. `Flight Status` -> `FlightStatus` or `Flight-Status` depending on input shape; the renderer trims and de-duplicates dashes).
696
+ - **Per-platform file naming**: `analysis/<feature>-<platform>.md`. The `<platform>` slug is lowercase, one of `ios | android | backend | frontend`. The `<feature>` slug preserves the user's feature name with whitespace replaced by `-` (e.g. `User Profile` -> `UserProfile` or `Item-Status` depending on input shape; the renderer trims and de-duplicates dashes).
661
697
  - **Standards binding (Q5)**: When `evidence.standards[]` is non-empty, every decision in Section 7 must cite the binding source. The renderer enforces this by failing render if any Section 7 architectural decision has no `cite:` reference; the user is prompted to either tighten the source or add a Risk row acknowledging the missing citation.
662
698
  - **Firebase ingestion (Q6)**: Console URLs are never fetched (auth-gated). Only `:names` and `:schema` inputs feed `evidence.firebase[]`. Section 6 emits per-platform snippets but the events table itself is shared across all per-platform files (the rules / event vocabulary is one product invariant).
663
699
  - **Wiki access fallback chain**: Phase 1 `wiki` fetcher tries (a) `git clone .wiki.git`, (b) `gh api repos/.../contents/<file>.md`, (c) raw `WebFetch` of the page URL. Only after all three fail does the entry land in `fetchErrors[]`.
@@ -99,6 +99,7 @@ These are the RECOMMENDED key names. When creating NEW keys, use these. But exis
99
99
 
100
100
  > Multi-agent setup onboards **both** Figma tokens because the pipeline's 3-tier Figma access chain (see `pipeline/rules/figma-pipeline.md`) uses them in priority order: Tier 1 = MCP (`figma_mcp`), Tier 2 = REST PAT (`figma_pat`), Tier 3 = user screenshot fallback. Missing either token forces a downshift; missing both leaves Tier 3 as the only path.
101
101
  | `fortify` | `${USER}_Fortify_Access_Token` | `fortify` |
102
+ | `graylog` | `${USER}_Graylog_Access_Token` | `graylog` |
102
103
  | `firebase` | `${USER}_Firebase_Access_Json` | `firebase` (any variant: `sa`, `service`, `account`, `access`, `json`) |
103
104
  | `jenkins` | `${USER}_Jenkins_Access_Token` | `jenkins` |
104
105
 
@@ -180,6 +181,7 @@ Save the resolved mapping to preferences:
180
181
  "figma_pat": "${USER}_Figma_Access_Token",
181
182
  "figma_mcp": "${USER}_Figma_Mcp_Access_Token",
182
183
  "fortify": null,
184
+ "graylog": null,
183
185
  "firebase": "${USER}_Firebase_Access_Json",
184
186
  "jenkins": null
185
187
  }
@@ -331,7 +333,7 @@ Update `prefs.global.keychainMapping.{service}` with the key name.
331
333
  Update `identity.servicePatMap.{service}` with the key name.
332
334
  Update `serviceStatus.{service} = { ok: true, checkedAt: <now> }`.
333
335
 
334
- **→ Next: if `{service}` is `jira` / `confluence` / `bitbucket` / `fortify` AND the corresponding
336
+ **→ Next: if `{service}` is `jira` / `confluence` / `bitbucket` / `fortify` / `graylog` AND the corresponding
335
337
  `prefs.global.hosts.{service}` is unset, run Step 3.5 (Host Prompt) inline before
336
338
  the Auto-routing rule below. required - the pipeline cannot build API URLs without
337
339
  the host. Firebase is skipped here (host is always `console.firebase.google.com` /
@@ -352,7 +354,7 @@ This builds `platformIdentityRouting` incrementally - no separate Step 7 neede
352
354
 
353
355
  ### Step 3.5 - Host Prompt (embedded in Token Save Flow)
354
356
 
355
- **Not a standalone step** - runs inline at the end of the Token Save Flow whenever the saved token belongs to a **hosted service** (Jira, Confluence, Bitbucket, Fortify) AND the host is not yet in `prefs.global.hosts`. Firebase tokens skip this step - Crashlytics is always on Google's fixed domains and `project_id` is embedded in the SA JSON.
357
+ **Not a standalone step** - runs inline at the end of the Token Save Flow whenever the saved token belongs to a **hosted service** (Jira, Confluence, Bitbucket, Fortify, Graylog) AND the host is not yet in `prefs.global.hosts`. Firebase tokens skip this step - Crashlytics is always on Google's fixed domains and `project_id` is embedded in the SA JSON.
356
358
 
357
359
  Right after Step D (identity mapping confirmed), ask:
358
360
 
@@ -380,6 +382,7 @@ Resulting shape:
380
382
  "confluence": "confluence.example.com",
381
383
  "bitbucket": "bitbucket.example.com",
382
384
  "fortify": "ssc.example.com",
385
+ "graylog": "graylog.example.com",
383
386
  "corpDomain": "example.com"
384
387
  },
385
388
  "defaultJiraKey": "PROJ"
@@ -387,7 +390,9 @@ Resulting shape:
387
390
  }
388
391
  ```
389
392
 
390
- Placeholders `{JIRA_HOST}`, `{CONFLUENCE_HOST}`, `{BITBUCKET_HOST}`, `{FORTIFY_HOST}`, `{CORP_DOMAIN}`, `{JIRA_KEY}` in skills/commands are resolved from this block at runtime. If a host is ever missing when a phase needs it, Phase 0 prompts the same Host Prompt inline.
393
+ Placeholders `{JIRA_HOST}`, `{CONFLUENCE_HOST}`, `{BITBUCKET_HOST}`, `{FORTIFY_HOST}`, `{GRAYLOG_HOST}`, `{CORP_DOMAIN}`, `{JIRA_KEY}` in skills/commands are resolved from this block at runtime. If a host is ever missing when a phase needs it, Phase 0 prompts the same Host Prompt inline.
394
+
395
+ Graylog uses a **PAT (access token)** whose API auth is HTTP Basic with the token as the username and the literal `token` as the password (`<token>:token`) - no separate username entry. Its host prompt behaves exactly like the Jira host prompt (saved to `prefs.global.hosts.graylog`, resolved as `{GRAYLOG_HOST}`). Graylog is **automatically optional / non-blocking** via the null-mapping convention: leaving `keychainMapping.graylog` (and/or `hosts.graylog`) `null` simply means the log-fetch adapter degrades to empty and never blocks a run - no extra setup code.
391
396
 
392
397
  **Re-run / update**: `/multi-agent:setup hosts` re-opens the prompt to edit values without touching tokens.
393
398
 
@@ -706,6 +711,7 @@ Standard key names (used when creating NEW tokens). Discovery may find existing
706
711
  | `figma_pat` | `${USER}_Figma_Access_Token` | PAT (Tier 2, REST API) | Figma Developer Settings (max 90 days). Token Save Flow prompt copy: "Figma Personal Access Token (for Tier 2)". |
707
712
  | `figma_mcp` | `${USER}_Figma_Mcp_Access_Token` | OAuth (Tier 1, MCP) | Automatic via Claude Code Figma MCP remote auth. Token Save Flow prompt copy: "Figma MCP token (for Tier 1)". |
708
713
  | `fortify` | `${USER}_Fortify_Access_Token` | API Token | Fortify SSC -> Token Management (VPN required) |
714
+ | `graylog` | `${USER}_Graylog_Access_Token` | PAT (API Basic `<token>:token`) | Graylog -> System -> Users and Teams -> Edit Tokens (VPN required). Auth is HTTP Basic with the token as username and literal `token` as password. |
709
715
  | `firebase` | `${USER}_Firebase_Access_Json` | Firebase JSON (base64) | Firebase Console -> Project settings -> Service accounts -> Generate new private key. Project id is parsed from the decoded JSON - no separate entry. |
710
716
  | `jenkins` | `${USER}_Jenkins_Access_Token` | API Token | Jenkins -> User -> Configure -> API Token |
711
717
  | - | Git Identities | JSON (preferences) | Stored in `$HOME/.claude/multi-agent-preferences.json` - not Keychain |
@@ -11,6 +11,12 @@
11
11
  # - confluence : Confluence pages (host pattern + display/spaces/pageId)
12
12
  # - crashlytics : Firebase Crashlytics issue/session URLs
13
13
  # - fortify : Fortify SSC findings URLs
14
+ # - graylog : Graylog trx-id / conversation-id references. Unlike the
15
+ # others this is matched from free text (labels like "trx",
16
+ # "trxid", "transaction id", "conversationId", "convId",
17
+ # "X-conversationId" followed by an id) rather than a URL, so
18
+ # its entries carry "url": null. Advisory diagnostic context;
19
+ # pattern-based + tolerant, a project may refine the labels.
14
20
  # - figma : Figma design / make / FigJam / slides URLs
15
21
  # - generic-doc : http(s) URLs that didn't match a more specific type but
16
22
  # look like documentation (Notion, Google Docs, GitHub
@@ -26,6 +32,7 @@
26
32
  # { "type": "swagger", "url": "...", "metadata": { "format": "json|yaml|unknown" } },
27
33
  # { "type": "crashlytics","url": "...", "metadata": { "projectId": "...", "platform": "ios|android", "issueId": "...", "sessionId": "...|null" } },
28
34
  # { "type": "fortify", "url": "...", "metadata": { "host": "...", "projectId": "...|null" } },
35
+ # { "type": "graylog", "url": null, "metadata": { "idType": "trx|conversation", "id": "...", "label": "..." } },
29
36
  # { "type": "figma", "url": "...", "metadata": { "kind": "design|make|board|slides", "fileKey": "...", "nodeId": "...|null" } },
30
37
  # ...
31
38
  # ]
@@ -188,5 +195,38 @@ for url in RAW_URLS:
188
195
  seen.add(key)
189
196
  out.append({"type": typ, "url": url, "metadata": meta})
190
197
 
198
+ # --- Graylog trx / conversation ids (label-based, not URL) -----------------
199
+ # Recognise free-text references like "trxId: ABC123", "transaction id = ...",
200
+ # "conversationId ...", "X-conversationId: ...". Pattern-based + tolerant - a
201
+ # project can refine the label set. Longer/more-specific labels lead the
202
+ # alternation so "trxid" is not shadowed by "trx". The id is alphanumeric plus
203
+ # ._- and long enough (>= 6 chars) to avoid catching stray words.
204
+ GRAYLOG_RE = re.compile(
205
+ r"(?P<label>"
206
+ r"x[\s_-]*conversation[\s_-]*id"
207
+ r"|conversation[\s_-]*id"
208
+ r"|conv[\s_-]*id"
209
+ r"|transaction[\s_-]*id"
210
+ r"|trx[\s_-]*id"
211
+ r"|trx"
212
+ r")"
213
+ r"\s*[:=#]?\s*"
214
+ r"[\"']?(?P<id>[A-Za-z0-9][A-Za-z0-9._-]{5,})",
215
+ re.IGNORECASE,
216
+ )
217
+ for m in GRAYLOG_RE.finditer(text):
218
+ gid = m.group("id").rstrip(".,;:!?)")
219
+ label = m.group("label")
220
+ id_type = "conversation" if "conv" in label.lower() else "trx"
221
+ key = ("graylog", gid)
222
+ if not gid or key in seen:
223
+ continue
224
+ seen.add(key)
225
+ out.append({
226
+ "type": "graylog",
227
+ "url": None,
228
+ "metadata": {"idType": id_type, "id": gid, "label": label},
229
+ })
230
+
191
231
  print(json.dumps(out))
192
232
  PY