# Locked decisions (35)

> The 35 Locked decisions of the analysis flow. Loaded by `/multi-agent:analysis`, by `/multi-agent:analysis-resolve` (which inherits them) and by pipeline Phase 1 when it runs the analysis engine. Numbering is canonical: cite as `Locked <n> (<short label>)`.

### Index by category (v9.1.0+)

Browse-friendly grouping of the 35 Locked decisions. Numbering stays canonical (matches the list below); the index is read-only navigation.

| Category | Decisions | Concern |
|---|---|---|
| **A. Governance** | 1, 5, 6, 7, 10, 26, 27, 32 | Run-level process rules: one feature per run, default output, auto-commit ban, punctuation policy, output picker timing, Pass B preview, evidence digest cache, analysis profile |
| **B. Citation and Evidence** | 3, 4, 8, 11, 24, 30, 34 | 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), references built from the evidence record |
| **C. Output Format and Structure** | 2, 9, 13, 14, 16, 17, 20, 21, 25, 33, 35 | 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, corporate backbone always renders, stack-optional render |
| **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) |
| **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 |

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)`).

### Full list

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.
2. **Section omission rule.** Sections with zero evidence are dropped entirely; no `TBD` placeholder section. Numbering remains sequential `1..N` over the rendered set.
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.
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?".
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).
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.
7. **Humanizer punctuation policy is non-negotiable.** No em-dash, en-dash, ellipsis, curly quotes, or section sign in any emitted text. Verification grep is run before the file lands.
8. **Standards binding.** When `evidence.standards[]` is non-empty, Section 7 architectural decisions must cite their binding source by file plus section. Decisions that contradict a binding source go to Section 7 Risks rather than silently overriding.
9. **Per-platform output split.** One markdown file is produced per selected platform under `analysis/<feature>-<platform>.md`. There is no merged single file. Section duplication follows the A3 hybrid table in `$HOME/.claude/multi-agent-refs/analysis-template.md` (Sections 1 + 4 duplicated verbatim; Sections 2, 3, 5, 6, 7 projected per platform). Each file carries a YAML front-matter header naming the feature, platform, generated-at timestamp, sibling file list, and binding standards source.
10. **Output destination is asked after drafts exist.** Phase 3 renders each per-platform markdown to `/tmp/analysis-<feature-slug>-<timestamp>/` first. Only then does Phase 3.5 surface the output-destination picker (Local / Confluence / Jira). Drafts in `/tmp/` are the source of truth on resume; `/multi-agent:resume` re-uses them when `phase == awaiting_output_decision`.
11. **Repo-evidence reuse-first.** Phase 1b runs a repo-evidence collector against each selected repo, producing 13 buckets (services, dtos, useCases, validationRules, domainEntities, routes, coordinators, diConfigurators, uiComponents, tokens, localizationKeys, testingIdentifiers, analyticsEvents) with each row tagged `direct-match | same-domain | cross-cutting`. Section 7 emits `Reuse existing X (file:line)` rows for `direct-match` items and advisory rows for `cross-cutting` items. New-write tasks for items that have a `direct-match` are downgraded to Risks ("existing X candidate found; reuse or document why a new one is needed").
12. **MUST: Figma access - 3-tier fallback chain, pipeline-wide.** When any Figma URL or node ID is supplied (Phase 0 Step 5), Phase 1 establishes a Figma ground-truth artefact via the 3-tier chain before any UI synthesis runs: (1) Figma MCP `get_design_context` / `get_screenshot` / `get_metadata` for every referenced frame, with one re-auth retry on auth failure; (2) Figma REST API (`GET /v1/files/{fileKey}/nodes`, `GET /v1/images/{fileKey}`) using the PAT resolved through `~/.claude/lib/credential-store.sh get <logical-key>` where `<logical-key>` = `prefs.global.keychainMapping.figma`; (3) a user-attached screenshot as last resort. The tier in use is persisted as `state.figmaAccess.tier`. On Tier 1 the `CodeConnectSnippet` blocks name the exact target component consumed verbatim in Section 2 and Section 7. On Tier 2 the canonical-component decision falls back to the repo's `*.figma.swift` / `*.figma.kt` mappings keyed by `fileKey` + `nodeId`. On Tier 3 the canonical-component decision becomes "tier-3 best-fit pending design review" and produces a forced Open Question in Section 7 plus a Phase 4 `review_blocking` flag. Sound-alike alternatives, "more flexible" wrappers, and extrapolating from Confluence text-only "Component Kompozisyonu" / "Component Inventory" tables are forbidden in every tier. If all three tiers fail, halt the run and ask the user for access; never proceed with text-derived guesses. Section 7 architecture decisions must cite the node ID (Tier 1 or Tier 2) or the user-screenshot reference (Tier 3) for every UI atom row. Violations cost rebuild rounds (raw-primitive substitution; sound-alike-component swap). Generic rule rationale and checklist: see `$HOME/.claude/rules/figma-pipeline.md` "MUST: Figma access - 3-tier fallback chain (BLOCKING, pipeline-wide)". Memory: `[[figma-no-guesswork]]`.
13. **Gherkin user stories.** Section 4 scenarios use Given / When / Then. Plain-prose user stories are rejected at render time.
14. **Goals and Non-Goals are paired.** Section 2 always carries both columns. A row in only the goal column without an explicit non-goal counterpart is rejected. Vague "out of scope" phrasing does not satisfy the non-goal column; each non-goal names what is excluded.
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.
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.
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.
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.
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.
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.
    - **`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.
    - **`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.
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.
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.
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.
24. **Pass B cell footnote mandatory.** Every cell Pass B fills in Section 13 (Architecture Plan concept table) and any other per-platform projection carries a footnote of the form `^[<convention-key> <confidence>: <evidence-source>]` pointing back to Phase 1c output. Cells with `confidence: low | none` cite `conventions-defaults.md:C<n>-<platform>` and emit a row in Section 20 Risks ("convention fallback applied"). Footnote-less cells fail the dispatch gate.
25. **Lite mode for small features.** When Phase 1 signals indicate a small feature, Lite mode auto-activates and renders only Sections 1, 2, 4, 9, 13, 14, 21, plus optional 23 Changelog. The user can force Lite with `--lite` or force Full with `--full`. Full mode is the default for new feature analyses. **Scoring (v9.1.0+):** three independent signals - `confluenceSpecLines < 100`, `figmaFramesCount <= 1`, `repoDirectMatchCount >= 8`. Each true signal scores 1 point; Lite auto-activates at `score >= 2`. Previous AND-threshold (`v8.12.0..v9.0.x`) was too strict and forced small features into Full mode when one signal was just over the line. Explicit user flags (`--lite` / `--full`) always win over auto-scoring.
26. **Pass B preview before render.** Phase 2a presents the resolved convention table to the user before Phase 2b emits any platform file. The user can approve, override individual cells, or cancel. Empty answers do not imply consent (`feedback_no-inferred-defaults-from-empty-answer`); the picker re-asks on empty submit.
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.
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.
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.
30. **Analysis as self-contained design bridge - no MCP outside analysis phase (BLOCKING, pipeline-wide).** 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`, at either depth. Hard requirement (v9.0.0): Phase 2 Pre-item and Phase 3 Pre-item (BLOCKING) abort the run when the analysis document is missing. Memory: `[[mcp-only-in-analysis]]`. Generic rule rationale and access matrix: see `$HOME/.claude/rules/figma-pipeline.md` "MUST: No MCP outside analysis phase".
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 by a dev run. The rule-to-acceptance-criterion half always holds, in both modes.

