# Architecture Map — As-Built Operational Layer

`docs/architecture-map.yaml` is the **as-built** layer beneath the SAD. The SAD §7 is the **as-designed** contract (approved, gated); this map records what was actually built and how to navigate it. **No approval gate** — it is generated and updated freely by commands. Join keys = `MOD-NN` (module) and `MOD-NN.C#` (component) — both defined in SAD §7. Components are the **coverage unit**: done-time completeness asserts every component is built by some Feature.

Keep design in the SAD, reality in the map. Only a genuine *design* change touches the SAD (via `sad-impact.md` → `/tas-sad`); routine as-built facts go here.

## A. Schema & update convention

```yaml
# docs/architecture-map.yaml — AS-BUILT operational layer beneath the SAD. NO approval gate.
# Join key = MOD-ID (defined in SAD §7). SAD = design; this = reality.
version: 1
last_updated: YYYY-MM-DD

modules:
  MOD-001:
    name: Checkout UI
    container: Web App          # → container coverage roll-up + trace
    stack: web
    frs: [FR-003]               # design intent (seeded from SAD §7)
    status: built               # planned | in_progress | built
    code_anchor: [apps/web/src/features/checkout/]   # LIST — file/stack-trace → module by prefix match
    provides: [screen:/checkout]                     # endpoint/screen/event → module (trace anchor)
    depends_on: [MOD-002]       # ACTUAL deps (invert across all modules → dependents / blast radius)
    built_by: [Feature-003]     # module → feature → solution (roll-up of its components' built_by)
    tests: [TAS_F003_AC1, TAS_F003_AC2]
    drift: null                 # note when actual ≠ SAD §7; non-null → consider /tas-sad
    last_built: YYYY-MM-DD
    components:                 # buildable leaves (SAD §7 component table) — the coverage unit
      MOD-001.C1:
        name: CheckoutPage
        frs: [FR-003]           # design intent (seeded from SAD §7)
        status: built           # planned | in_progress | built
        origin: feature         # feature | baseline — baseline = pre-existing code adopted via /tas-init (no claiming Feature required)
        built_by: [Feature-003] # component → feature (the completeness check); empty+origin:baseline is still Covered
        code_anchor: [apps/web/src/features/checkout/CheckoutPage.tsx]
        tests: [TAS_F003_AC1]
      MOD-001.C2:
        name: OrderApiClient
        frs: [FR-003]
        status: built
        built_by: [Feature-003]
        code_anchor: [apps/web/src/features/checkout/api.ts]

# Coverage ledger — the other tracked design items (SAD §8 / §9.2 / §11 / §10).
# Every entry must end up claimed by a Feature; /tas-status asserts 100% before release.
entities:                       # SAD §8.1 Domain Model — "buildable": exactly ONE owner Feature creates the schema
  E-003:
    name: Order
    owner: Feature-005          # the Feature that creates this entity's schema/table (others only use it)
    status: built               # planned | built
    origin: feature             # feature | baseline (table already existed when the kit was adopted)
    code_anchor: [services/api/src/Order/Order.cs]
contracts:                      # SAD §9.2 Integration Contract Registry — "buildable": ONE producer Feature
  IC-01:
    name: POST /v1/payments
    producer_mod: MOD-003       # design (from §9.2 Producer column)
    producer: Feature-007       # the Feature that builds the producer side
    status: built               # planned | built
    origin: feature             # feature | baseline
nfrs:                           # SAD §11 NFR Strategy — "cross-cutting": addressed by ≥1 Feature OR its own Feature
  NFR-001:
    category: Latency
    addressed_by: [Feature-005] # Features that enforce it as a constraint (or a dedicated Feature)
    status: enforced            # planned | enforced
    origin: feature             # feature | baseline (already satisfied by pre-existing code)
security:                       # SAD §10 Security Controls — "cross-cutting": addressed by ≥1 Feature OR its own Feature
  SEC-01:
    name: JWT on protected routes
    addressed_by: [Feature-002]
    status: implemented         # planned | implemented
    origin: feature             # feature | baseline
```

A module's `status` / `built_by` roll up from its components: a module is `built` only when **all** its components are `built`. The four ledger sections above close the coverage loop for entities, contracts, NFRs, and security controls the same way components do for modules.

