boma/docs/superpowers/specs/2026-06-10-adr-structure-design.md
sjat dfbe37916f docs(adr): design spec for ADR structure & lifecycle (ADR-023)
Codifies the structure ADRs 019-022 converged on, pins an
Accepted/Superseded/Deprecated lifecycle with a no-silent-rewrite rule,
adds an adr-template.md scaffold, and plans a Status-header backfill of
ADRs 001-018. Basis for ADR-023.

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

6.7 KiB
Raw Blame History

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 (019022) have converged on a clean pattern (StatusContextDecisionConsequencesRelated), but it lives only as imitation; ADRs 001018 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 001018 are freeform; 019022 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 019022 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 backfill of ## Status into the ADRs that lack one.
  • Out (for now): rewriting the decisions in any existing ADR; normalizing the body section names of 001018 beyond adding Status; 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); a "Proposed" draft stage (rejected — boma is single-contributor and trunk-based with no review gate, so ADRs are born Accepted).

Decision

1. Title & filename

  • Title line: # ADR-NNN — <Title>: <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

Three states; no "Proposed" stage.

  • Born Accepted (YYYY-MM-DD) — the sole author commits to it on writing.
  • 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 backfill (001018)

A separate follow-up step after the ADR and template land: add a ## Status section to every ADR that lacks one. Status value is Accepted (YYYY-MM-DD) where the date is reconstructed from each file's first git-commit date. Only the Status header is added — no decision content is touched. ADRs already carrying a ## Status (019022) are left alone.

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 backfill commit touching ~18 files (Status header only).
  • /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 3-state lifecycle, template name (adr-template.md), enforcement (/review-repo, no CI gate), and the Status-only backfill were all confirmed during brainstorming.