Decision Docs Append-Only with Supersession
petrova intermediate 5 min read
ELI5
Decision docs are a courtroom transcript, not a wiki. You don’t go back and pencil corrections into yesterday’s verdict — you file a new verdict that explicitly overturns it, and the old verdict gets a “see new ruling” note pasted on top. Both stay readable.
Technical Deep Dive
Status lifecycle
stateDiagram-v2 [*] --> draft draft --> open : ratified by author open --> closed : human sign-off + outcome recorded closed --> superseded : new doc written that overturns this one superseded --> [*] closed --> [*] : remains canonical until/unless superseded note right of superseded Status flips by editing only the status line and adding the > Superseded blockquote — the body stays intact (MR-7). end noteThe full enum (docs/decisions/_template.md): draft, open, closed, superseded. Once closed, a doc’s body is frozen.
The supersession protocol (MR-7)
Two text changes happen together, in the same commit:
On the new doc (YYYY-MM-DD-<slug>.md):
## Supersedes- `docs/decisions/2026-04-26-soak-result.md` — superseded by this doc on <reason>. The original verdict is preserved for traceability.On the old doc, prepended above the existing body:
> **Superseded** by `docs/decisions/YYYY-MM-DD-<new>.md` on YYYY-MM-DD.> Original content preserved below for traceability.The old doc’s **Status:** line flips from closed to superseded. The old body remains untouched.
Why “fixing a typo” in a closed doc is the failure mode
Editing closed decision docs silently destroys lineage. From META-RULES.md MR-7:
“You do not edit a closed decision doc to ‘fix’ what it said. You write a new decision doc that supersedes it. … The lineage is part of the system’s memory. Editing closed docs silently destroys it.”
The pragmatic exception is truly mechanical (broken link, typo in heading). Even then, prefer a new note doc; the cost of a one-paragraph follow-up is much lower than the cost of a future reader being unable to reproduce why the closed verdict said what it said.
Filename + dating discipline (MR-4)
docs/decisions/YYYY-MM-DD-<slug>.md. The docs-invariants.yml CI workflow validates:
for f in $(find docs/decisions -maxdepth 1 -name '*.md' \ ! -name 'README.md' ! -name '_*' ! -name '_changelog.md'); do base=$(basename "$f") if ! [[ "$base" =~ ^[0-9]{4}-[0-9]{2}-[0-9]{2}-[a-z0-9-]+\.md$ ]]; then echo "MR-4 violation: $f does not match YYYY-MM-DD-<slug>.md" fail=1 fidoneFindings live under docs/findings/ with YYYYMMDD[-HHMM]-<slug>.md (no hyphens between date components — different filename grammar; both are validated).
CI catches the half-supersession
A common shape of failure: someone marks the old doc **Status:** superseded but forgets the > **Superseded-by:** blockquote (or vice versa). The CI workflow has a dedicated check:
if re.search(r'\*\*Status:\*\*\s*superseded', content, re.IGNORECASE): if not re.search(r'\*\*Superseded-by:\*\*\s*\S', content, re.IGNORECASE): print(f"MR-7 violation: {path} status=superseded but no Superseded-by link") fail = TrueSo the discipline does not rely on goodwill — half-supersessions fail the docs-invariants job before the PR can merge.
Templates and conventions
core/templates/docs/decisions/_template.md mandates: front-matter with rank: decisions + outranks:, a ## Context, a ## Decision, at least two ## Alternatives considered entries (the petrova-decide skill refuses fewer than two), ## Consequences, ## References, and a ## Sign-off block carrying agent + human signatures.
Real-life example: sub-project G chain
The recent G-series (decision-doc lineage in petrova-hq’s own ledger):
stateDiagram-v2 [*] --> g_open : 2026-05-06-sub-project-g-rocky-eva-surface-ratification.md (status: open) g_open --> g_close : 2026-05-06-sub-project-g-closure.md (closes G with ratified shapes) g_close --> [*]G.3 (commit 8d75cbe — feat(schema): G.3 simplify integration_eva.evidence per G.2 ratification) edited the schema; the closing decision doc cited G.2’s eva-hq ratification as grounding. Neither G-open nor G-close edits the other’s body — they reference each other.
Key Terms
- Supersession protocol — paired text changes (
## Supersedeson the new doc;> **Superseded** by ...blockquote on the old) that together flip an old doc’s status without editing its body. outranks:front-matter — every decision doc declares its rank tier and what it outranks; consumed by both the drift-watcher and the docs-invariants CI.- MR-7 — the “decision docs are append-only” meta-rule; the foundational invariant of the decision ledger.
Q&A
Q: What two text changes are required when one decision doc supersedes another?
A: (1) The new doc gets a ## Supersedes section listing the predecessor and the reason. (2) The old doc gets a > **Superseded** by <new path> on <date>. Original content preserved below for traceability. blockquote prepended, and its **Status:** line flips to superseded. Both edits land in the same commit.
Q: Why is editing a closed decision doc to fix a typo discouraged? A: Because the lineage is part of the system’s memory. Even tiny edits invite “while I’m in here” corrections, which silently rewrite history and break MR-7’s load-bearing property: that any reader can reproduce why a closed verdict said what it said. A short follow-up note doc costs almost nothing and preserves the property.
Q: How does the docs-invariants CI catch a half-supersession?
A: It greps every closed-or-later doc for **Status:** superseded and, when it finds one, requires a matching **Superseded-by:** <link> line. Either present without the other fails the job. So a half-supersession cannot merge.
Examples
A 2026-04-26 phase-close decision was overturned on 2026-05-01 because a new probe surfaced a regression. The 2026-05-01 doc carries ## Supersedes - docs/decisions/2026-04-26-phase-7-close.md — soak run regressed; re-classifying advisory as block. The 2026-04-26 doc gets the > **Superseded** by docs/decisions/2026-05-01-phase-7-close-amended.md on 2026-05-01. blockquote and its status flips to superseded. Both commits land together; CI passes.
neighbors on the map
- AuditTrail & Selective Disclosure implementing a compliance export that must only reveal disclosed audit entries
- Operations & Versions Schema writing a new sync query
- Retention Soft & Hard Delete auditing why a run vanished