boma/docs/decisions/023-adr-structure.md
sjat 6d7d27b03b docs(adr): add Proposed lifecycle state; mark ADR-011 Proposed
Revisits the lifecycle decision on the evidence of ADR-011 (a real draft
with open questions). Adds a fourth state, Proposed (YYYY-MM-DD), to ADR-023,
the template, the adr-structure check (+test), spec and plan. Sets ADR-011's
Status to Proposed and removes its now-redundant inline 'Proposed' line.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-10 14:48:55 +02:00

5.2 KiB
Raw Permalink Blame History

ADR-023 — ADR structure & lifecycle

Status

Accepted (2026-06-10). Meta/doctrine ADR — pins how ADRs are written; the adr-structure check (scripts/repo-scan.py) and docs/decisions/adr-template.md ship with it, and ADRs 001018 were retroactively restructured to conform. Resolves the FRICTION signal (2026-05-31) about ADR-writing policy being unsettled.

Context

boma records architectural decisions as numbered ADRs in docs/decisions/, and CLAUDE.md treats them as load-bearing. Yet no ADR said how an ADR is written. The newest ADRs (019022) converged on a clean shape — Status → Context → Decision → Consequences → Related — but only by imitation. ADRs 001018 predate it and drifted widely: most lacked a ## Status section entirely (016018 carried only a trailing build-state note), and many lacked an explicit ## Decision or ## Consequences heading, their decisions spread across ad-hoc topical sections. The result was structural drift and no uniform way to tell an active decision from a superseded or deprecated one.

Decision

1. Title & filename

Title line: # ADR-NNN — <Title>: <optional clarifying subtitle> (em-dash). 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. Mandatory sections, in this order

  • ## Status — a lifecycle line, usually Accepted (YYYY-MM-DD) (see §4), plus an optional one-line note.
  • ## Context — the forces, the problem, what exists today, why now.
  • ## Decision — what we are doing; numbered sub-decisions for multi-part ADRs.
  • ## Consequences — results, trade-offs explicitly accepted, follow-on work.

3. Optional sections (use only where they genuinely apply)

## Related, ## Scope, ## Guardrails / ## Enforcement, ## What was ruled out, ## Verified facts (ADR-014).

4. Status lifecycle

Four states. Because boma is single-contributor and trunk-based with no review gate, most ADRs are born Accepted (YYYY-MM-DD) — committed-to on writing. A Proposed state exists for a genuine draft whose core direction is recorded but whose specifics are still open for discussion (e.g. ADR-011); it is promoted to Accepted once settled.

  • Proposed (YYYY-MM-DD) — drafted, under discussion, not yet committed-to. May carry open questions. Promoted to Accepted (YYYY-MM-DD) when decided.
  • Accepted (YYYY-MM-DD) — committed-to. The common starting state.
  • Replaced → old ADR's Status becomes Superseded by ADR-NNN (YYYY-MM-DD); the new ADR records Supersedes ADR-MMM in its Status and ## Related. The link is bidirectional.
  • Retired with no replacement → Deprecated (YYYY-MM-DD) + a one-line reason.

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.

5. Template & enforcement

docs/decisions/adr-template.md is the scaffold for new ADRs. The /review-repo command's pre-scan (scripts/repo-scan.py) emits an adr-structure finding for any numbered ADR missing a mandatory section or with an unparseable Status line. It checks presence and Status, not section order — order is a convention the template carries, deliberately not gated, to keep enforcement lightweight (consistent with boma's other doctrine ADRs adding no CI gate).

6. Retroactive conformance of the back-catalogue

ADRs 001018 are restructured to satisfy this standard rather than grandfathered. The restructure is presentational — existing headings are relabelled, regrouped, or demoted under a ## Decision umbrella; a dated ## Status is added; a ## Consequences section is assembled from implications the ADR already states. The substance of no decision is changed. This keeps the check uniform (no number threshold) and the corpus a consistent, legible decision history.

Consequences

  • New ADRs have one obvious shape and a scaffold; structural drift stops.
  • Every ADR declares its lifecycle state uniformly, and reversals are traceable.
  • The whole corpus conforms; the check needs no grandfathering and stays simple.
  • One-time restructure churn across ADRs 001018 (heading reorganization + a Status and a Consequences section per file; no decision substance changed).
  • /review-repo grows one deterministic check; no new CI machinery.
  • This ADR is the first conformant example and is held to its own check.

What was ruled out

  • A make lint / CI gate for ADR structure — heavier than the risk warrants; the /review-repo check and the template suffice.
  • Machine-enforcing section order — brittle for marginal value; left as a template-demonstrated convention.
  • Grandfathering 001018 from the check — rejected in favour of restructuring the whole corpus to conform, so the standard applies uniformly with no exceptions.
  • ADR-014 — knowledge sourcing (the Verified facts optional section).
  • ADR-019/020/021/022 — the emergent structure this ADR codifies.
  • docs/decisions/adr-template.md — the scaffold.
  • scripts/repo-scan.py — the adr-structure enforcement check.