# Design — ADR structure & lifecycle - **Date:** 2026-06-10 - **Status:** Approved design — implementation plan to follow - **Resolves:** the absence of a written standard for how ADRs in `docs/decisions/` are structured. The newest ADRs (019–022) have converged on a clean pattern (`Status` → `Context` → `Decision` → `Consequences` → `Related`), but it lives only as imitation; ADRs 001–018 predate it and most lack a `Status` section. - **Becomes:** ADR-023 (this design is the basis for that ADR). - **Reuses:** boma's existing `*-template.md` convention (`service-security-template.md`, `service-verify-template.md`, `service-access-template.md`, `service-backup-template.md`); ADR-014 (knowledge-sourcing → the optional `Verified facts` section); ADR-019/020/021/022 (the emergent structure being codified); the `/review-repo` command (enforcement home). --- ## Problem boma documents architectural decisions as numbered ADRs in `docs/decisions/`, and CLAUDE.md treats them as load-bearing ("Before assuming a role, provider, or pipeline exists, check STATUS.md"; the entire "Further reading" table points into them). Yet there is no ADR that says how an ADR is written. The result: - **Structural drift.** ADRs 001–018 are freeform; 019–022 converged on a consistent shape but only by imitation. A new ADR's structure depends on which existing one the author happened to copy. - **No status discipline.** Most early ADRs have no `## Status` section, so there is no uniform way to tell an active decision from a superseded or deprecated one — and no written rule for how a decision gets reversed without silently rewriting history. - **No scaffold.** Every other recurring document type in boma has a template (`service-security-template.md`, etc.). ADRs do not. This design codifies the structure 019–022 already demonstrate, pins a status lifecycle, ships a template, and reconciles the back-catalogue. ## Scope - **In:** the canonical section set (mandatory + optional); title and filename convention; the `Accepted / Superseded / Deprecated` status lifecycle and the no-silent-rewrite rule; cross-reference convention; an ADR template file; a lightweight `/review-repo` structure check; a **one-time retroactive restructure of ADRs 001–018** to full conformance (all four mandatory sections + a parseable Status line), reorganizing existing content under canonical headings. - **Out (for now):** *changing the substance of* any existing decision (the restructure is presentational — relabel/regroup/demote existing content, add a dated Status, never alter what was decided); a `make lint` / CI gate for ADR structure (explicitly rejected in favour of the `/review-repo` check — consistent with boma's other doctrine ADRs, which add no CI gate); grandfathering pre-convention ADRs from the check (rejected — the whole corpus is brought to conformance instead). The lifecycle uses four states — `Proposed / Accepted / Superseded / Deprecated`. An earlier draft of this design omitted `Proposed`, but ADR-011 (a real draft with open questions) is evidence boma occasionally needs it, so it was kept. ## Decision ### 1. Title & filename - Title line: `# ADR-NNN — : <optional clarifying subtitle>` (em-dash `—`, matching every existing ADR). - Filename: `NNN-kebab-title.md`, zero-padded 3-digit, monotonic, **never reused** (a superseded ADR keeps its number and file). - A new ADR is registered as a row in the CLAUDE.md "Further reading" table. ### 2. Canonical sections **Mandatory — every ADR, in this order:** | Section | Holds | |---|---| | `## Status` | `Accepted (YYYY-MM-DD)`, plus an optional one-line note (what it resolves/supersedes, or a doctrine-not-yet-built caveat as ADR-022 uses) | | `## Context` | the forces, the problem, what exists today, why now | | `## Decision` | what we are doing — numbered sub-decisions for multi-part ADRs, as 020/021/022 do | | `## Consequences` | results, trade-offs *explicitly accepted*, follow-on work | **Optional — use only where genuinely applicable, never as padding:** - `## Related` — links to other ADRs by number. - `## Scope` — explicit in/out-of-scope boundaries. - `## Guardrails` / `## Enforcement` — how the decision is mechanically enforced (lint, CI, hooks). - `## What was ruled out` — rejected alternatives, each with its reason. - `## Verified facts (ADR-014)` — version-stamped facts per the knowledge-sourcing rule. ### 3. Status lifecycle Four states. Most ADRs are **born `Accepted (YYYY-MM-DD)`** — the sole author commits to it on writing (boma is single-contributor and trunk-based with no review gate). - **`Proposed (YYYY-MM-DD)`** — a genuine draft whose core direction is recorded but whose specifics are still open (e.g. ADR-011, which carries open questions). Promoted to `Accepted (YYYY-MM-DD)` once settled. - **`Accepted (YYYY-MM-DD)`** — committed-to; the common starting state. - Replaced by a later decision → the old ADR's Status becomes **`Superseded by ADR-NNN (YYYY-MM-DD)`**; the superseding ADR records `Supersedes ADR-MMM` in its own `## Status` and `## Related`. The link is **bidirectional** — both files must point at each other. - Retired with no replacement → **`Deprecated (YYYY-MM-DD)`** plus a one-line reason. **Load-bearing rule — no silent rewrites.** An `Accepted` ADR is not edited to reverse its decision. Typo and clarity fixes are fine; a *material reversal* requires a new ADR and a `Superseded by` marker on the old one. The history of decisions stays legible. ### 4. Cross-references Reference other ADRs by number inline (`ADR-019`), and collect the relationships in a `## Related` section. ### 5. Template file Ship `docs/decisions/adr-template.md` — consistent with boma's existing `*-template.md` convention. It contains the mandatory section headers pre-filled with short HTML-comment hints, and the optional sections listed as commented stubs to uncomment when relevant. It is a skeleton, not a numbered decision, so it does not take an ADR number. ### 6. Retroactive restructure (001–018) A **separate step** after the ADR and template land: bring every pre-convention ADR to full conformance — all four mandatory sections present and a parseable Status line. This is a **presentational** restructure, governed by a strict faithfulness rule: - **Add** a `## Status` section valued `Accepted (YYYY-MM-DD)`, the date reconstructed from the file's **first git-commit date**. For 016–018, whose existing trailing build-state note is unparseable, prepend the dated `Accepted (...)` clause so the note becomes a parseable Status line's tail. - **Reorganize** existing content under the canonical headings: relabel a synonym (`## Decisions` → `## Decision`), or introduce a `## Decision` umbrella and **demote** the existing topical `##` headings to `###` beneath it. No sentence of existing prose is altered. - **Add** a `## Consequences` section built **only** from implications the ADR already states (trade-offs, "what was ruled out", "open questions", follow-on work already named). If an ADR genuinely states nothing that can be faithfully cast as a consequence, that file is escalated for a human decision rather than inventing one. - **Never** change the substance of a decision. A `git diff` of the restructure should show heading-level changes, a new Status section, and a Consequences section assembled from existing material — not edits to existing argument. ADRs already conformant (019–022) are left alone. End state: the `adr-structure` check reports zero findings across the whole corpus, with no grandfathering. ### 7. Enforcement Lightweight, no CI gate. The `/review-repo` command gains an ADR-structure check: every file in `docs/decisions/` matching `NNN-*.md` has the four mandatory sections and a parseable `## Status` line. The template carries the convention forward for new ADRs. ## Consequences - New ADRs have one obvious shape and a scaffold to start from; structural drift stops. - Every ADR declares its lifecycle state uniformly, and reversals are traceable rather than silent — the back-catalogue becomes a legible decision history. - One-time churn: a restructure touching ~18 files (heading reorganization + a Status section + a Consequences section per file). Larger and more judgment-heavy than a Status-only backfill, hence the faithfulness rule and per-file review. - The whole corpus conforms — the check needs no grandfathering or number threshold, and stays simple (presence + parseable Status, applied uniformly). - `/review-repo` grows a new check; no new CI machinery, matching boma's habit of not gating doctrine in CI. - This ADR is itself the first conformant example — it must follow its own structure. ## Open questions None outstanding — title/filename, the **4-state lifecycle** (`Proposed / Accepted / Superseded / Deprecated`; `Proposed` adopted on the evidence of ADR-011), template name (`adr-template.md`), enforcement (`/review-repo`, no CI gate), and the **full retroactive restructure** of 001–018 (no grandfathering) were all confirmed during brainstorming and execution.