**`origin` — greenfield vs brownfield.** Every item carries `origin: feature | baseline`:
- `feature` (default, greenfield + all new work) — the item MUST be claimed by a Feature; unclaimed = a coverage gap.
- `baseline` — the item already existed in the codebase when the kit was adopted (seeded by `/tas-init` brownfield). It is **Covered without a claiming Feature** (`built_by`/`owner`/`producer`/`addressed_by` may be empty), so coverage gates never demand a fake Feature for pre-existing code. A Feature that later touches a baseline entity records it under `Entities (uses)`, not `owns`. When new work genuinely replaces a baseline item, flip its `origin` to `feature` and claim it normally.

Who writes what:
- **`/tas-init` (brownfield)** seeds items that already exist in the scanned codebase as `status: built, origin: baseline` (with `code_anchor` to the existing code, claim fields empty) — so adopting the kit does NOT force fake Features for working code. Design items with no code yet stay `origin: feature, status: planned`.
- **`/tas-sad`** seeds every tracked design item as `status: planned, origin: feature` with its design fields: each `MOD-NN` (+ `components` map) from §7; each `E-NNN` from §8.1; each `IC-NN` (+ `producer_mod`) from §9.2; each `NFR-NNN` from §11; each `SEC-NN` from §10. On a §-change, syncs add/remove at every level (existing baseline entries keep their `origin`).
- **`/tas-plan`** records the claim from the Feature-Technical `## Modules` block: `built_by` on each component in `Builds`; `owner` on each entity in `Entities (owns)`; `producer` on each contract in `Contracts (produces)`; `addressed_by` on each `NFR-NNN` / `SEC-NN` claimed.
- **`/tas-dev` write-back** (after Done) sets the as-built fields: per component (`status: built`, `code_anchor`, `tests`, `last_built`) + module roll-up (`provides`, `drift`); and flips the claimed entities → `built`, contracts → `built`, NFRs → `enforced`, security → `implemented` (with `code_anchor` where applicable).

Rules:
- `code_anchor` is always a **list** (a module/entity may span multiple paths/namespaces).
- `dependents` are **not stored** — compute on demand by inverting `depends_on` across all modules (avoids drift).
- Only update the keys that changed; never rewrite the whole file.
- All IDs (`MOD-NN`, `MOD-NN.C#`, `E-NNN`, `IC-NN`, `NFR-NNN`, `SEC-NN`) are stable and global — never reuse a retired ID.
- **Buildable** items (component, entity, contract) have exactly one builder/owner/producer Feature. **Cross-cutting** items (NFR, security) may be `addressed_by` several Features (constraint) or a single dedicated Feature.

## B. Trace procedure (error → fix)

Given a symptom (local/prod error, failing test, bad behavior), walk the spine deterministically:

1. **Symptom → anchor.** Identify the entry signal: an endpoint/screen/event, a log line (should carry `MOD-id` + correlation id), or a stack-trace file path.
2. **Anchor → MOD.** Endpoint/screen/event → grep `provides`. Stack-trace file → prefix-match `code_anchor`. Log `MOD-id` → direct. → the suspect `MOD-NN` (+ its `container`).
3. **MOD → Feature → solution.** `built_by` → read that Feature-Technical (`Logic Flow`, `File Changes`, AC) to inspect whether the implemented solution is flawed.
4. **Dependency walk.** Follow `depends_on` downstream (the fault may originate in a module/external this one calls); invert `depends_on` for **dependents** (who else is affected).
5. **Reproduce.** Run the module's `tests` (its FR's AC tests) to confirm and localize.
6. **Classify the fix.** Code defect → `/tas-fix` or `/tas-debug` loop. Design flaw (the SAD §7 approach is wrong) → set `drift`, escalate via `sad-impact.md` → `/tas-sad` / `/tas-adr`.

## C. Impact procedure (change → blast radius)

When adding or editing a Feature/module, before committing to the plan:

1. **Identify target modules** — the `MOD-NN` the change builds or touches.
2. **Downstream** — `depends_on` of the target: modules/externals it relies on (must still satisfy their contracts).
3. **Upstream (blast radius)** — invert `depends_on` across all modules to find every module that depends on the target; map each to its `built_by` Feature(s).
4. **Report** — list affected modules + Features as regression risk / **tech-debt Feature** candidates. A breaking change to a module's `provides` means every dependent Feature must be revisited.
5. **Placement (new feature)** — use SAD §7 + the map to decide which container/module the new work belongs to, and whether it extends an existing module (add to `built_by`) or needs a new `MOD-NN` (→ `/tas-sad`).
