# Step 4.5: Architecture Decision Records (ADRs)

**Role**: Architect / technical writer
**Goal**: Capture every major architecture, tech-stack, data-model, and integration decision made during Steps 2–4 as a durable, dated, immutable record under `_docs/02_document/adr/`.
**Constraints**: ADRs only — do not re-open architecture; do not make new decisions in this step. Document what has been decided, not what is still open.

ADRs are the single thing in `_docs/` that explains the **why** of each major decision after the conversation history is gone. They are consumed by:

- `decompose` Step 1.5 (`steps/01-5_module-layout.md`) — every Accepted ADR is cross-checked against the module-layout proposal; conflicts trigger an explicit Choose between supersede / exception / re-open.
- `new-task` Step 4.5 (`SKILL.md` § "Step 4.5: Contract & Layout Check") — every new task is classified against Accepted ADRs as Conflict / Drift / Aligned; conflicts STOP the task with a Choose A/B/C; drift adds an `### ADR Impact` section; alignment adds an `### ADR Compliance` section.
- `refactor` Phase 2b.1 (`phases/02-analysis.md`) — every Accepted ADR is diffed against the proposed roadmap; Violations trigger a BLOCKING supersede gate that produces a `supersede_adr_NNN.md` task before any refactor task is created.
- `code-review` Phase 7 (`SKILL.md` § "Phase 7: Architecture Compliance") — every changed-files batch is checked against Accepted ADRs; ADR-Violation findings are Critical, ADR-Drift findings are High.

Discipline that still relies on the human: when a downstream skill detects a Drift case, the resulting task spec MUST land its `## ADR Impact` / `## ADR Compliance` section; the implementer must address it; the next code-review batch then has the context it needs. Drift left undocumented is the silent-failure path — every consumer hook above is designed to make it visible.

## Inputs

- `_docs/02_document/architecture.md` (incl. confirmed `## Architecture Vision`)
- `_docs/02_document/glossary.md`
- `_docs/02_document/data_model.md`
- `_docs/02_document/system-flows.md`
- `_docs/02_document/risk_mitigations.md` (and any `risk_mitigations_NN.md` iterations from Step 4)
- `_docs/02_document/components/[##]_[name]/description.md`
- `_docs/02_document/deployment/` (CI/CD, environments, observability)
- `_docs/00_problem/restrictions.md` and `_docs/00_problem/acceptance_criteria.md` (each ADR must reference relevant constraints / AC by ID)
- Optional: `_docs/01_solution/solution.md` and `_docs/01_solution/tech_stack.md` (research output)
- Optional: `_docs/LESSONS.md` — surface any lesson categories of `architecture` / `dependencies` that bias the recommendation

## What is an ADR (and what is not)

Capture an ADR when **all** of the following hold:

1. The decision picks between two or more genuinely valid approaches with meaningful trade-offs.
2. The decision has **downstream consequences** that other decisions, code, or tasks inherit from.
3. The decision is **non-obvious** to a future reader who only sees the final code — they would ask "why was it built this way?" rather than discovering the answer by reading the source.

Do NOT create an ADR for:

- Naming, formatting, or purely cosmetic choices.
- A choice that is fully implied by a single explicit restriction (`restrictions.md` is itself the record — link to it from the architecture doc instead).
- A choice the team has not actually made yet — open questions live in `risk_mitigations.md` or `_docs/_process_leftovers/`, not in ADRs.
- A technology selection where research already produced an exact-fit selection with one viable option (the research doc is the record — link to the relevant `solution_draft*.md` section).

## Process

### Phase 4.5a: Decision Inventory

Walk the inputs and list candidate decisions. For each candidate, record a one-liner:

```
- [decision] — [trade-off summary] — [downstream consumers] — [evidence file:section]
```

Inspect at minimum:

