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>
6.7 KiB
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 aStatussection. - Becomes: ADR-023 (this design is the basis for that ADR).
- Reuses: boma's existing
*-template.mdconvention (service-security-template.md,service-verify-template.md,service-access-template.md,service-backup-template.md); ADR-014 (knowledge-sourcing → the optionalVerified factssection); ADR-019/020/021/022 (the emergent structure being codified); the/review-repocommand (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
## Statussection, 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 / Deprecatedstatus lifecycle and the no-silent-rewrite rule; cross-reference convention; an ADR template file; a lightweight/review-repostructure check; a one-time backfill of## Statusinto the ADRs that lack one. - Out (for now): rewriting the decisions in any existing ADR; normalizing the
body section names of 001–018 beyond adding
Status; amake lint/ CI gate for ADR structure (explicitly rejected in favour of the/review-repocheck — 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 recordsSupersedes ADR-MMMin its own## Statusand## 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 (001–018)
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
(019–022) 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-repogrows 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.