32. **Analysis profile selected at intake.** `state.analysisSpec.profile` is `global` (default) or `corporate`, asked once at Phase 0 Step 1b and never re-asked mid-run. `global` renders `$HOME/.claude/multi-agent-refs/analysis-template.md` (23 sections, development handoff). `corporate` renders `$HOME/.claude/multi-agent-refs/analysis-template-corporate.md` (requirements document: `IG -> UC -> FG` spine, three traceability matrices, current-to-target state with impact analysis, then Technical Analysis and Development Analysis). **Both profiles read the same `state.analysisSpec.evidence.*`** - intake, fetching, repo evidence and convention extraction are shared and profile-independent; only the projection differs. This is what keeps the two templates from drifting into two products. One run emits one profile: rendering both from a single run would produce two documents describing the same feature, and the next reader would have to decide which one is current. When only one profile is available (`prefs.global.analysisProfiles` lists one, or the corporate profile has no binding configuration), the step auto-resolves and prints its breadcrumb with the resolution noted, per the picker contract.
33. **Corporate backbone always renders.** In the `corporate` profile the Locked 2 omission rule is replaced for Part A and the footer: those sections render even with zero evidence, carrying `N/A` when the section is genuinely out of scope for the feature and `EKLENECEK` when evidence is expected but missing. This is the point of a requirements document - a reader has to be able to tell "we considered hardware needs and there are none" from "nobody looked". Every `EKLENECEK` emits a matching Section 20 Risks and Open Questions row naming what is missing and who can answer it; an `EKLENECEK` with no such row fails the dispatch gate, because an unanswered question nobody owns is how a placeholder reaches production. **Missing inputs never block the run**: the corporate source practice of halting until every input arrives is deliberately not adopted - the document is produced with `EKLENECEK` in the gaps and the gaps are raised in Section 20. Part B follows the global omission table unchanged. In the `global` profile Locked 2 applies as written, with no placeholder of any kind.
34. **References are built from the evidence record, not written.** Section 21 is emitted by `$HOME/.claude/scripts/build-references.mjs` from `state.analysisSpec.evidence.*` in both profiles. Each row carries a precision anchor in its `Sürüm / Ref` column - Figma node id, Confluence `pageId` plus page version, the commit SHA a repo was read at, the Swagger spec version - because a reference with no anchor points at a moving target. Each row carries an `Erişim / Access` cell: a declared source that could not be fetched still gets a row reading `erişilemedi (<reason>)`, since a silently dropped source reads to the next person as a source that never existed. User statements from the conversation that no fetched source contains are recorded as `Serbest metin` rows, quoted verbatim, with the decision they settled. **Coverage gate**: every entry in `evidence.figma[]`, `confluence[]`, `jira[]`, `swagger[]`, `repo[]`, `standards[]`, `firebase[]`, `documents[]`, `outside[]`, `freeText[]` and every entry in `evidence.fetchErrors[]` must appear as a row, and every row must map to an evidence entry. A source that shaped the document but is missing from References fails the dispatch gate; so does an invented row with no evidence behind it.
35. **Stack-optional render.** Platform and repo selection are optional. When `state.analysisSpec.platforms[]` is empty, the run still completes: the analysis layers that do not need a target repository render in full - Part A and Part B in the corporate profile, Sections 1-12 and 16-17 in the global profile - and only the development layer is dropped (corporate Part C; global Sections 13, 14, 15) along with the Pass B projection, since there are no conventions to project onto. A Section 20 row records that the development analysis awaits a repo selection. One document is emitted rather than one per platform, because the per-platform split (Locked 9) exists to carry per-platform projections and there are none. It lands at `~/Desktop/multiAgentAnalysis/<feature-name>/<feature>.md`: the repo-relative `analysis/` path has nothing to be relative to without a repo, and the current working directory is never used, since for a repo-less run it is arbitrary. Desktop rather than a hidden directory because the document is a deliverable somebody is meant to open and hand over, and `multiAgentAnalysis` rather than a bare `Analysis` because a generic word collides with whatever else is on a desktop while the producer name groups every run this command ever writes. The Phase 3.5 picker shows the resolved path and takes an override through its Other input. A requirements document is useful before anyone has decided which repository will hold the code, and refusing to produce one until that decision exists inverts the order the work actually happens in.