| Inspection target | Typical decisions surfaced |
|-------------------|----------------------------|
| `architecture.md` § layering | Layering style (clean vs hex vs n-tier), which layer owns transactions, how cross-cutting concerns enter |
| `architecture.md` § Architecture Vision | The North Star principle (e.g., "edge-first, sync-second"); ADR captures the implication for one specific subsystem |
| `data_model.md` | Datastore choice (Postgres vs Mongo), partitioning, soft vs hard deletes, schema evolution strategy |
| `system-flows.md` | Sync vs async boundaries, idempotency strategy, retry policy ownership, error envelope shape |
| `components/*/description.md` § interfaces | Public-API style (REST vs RPC vs event), versioning strategy, auth/authorization placement |
| `deployment/containerization.md` | Single container vs sidecar vs init container, base image lineage |
| `deployment/ci_cd_pipeline.md` | Trunk-based vs feature-branch, gate ordering, deploy strategy (blue-green / canary / all-at-once) |
| `deployment/observability.md` | Logging stack, metric backend, sampling rate decisions, retention |
| `risk_mitigations.md` | Risk-acceptance trade-offs (e.g., "we accept N% data loss in exchange for sub-100ms p99") |
| Tech-stack from `_docs/01_solution/tech_stack.md` | Anything where research recorded ≥2 candidates and a winner |

Drop any candidate that fails the three "what is an ADR" criteria above. Keep the rest.

### Phase 4.5b: Numbering and Slugs

ADRs are numbered globally per project, monotonically, never re-used.

1. List existing files under `_docs/02_document/adr/` matching `^[0-9]{3}_.+\.md$`.
2. The next ADR number is `max(existing) + 1`, zero-padded to 3 digits.
3. The slug is kebab-case, ≤6 words, derived from the decision summary. Example: `001_use-postgres-for-transactional-data.md`, `004_event-driven-cross-component-comms.md`.

### Phase 4.5c: Render One ADR Per Decision

For each kept candidate, render the ADR using `templates/adr.md`. Required sections (do NOT omit any):

| Section | Content |
|---------|---------|
| **Number** | `NNN` |
| **Title** | One-line decision statement (matches slug) |
| **Status** | `Proposed` (only during Step 4.5 iteration) → `Accepted` (after user confirmation at the BLOCKING gate) |
| **Date** | YYYY-MM-DD (the date the user confirmed) |
| **Deciders** | The user (project owner) — the AI is not a decider |
| **Context** | The problem this decision addresses, including links to AC IDs, restriction IDs, risks, and (where relevant) the research draft section |
| **Decision** | The chosen approach in one sentence, then the supporting detail |
| **Alternatives Considered** | Each alternative with a one-line "rejected because…" |
| **Consequences** | Positive (what becomes easier / cheaper / faster) and negative (what becomes harder / locked in / costly to undo). Be honest — every decision has a downside. |
| **Supersedes / Superseded by** | Empty initially; updated when a future ADR overturns this one |
| **Evidence** | File-and-section pointers into `_docs/` showing where the decision is reflected (architecture.md § layering, components/02_*/description.md § interface, etc.) |

After rendering, write each file to `_docs/02_document/adr/NNN_<slug>.md`. Keep `Status: Proposed` until the BLOCKING gate.

### Phase 4.5d: Maintain the ADR Index

Write or update `_docs/02_document/adr/README.md` with this exact shape:

```markdown
# Architecture Decision Records

This index lists every ADR for this project, in number order. ADRs are immutable once `Accepted` —
new decisions that overturn a prior ADR are recorded as new ADRs whose `Supersedes` field points
back, and the original ADR's `Superseded by` field is updated.

| # | Title | Status | Date | Supersedes |
|---|-------|--------|------|------------|
| 001 | Use Postgres for transactional data | Accepted | 2026-05-21 | — |
| 002 | Event-driven cross-component comms | Accepted | 2026-05-21 | — |
| ... | ... | ... | ... | ... |
```

Sort by `#` ascending. Include all ADRs ever written, even superseded ones — the audit trail is the point.

### Phase 4.5e: Cross-Link from architecture.md

