mirror of
https://github.com/azaion/gps-denied-onboard.git
synced 2026-06-21 07:11:13 +00:00
6044a33197
Bundled hygiene commit before cycle-3 /implement (AZ-776, AZ-777). Mixes two concerns by user choice (autodev option B): - Cycle-3 autodev artifacts not yet committed by Step 9 (new-task): task specs for AZ-776 / AZ-777 under _docs/02_tasks/todo/ and the updated _docs/02_tasks/_dependencies_table.md. - Accumulated skill / rule tooling maintenance under .cursor/ (skills: autodev, code-review, decompose, deploy, implement, new-task, plan, refactor, retrospective, test-spec; rules: coderule, cursor-meta, meta-rule, testing; new release skill scaffolding). - Autodev bootstrap state: _docs/_autodev_state.md (step 10 in_progress) and _docs/_process_leftovers/2026-05-11_d_cross_cve_1_opencv_pin_deferred.md (replay timestamp refreshed; gtsam 4.2 still numpy<2-only). Co-authored-by: Cursor <cursoragent@cursor.com>
188 lines
12 KiB
Markdown
188 lines
12 KiB
Markdown
# 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 |
|