ADR Lifecycle: Three Epochs and Tiered Edits
Context and Problem Statement
The 2026-10-02 audit of pull requests merged without human review found ADRs edited in place after acceptance: ADR-0041 and ADR-0096 by #4025, and ADR-0070 and ADR-0084 rewritten wholesale under their own numbers, their chosen option replaced weeks after acceptance. An agent, or a human, who cites an ADR by number then cites text that never said what the citation meant. The opposite failure also exists: superseding an ADR within hours of writing it leaves a trail of dead records for a decision that was never settled.
ADR status is the confidence signal agents read (MS-14, ADR-0043), but nothing ties it to how long the decision has stood or to who may change it and how.
When is an ADR free to edit, when must a human be asked, and when must the change be a new ADR?
Decision Drivers
- A citation of an ADR MUST keep meaning what it meant when it was written, once the decision has had time to be built on.
- A fresh decision needs to be fixable without ceremony while its author still holds the context.
- Agents implement against ADRs that no human has read yet; the human touch should be one specific, mandatory question, not a review gate on every edit.
- Elapsed time alone is the wrong signal that a decision has had its chance to be revised: it runs out over weekends and while an agent-written ADR sits unread, whether or not anyone is revising it.
- Every ADR must still harden eventually; none may stay undecided forever.
- The rule must be checkable from the repository alone: frontmatter, specs and tests, never a reviewer's memory.
Considered Options
- Immutable once written: every change is a new ADR.
- Edit in place freely, with git as the record.
- Three epochs measured from
updated, with edit tiers.
Decision Outcome
Chosen option: "Three epochs measured from updated, with edit tiers", because it is the only option that gives a fresh decision room to settle, protects a settled decision's citations, and names the point at which a human must decide.
Epoch 1 ends on the first test-verified dependent or a backstop timer, whichever comes first.
Frontmatter
created: the date the ADR was first written. Immutable.updated: the date of the last material edit. Editorial edits, annotations and appended clarifications do not change it.revision: an integer, starting at 1, incremented by each material edit.datekeeps its earlier meaning (the date first written) and is not changed.- Existing ADRs are migrated with
created = updated = dateandrevision = 1.
Epochs
The timers are measured from updated; the dependency event is not.
| Epoch | Ends | status |
Editing |
|---|---|---|---|
| 1 | at the first test-verified dependent, or day 14 | proposed |
Edit in place freely. |
| 2 | at day 28 | accepted-provisional |
Ask the human whether to edit in place or supersede. |
| 3 | never | accepted |
Supersede; see the edit tiers. |
A test-verified dependent is a spec requirement that cites the ADR in adr: and whose verification names a test file that exists, counted in the tree being checked: the pull request's head for a pull-request check, main for the scheduled report.
It is the signal the material test asks for: once something is built on the ADR, rewriting it freely can make that thing wrong.
The first dependent ends epoch 1 and nothing more; the first implementation is often where a detail turns out wrong, and fixing it in place with the human's yes is cheaper than a superseding ADR.
The pull request that creates it, whether by adding a requirement, by adding adr: or a verification to an existing one, or by adding the test file, must set the ADR to accepted-provisional in the same change, because it is the change that moved the facts; a check against the merge base enforces it.
The day-14 and day-28 timers are a backstop for an ADR nothing tests, so that every ADR eventually hardens.
A material edit bumps updated and restarts both timers, but not the dependency: an ADR that has a test-verified dependent never returns to epoch 1.
Status only moves forward.
The computed epoch is a floor: a status already ahead of it stands, so a change to these timers never demotes an ADR that agents have built on as accepted.
A material edit that restarts the timers keeps a status already ahead, under the status_override: the edit already needs.
A pull request that moves a status ahead of its epoch must add or change a status_override: naming a human's reason; an override already on the base does not cover a new promotion, and the override is visible in the frontmatter.
The clock alone never fails a merge-blocking check, because an ADR crossing a boundary changes no commit.
A pull request that materially edits an ADR (its updated date changes, or the ADR is new) must leave the status on the epoch for that date or carry a status_override:, and a diff-based check against the merge base enforces it (#4196).
A scheduled workflow reports every other ADR whose status is behind its epoch through one self-closing tracking issue and never fails the build; a human flips the status.
Agents and proposed ADRs
Agents implement against proposed ADRs.
A proposed ADR is not a draft awaiting approval before work may start; it is the working decision, and the mandatory human touch is the epoch-2 ask.
AGENTS.md's earlier wording that agents "propose architectural changes, not apply" is retired.
ADR-0115 (PR #4068) and ADR-0116 (PR #4078) are proposed under this rule.
Edit tiers
- Editorial and annotation. Typos, link repair, formatting, and append-only annotations (for example a dated human-ratification note naming the maintainer). Allowed in any epoch. Does not change
updatedorrevision. - Clarification. A change that does not alter what anything built on the ADR must do. After epoch 1, append it as a dated note; do not rewrite the original text. Does not change
updated. - Material change. A change that passes the material test: would something built on the old text now be wrong? It bumps
updatedandrevision, and follows the epoch rule above.
In epoch 3 a material change to one detail, with the chosen option intact, is a dated Amendment section that quotes the replaced text.
A change of the chosen option is a new ADR that supersedes the old one; the old one is restored to its original text, marked superseded, and moved to archived/ (MS-14-004).
Rewriting an accepted ADR under its own number is never correct.
Consequences
- Good, because citations of a settled ADR stay true.
- Good, because a fresh decision can be corrected cheaply.
- Good, because the human's required involvement is one question at a known moment.
- Good, because an ADR nothing builds on can be revised for two weeks, however long it waits unread.
- Bad, because every ADR needs three extra frontmatter fields and a status lint.
- Bad, because the epoch depends on the spec corpus as well as the frontmatter, so a pull request that never touches an ADR can be required to change its status.
- Bad, because the backstop is still a fixed clock; the dependency event and the human override exist for that reason.
Validation
AdrFrontmatter accepts created, updated and revision (vultron/metadata/adr/schema.py).
The status-against-epoch lint is #4196, the archive tooling is #4197, and the tooling for revision 2 is #4501.
MS-14-007 through MS-14-010 and MS-14-012 state the requirements.
More Information
The restoration of ADR-0041, ADR-0096, ADR-0070 and ADR-0084, and the annotations on ADR-0099, ADR-0111, ADR-0113 and ADR-0114, apply this rule retroactively; they are recorded under #4195.
notes/specs-vs-adrs.md describes the epochs and tiers for authors.
Generated spec requirements: meta-specifications.yaml MS-14-007, MS-14-008, MS-14-010, MS-14-012.