In `architecture.md`, every section that reflects an ADR decision gets a one-line trailing reference:

```markdown
> See ADR 001 (Use Postgres for transactional data), ADR 003 (Event-driven cross-component comms).
```

Place the reference at the end of the section, after the prose. This lets a future reader of `architecture.md` jump straight to the rationale.

### Phase 4.5f: BLOCKING Gate — User Confirmation

Present the ADR set to the user using the Choose format from `.cursor/skills/autodev/protocols.md` (or plain text if AskQuestion is unavailable):

```
══════════════════════════════════════
 DECISION REQUIRED: ADR set captured (N records)
══════════════════════════════════════
 001 — [title]
 002 — [title]
 ...
══════════════════════════════════════
 A) Accept all ADRs as written
 B) Edit specific ADRs (numbers and edits)
 C) Add a missed decision (description)
 D) Remove an ADR (number and reason)
══════════════════════════════════════
 Recommendation: A — review the rendered set and confirm; corrections are quick on Round 2
══════════════════════════════════════
```

Loop:

- **A** → flip every ADR's `Status` from `Proposed` to `Accepted`, set `Date` to today's date, save, exit step.
- **B** → apply edits, re-present the modified ADRs, loop.
- **C** → run Phase 4.5a–4.5e for the missed decision only, append to the set, re-present, loop.
- **D** → confirm with the user that the candidate fails the three "what is an ADR" criteria, remove the file, update the index, loop.

Do NOT mark `Accepted` without an explicit user A.

## Self-verification

- [ ] Every kept candidate from Phase 4.5a has a corresponding file under `adr/`
- [ ] Every ADR has all required sections (none empty except `Supersedes` / `Superseded by`)
- [ ] `Decision` sections are one-sentence-then-detail, not "we'll figure it out"
- [ ] `Alternatives Considered` lists at least one rejected alternative per ADR
- [ ] `Consequences` lists both positive AND negative consequences (an ADR with no negatives is suspect)
- [ ] `Evidence` points at real `_docs/` sections that exist on disk
- [ ] `adr/README.md` index lists every file in the directory and matches their `Status` / `Date`
- [ ] `architecture.md` has a trailing `See ADR …` reference at every section that an ADR reflects
- [ ] The user confirmed the set via Choose A; every ADR is `Accepted` with today's date

## Common mistakes

- **Re-opening architecture**: Step 4.5 records, it does not decide. If a candidate decision turns out to be unsettled, that's a Step 2 / Step 4 gap — return there, do not paper over it with a wishy-washy ADR.
- **Decision-of-the-week**: do not write an ADR for every minor pattern choice. The bar is "non-obvious to a future reader". 5–15 ADRs is typical for a planning round; 40+ is over-capture.
- **Negative consequences left empty**: every real decision has costs. If you cannot name one, the decision was not actually weighed.
- **Vague evidence**: `architecture.md` is not enough — point at the specific section. `architecture.md § Layering` ≠ `architecture.md`.
- **Numbering reuse**: never recycle a number from a deleted ADR. The audit trail is more important than tidy numbering.
- **Superseding without recording**: when a later cycle overturns an ADR, the new ADR must point at the old one via `Supersedes`, AND the old ADR's `Superseded by` field must be updated. Index reflects both. (This is enforced when `decompose` or `refactor` later updates ADRs.)

## Escalation

| Situation | Action |
|-----------|--------|
| Candidate decision is unsettled (the team has not actually decided) | Return to the originating step (2 / 3 / 4); do NOT write a placeholder ADR |
| Two candidates in Phase 4.5a turn out to be the same decision phrased differently | Merge into one ADR, list both phrasings in `Context` |
| User picks D (remove an ADR) and the AI judges the decision is genuinely worth recording | Surface the disagreement, ASK why the user wants it removed, defer to user |
| Existing `adr/` directory has files but `adr/README.md` is missing or stale | Rebuild the index from the directory before adding new ADRs |
