docs(adr): revise spec+plan — full retroactive restructure of 001-018
Replaces the Status-only backfill with a faithful presentational restructure bringing the whole back-catalogue to 4-section conformance (no grandfathering). Adds the faithfulness rule and per-file worklist. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
a3ea0f7d80
commit
89179dd7c9
2 changed files with 126 additions and 85 deletions
|
|
@ -23,7 +23,7 @@
|
|||
- **Status lifecycle (3 states):** `Accepted (YYYY-MM-DD)` → optionally `Superseded by ADR-NNN (YYYY-MM-DD)` or `Deprecated (YYYY-MM-DD)`. No "Proposed" stage.
|
||||
- **No silent rewrites:** material reversal = new ADR + `Superseded by` marker; bidirectional link.
|
||||
- **Enforcement checks presence + parseable Status line, NOT section order.** Order is demonstrated by the template, not machine-enforced.
|
||||
- **Backfill is Status-header-only** — no decision content touched.
|
||||
- **Back-catalogue is fully restructured (no grandfathering)** — ADRs 001–018 are brought to all-four-section conformance. The restructure is **presentational**: relabel/regroup/demote existing headings, add a dated Status, assemble a Consequences section from implications the ADR already states. **The substance of no decision is changed.** If a faithful Consequences cannot be drawn from existing content, escalate that file rather than inventing one.
|
||||
|
||||
---
|
||||
|
||||
|
|
@ -280,18 +280,20 @@ Create `docs/decisions/023-adr-structure.md`. It must pass its own check (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. Resolves the FRICTION signal (2026-05-31) about ADR-writing policy
|
||||
being unsettled.
|
||||
ship with it, and ADRs 001–018 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 (019–022) converged on a clean shape — Status → Context → Decision →
|
||||
Consequences → Related — but only by imitation, and ADRs 001–018 predate it: 001–015
|
||||
carry no `## Status` section at all, and 016–018 have a trailing build-status note
|
||||
rather than a lifecycle line. The result is structural drift and no uniform way to
|
||||
tell an active decision from a superseded or deprecated one.
|
||||
Consequences → Related — but only by imitation. ADRs 001–018 predate it and drifted
|
||||
widely: most lacked a `## Status` section entirely (016–018 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
|
||||
|
||||
|
|
@ -338,12 +340,22 @@ numbered ADR missing a mandatory section or with an unparseable Status line. It
|
|||
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 001–018 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.
|
||||
- One-time backfill churn: a Status header added to ADRs 001–018 (header only; no
|
||||
decision content changed).
|
||||
- The whole corpus conforms; the check needs no grandfathering and stays simple.
|
||||
- One-time restructure churn across ADRs 001–018 (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.
|
||||
|
||||
|
|
@ -354,8 +366,8 @@ doctrine ADRs adding no CI gate).
|
|||
the `/review-repo` check and the template suffice.
|
||||
- **Machine-enforcing section order** — brittle for marginal value; left as a
|
||||
template-demonstrated convention.
|
||||
- **Normalizing the body of 001–018** beyond adding `## Status` — out of scope; the
|
||||
decisions themselves are untouched.
|
||||
- **Grandfathering 001–018 from the check** — rejected in favour of restructuring the
|
||||
whole corpus to conform, so the standard applies uniformly with no exceptions.
|
||||
|
||||
## Related
|
||||
|
||||
|
|
@ -428,92 +440,96 @@ Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>"
|
|||
|
||||
---
|
||||
|
||||
## Task 5: Backfill `## Status` into ADRs 001–018
|
||||
## Task 5: Retroactively restructure ADRs 001–018 to full conformance
|
||||
|
||||
**Files:**
|
||||
- Modify: `docs/decisions/001-architecture.md` … `015-control-host.md` (insert a Status section)
|
||||
- Modify: `docs/decisions/016-mesh-vpn.md`, `017-service-ui-verification.md`, `018-logging.md` (prepend a parseable Accepted line to the existing Status section)
|
||||
**Goal:** every ADR in 001–018 ends with all four mandatory sections present and a
|
||||
parseable Status line, so the `adr-structure` check reports zero findings — **without
|
||||
changing the substance of any decision.**
|
||||
|
||||
**Files (current findings — the exact worklist):**
|
||||
- Missing `Status` + `Consequences`: `001-architecture.md`, `002-security.md`, `004-docker-model.md`, `005-bootstrapping.md`, `014-knowledge-sourcing.md`
|
||||
- Missing `Status` + `Decision` + `Consequences`: `006-terraform.md`, `007-network.md`, `008-testing.md`, `009-provisioning-handoff.md`, `010-forgejo-ci.md`, `011-update-management.md`
|
||||
- Missing all four: `003-toolchain.md`
|
||||
- Missing `Status` + `Decision`: `013-heritage-v4.md`
|
||||
- Missing `Status` only: `012-hardware-capacity.md`, `015-control-host.md`
|
||||
- Have unparseable `Status` + missing `Consequences`: `016-mesh-vpn.md`, `017-service-ui-verification.md`, `018-logging.md`
|
||||
|
||||
(`010`/`011` use `## Decisions` (plural) → relabel to `## Decision`. The "missing
|
||||
Decision" cases generally have the decision spread across topical `##` headings.)
|
||||
|
||||
**THE FAITHFULNESS RULE (non-negotiable):** This is a *presentational* restructure.
|
||||
You MAY: add a `## Status` section; relabel a heading (`## Decisions` → `## Decision`);
|
||||
introduce a `## Decision` umbrella heading and **demote** existing topical `##` headings
|
||||
to `###` beneath it; add a `## Consequences` section. You MUST NOT alter any existing
|
||||
sentence of decision prose, reword arguments, or add new policy. A `## Consequences`
|
||||
section is assembled **only** from implications the ADR already states (its trade-offs,
|
||||
"what was ruled out", "open questions", named follow-on work). **If an ADR states
|
||||
nothing that can be faithfully cast as a consequence, STOP and report it as
|
||||
DONE_WITH_CONCERNS / escalate — do not invent consequences.**
|
||||
|
||||
**Per-file date source:** the file's first git-commit (add) date —
|
||||
`git log --diff-filter=A --format=%as -- <path> | tail -1` (yields `YYYY-MM-DD`).
|
||||
|
||||
- [ ] **Step 1: For each of 001–015, insert a Status section after the title**
|
||||
- [ ] **Step 1: Add a dated `## Status` section to each ADR**
|
||||
|
||||
For each file `docs/decisions/NNN-*.md` in 001–015, get its date and insert a Status
|
||||
section between the title line and the first `##` heading. Worked example for
|
||||
`001-architecture.md` (its line 2 is blank, line 3 is `## Context`):
|
||||
|
||||
```bash
|
||||
f=docs/decisions/001-architecture.md
|
||||
d=$(git log --diff-filter=A --format=%as -- "$f" | tail -1)
|
||||
# Insert after the title's trailing blank line, before "## Context":
|
||||
```
|
||||
|
||||
Use the Edit tool to change, in `001-architecture.md`:
|
||||
For 001–015 (no Status today): insert, between the title line and the first `##`
|
||||
heading, a Status section:
|
||||
|
||||
```markdown
|
||||
# ADR-001 — Architecture overview
|
||||
|
||||
## Context
|
||||
```
|
||||
|
||||
to:
|
||||
|
||||
```markdown
|
||||
# ADR-001 — Architecture overview
|
||||
|
||||
## Status
|
||||
|
||||
Accepted (<d>)
|
||||
|
||||
## Context
|
||||
```
|
||||
|
||||
where `<d>` is the date from the command above. Repeat for 002–015, matching each
|
||||
file's actual title text and its first `##` heading (the heading is not always
|
||||
`## Context`).
|
||||
where `<d>` is the file's first-git-commit date. For 016/017/018 (unparseable Status
|
||||
today): prepend a parseable `Accepted (<d>). ` clause to the first line of their
|
||||
existing `## Status` section so the build-state note becomes its tail, e.g.
|
||||
`Accepted (2026-06-05). Designed. **Authorable now:** ...`.
|
||||
|
||||
- [ ] **Step 2: For 016, 017, 018, make the existing Status section parseable**
|
||||
- [ ] **Step 2: Ensure a `## Decision` section exists**
|
||||
|
||||
These already have a `## Status` section whose first line is build-state prose. Get the
|
||||
date (`git log --diff-filter=A --format=%as -- <path> | tail -1`) and prepend a
|
||||
parseable Accepted line so the existing note becomes a trailing clause. Worked example
|
||||
for `018-logging.md` — change its Status section from:
|
||||
For ADRs flagged "missing Decision" (003, 006, 007, 008, 009, 010, 011, 013): relabel a
|
||||
plural/synonym heading where one exists (`## Decisions` → `## Decision` in 010/011), or
|
||||
introduce a `## Decision` umbrella immediately after `## Context` and demote the existing
|
||||
topical `##` body headings (e.g. in 003: "Execution engine", "Python environment", …) to
|
||||
`###`. Do not move or rewrite the prose under them.
|
||||
|
||||
```markdown
|
||||
## Status
|
||||
- [ ] **Step 3: Ensure a `## Consequences` section exists**
|
||||
|
||||
Designed. **Authorable now:** ...
|
||||
```
|
||||
For every ADR flagged "missing Consequences" (001, 002, 003, 004, 005, 006, 007, 008,
|
||||
009, 010, 011, 014, 016, 017, 018): add a `## Consequences` section near the end,
|
||||
assembled strictly from implications the ADR already states. Where an ADR has a trailing
|
||||
section that *is* consequences under another name (e.g. "What was ruled out", "Open
|
||||
questions", "Trade-offs"), you may keep that section and add a short `## Consequences`
|
||||
that references/summarizes the already-stated trade-offs — without introducing new
|
||||
claims. **Honour the faithfulness rule; escalate any ADR where no faithful Consequences
|
||||
can be drawn.**
|
||||
|
||||
to:
|
||||
|
||||
```markdown
|
||||
## Status
|
||||
|
||||
Accepted (<d>). Designed. **Authorable now:** ...
|
||||
```
|
||||
|
||||
Repeat for 016 and 017 with their own dates and existing first lines.
|
||||
|
||||
- [ ] **Step 3: Verify the whole corpus now passes the check**
|
||||
- [ ] **Step 4: Verify the whole corpus passes the check**
|
||||
|
||||
Run: `python3 scripts/repo-scan.py 2>/dev/null | python3 -c "import json,sys; v=[f for f in json.load(sys.stdin)['findings'] if f['check']=='adr-structure']; print('adr-structure findings:', len(v)); [print(' ', f['path'], '—', f['detail']) for f in v]"`
|
||||
Expected: `adr-structure findings: 0`.
|
||||
|
||||
- [ ] **Step 4: Run the full repo-scan test suite**
|
||||
- [ ] **Step 5: Verify faithfulness via diff**
|
||||
|
||||
Run: `git diff --stat` and spot-check `git diff docs/decisions/003-toolchain.md`.
|
||||
Expected: changes are heading additions/relabels/level-demotions, a new Status section,
|
||||
and a new Consequences section — **no edits to existing decision sentences.**
|
||||
|
||||
- [ ] **Step 6: Run the repo-scan test suite**
|
||||
|
||||
Run: `.venv/bin/pytest tests/test_repo_scan.py -q`
|
||||
Expected: PASS — 5 passed.
|
||||
|
||||
- [ ] **Step 5: Commit**
|
||||
- [ ] **Step 7: Commit**
|
||||
|
||||
```bash
|
||||
git add docs/decisions/0*.md docs/decisions/1*.md
|
||||
git commit -m "docs(adr): backfill Status section into ADRs 001-018
|
||||
git commit -m "docs(adr): restructure ADRs 001-018 to ADR-023 conformance
|
||||
|
||||
Status header only (Accepted, dated from each file's first git-commit);
|
||||
no decision content changed. Brings the back-catalogue to ADR-023 conformance.
|
||||
Presentational only: add a dated Status section, relabel/regroup headings
|
||||
under Decision, and add a Consequences section assembled from each ADR's
|
||||
already-stated implications. No decision substance changed.
|
||||
|
||||
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>"
|
||||
```
|
||||
|
|
@ -531,6 +547,6 @@ Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>"
|
|||
|
||||
## Self-review notes
|
||||
|
||||
- **Spec coverage:** §1 title/filename → Task 3 + template; §2 sections → Tasks 2/3 + check; §3 lifecycle → Task 3; §4 cross-refs → Task 3 `## Related`; §5 template → Task 2; §6 backfill → Task 5; §7 enforcement → Task 1 + Task 4. All covered.
|
||||
- **Spec coverage:** §1 title/filename → Task 3 + template; §2 sections → Tasks 2/3 + check; §3 lifecycle → Task 3; §4 cross-refs → Task 3 `## Related`; §5 template → Task 2; §6 retroactive restructure → Task 5; §7 enforcement → Task 1 + Task 4. All covered.
|
||||
- **Order nuance:** spec says sections come "in this order"; the check enforces presence + Status only. This is intentional and stated in both the spec's enforcement wording ("the four mandatory sections and a parseable Status line") and ADR-023's Decision §5 / "What was ruled out". Not a gap.
|
||||
- **Type/name consistency:** `adr_structure_findings` and the `"adr-structure"` check key are used identically in the function, the `scan()` wiring, the tests, and both verification one-liners.
|
||||
|
|
|
|||
|
|
@ -39,14 +39,17 @@ lifecycle, ships a template, and reconciles the back-catalogue.
|
|||
- **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 001–018 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).
|
||||
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); a "Proposed" draft stage (rejected — boma is
|
||||
single-contributor and trunk-based with no review gate, so ADRs are born Accepted);
|
||||
grandfathering pre-convention ADRs from the check (rejected — the whole corpus is
|
||||
brought to conformance instead).
|
||||
|
||||
## Decision
|
||||
|
||||
|
|
@ -103,12 +106,29 @@ 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.
|
||||
### 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:
|
||||
|
|
@ -120,7 +140,11 @@ a parseable `## Status` line. The template carries the convention forward for ne
|
|||
- 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).
|
||||
- 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.
|
||||
|
|
@ -128,5 +152,6 @@ a parseable `## Status` line. The template carries the convention forward for ne
|
|||
## 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.
|
||||
(`adr-template.md`), enforcement (`/review-repo`, no CI gate), and the **full
|
||||
retroactive restructure** of 001–018 (no grandfathering) were all confirmed during
|
||||
brainstorming.
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue