docs(governance): allow in-place refinement of accepted ADRs (refine vs. supersede)#382
Conversation
Replace the strict-immutability rule in docs/decisions/README.md ("do not
edit the original") with the mainstream refine-in-place vs. supersede-on-
reversal model, and add the bookkeeping that makes in-place refinement
auditable.
- Distinguish lifecycle state (proposed/accepted/superseded/deprecated)
from the orthogonal mutability operation (refine vs. supersede).
- Add a boundary test: if the action a reader takes is unchanged it is a
refinement (edit in place); if a past reader would now act differently it
is a reversal (new superseding ADR).
- Add a parallel "Changing an accepted ADR" table (Refinement / Reversal /
Obsolescence).
- Add optional **Last-updated:** field (distinct from immutable **Date:** =
decision date) and a ## Changelog convention to the template.
- Cite precedent (Joel Parker Henderson; MADR last-updated date).
- Regenerate the Starlight mirror.
Removes the contradiction with ADR-012 ("existing ADRs are updated
incrementally") and unblocks the ADR-003 decomposition (#186).
Refs #380
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
theagenticguy
left a comment
There was a problem hiding this comment.
Code-critic review — Approve with 2 minor fixes (docs-only, CI green 8/8).
The core change is correct: it resolves a genuine contradiction between the old README rule ("do not edit the original") and ADR-012's "existing ADRs are updated incrementally (not rewritten)." Source and the Starlight mirror are byte-identical in the changed regions, the #changing-an-accepted-adr-refine-in-place-vs-supersede anchor resolves, and the boundary test (action-unchanged → refine; reader-would-act-differently → supersede) is a clean rule.
Two factual nits in the closing paragraph, left as inline suggestions you can apply and resolve:
- MADR claim is inaccurate. MADR's template has a single
datefield meaning "when the decision was last updated" — it does not track a last-updated date distinct from the decision date. This standard's two-field design (immutableDate:+ separateLast-updated:) is actually stronger than MADR, so MADR isn't precedent for the distinction. - Henderson quote isn't verbatim. The source is two sentences ("In theory, immutability is ideal. In practice, mutability has worked better for our teams."); the PR merges them with a semicolon and lowercases the opening. Words are exact; punctuation is altered. Substance is faithful — his "mutability" means append dated notes to a living document, which is exactly the Changelog +
Last-updatedmodel.
Plus one non-blocking nit on the template's Changelog placeholder.
After applying any suggestion to docs/decisions/README.md, re-run mise //docs:sync to regenerate docs/src/content/docs/decisions/Readme.md. Applying a suggestion edits only the source, and the mirror must not be hand-edited (per AGENTS.md). The two are in sync now; don't let an applied suggestion silently break that parity.
… Changelog)
- Henderson quote: restore verbatim two-sentence form ("In theory,
immutability is ideal. In practice, mutability has worked better for our
teams.").
- MADR: correct the claim — MADR uses a single `date` field ("last updated"),
not a last-updated date distinct from the decision date; note that this
standard's two-field design (immutable `Date:` + separate `Last-updated:`)
goes further.
- Changelog template: make "omit when first creating" explicit so a freshly
copied template doesn't ship a present-but-empty section.
- Regenerate Starlight mirror.
Refs #380
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
|
Thanks @theagenticguy — all three applied in
Starlight mirror regenerated; rebased onto the latest branch state (post-#371 merge). Ready for re-review. |
theagenticguy
left a comment
There was a problem hiding this comment.
Approved. Both review nits addressed in b755f4cf5d, verified against the head:
- Henderson quote — now the verbatim two-sentence form ("In theory, immutability is ideal. In practice, mutability has worked better for our teams."). ✓
- MADR claim — corrected: it now states MADR uses a single
datefield meaning "when the decision was last updated," and that this standard goes further by keepingDate:immutable and recording refinements separately. Accurate, and it now reads as the stronger design rather than borrowing false precedent. ✓ - Changelog placeholder — "omit when first creating the ADR; add on the first in-place refinement." Closes the empty-section-on-creation gap. ✓
Source ↔ mirror parity holds — the fix touched both docs/decisions/README.md and the Starlight mirror docs/src/content/docs/decisions/Readme.md (+2/−2 each); their bodies are byte-identical. The mise //docs:sync caveat I flagged was respected.
CI is green across all 8 checks on this head. The change resolves the real contradiction with ADR-012's incremental-update language and unblocks the ADR-003 decomposition (#186). Good to merge.
The fork's main (isadeks/main) was 64 commits stale, making GitHub report linear-vercel as '60 behind'. Against real upstream (aws-samples/main), linear-vercel was only 5 commits behind. Merge those in to be fully current: - ephemeral stack cleanup script (aws-samples#109) - dependency upgrade (aws-samples#367) - ADR governance: in-place refinement (aws-samples#382) - test-perf: disable Lambda bundling in unit-test synths (aws-samples#366/aws-samples#371) - jira: reactive token refresh + retry on 401 (aws-samples#370/aws-samples#375) Clean merge, zero conflicts (linear-vercel's foundation was already current — merge-base 0e2806a, 2026-06-17).
Summary
Amends the ADR standard (
docs/decisions/README.md) to replace strict immutability with the mainstream refine-in-place vs. supersede-on-reversal model, and adds the bookkeeping that makes in-place refinement auditable.Closes #380.
Area
docs— guides or design sources (docs/decisions/)What changed
proposed → accepted → superseded/deprecated, about the decision) vs. mutability operation (refine vs. supersede, about a change in hand). The status table is unchanged; a new parallel "Changing an accepted ADR" table is added beside it.Date:stays immutable = the decision/acceptance date (the historical anchor). New optionalLast-updated:records in-place refinements; a new## Changelogsection records what changed.git logremains the byte-level backup, not the primary record.Why
The old rule ("do not edit the original") contradicted ADR-012 ("existing ADRs are updated incrementally, not rewritten") and was stricter than the standards it derives from. It also blocked the ADR-003 decomposition (#186) — extracting prose to a guide is an in-place edit of an accepted ADR.
Test plan
astro check— 0 errors, 0 warnings, 0 hintsForward-looking design notes (to be refined as #381 / #246 are implemented)
These are recorded here as the rationale that motivated this amendment and the follow-on graph work (#381). They are not implemented by this PR — they are preserved so the reasoning survives, and will be refined by decisions as they land. The README change here is deliberately the minimal sanctioning of in-place refinement; the items below are where it leads.
Thought 1 — Separate decision lifecycle from implementation maturity
"Further states after
accepted" (operationalized, enforced, validated, has-a-skill) do not belong in the ADR. An ADR has exactly one axis of state: is this decision live? (proposed → accepted → superseded/deprecated) — that's about the idea. Operationalized/enforced/validated describe the artifacts the decision spawned, a different axis.Cautionary example already in-tree: ADR-003's enforcement table has a
Status: Implemented/Plannedcolumn — implementation maturity living inside an ADR, exactly the thing that goes stale (it still says "Planned" for the commit-msg hook even though #186 may move it). ADR-012's own content rule says ADRs "MUST NOT contain checklists with >3 items" — that table is in tension with the standard it ships alongside.Position: don't store maturity in the ADR — derive it from the graph. An ADR is "operationalized" iff ≥1 persona references it; "enforced" iff a skill/hook implements it; "validated" iff that skill has tests. Computed by walking references, not hand-edited fields that rot. Keeps the ADR immutable-where-it-should-be (the decision) and mutable-where-it-must-be (everything downstream) — the natural extension of the refine-in-place model this PR introduces.
Thought 2 — The reference graph is many-to-many (a refinement of ADR-012)
ADR-012 currently says references point upward only in a strict tree (Skill → Guide → ADR). The persona framing breaks the tree:
Three facts the tree can't express:
validate-dependenciesserve Implementor and Planner).So it's a bipartite-ish many-to-many graph, not a hierarchy. Amending ADR-012's "Reference direction" section is itself a refinement (clarifying/extending, not reversing the three-layer decision) — making it the first real exercise of the refine-in-place path this PR adds. The model validates itself. Tracked in #381.
Thought 3 — Bidirectional backlinks + parity linter (staleness, made mechanical)
"Bidirectional reference consistency may be easier than a full repository read." This is the concrete fix for the risk ADR-012 flags but doesn't solve: "(!) Reference chain integrity must be maintained — a broken link means drift goes undetected."
Edges declared in frontmatter on both endpoints, checked by a script:
Invariant: every declared edge must be reciprocated on the other end. A linter walks all frontmatter, builds the graph, and fails CI on any one-directional edge — O(edges), mechanical, no semantic reading. Honest limit: this verifies structural consistency, not semantic freshness (that a skill still reflects the ADR's intent) — that stays a human/agent judgment. Tracked in #381; must be reconciled with #246 (agent asset registry) before that work begins.
Acknowledgment
By submitting this pull request, I confirm that you can use, modify, copy, and redistribute this contribution, under the terms of the project license.
🤖 Generated with Claude Code