Change lifecycle
Rendered from spec at76d46f3 (2026-10-25) · its source · Edit this page
Status: Accepted
How a change moves from idea to merged code across the spec and the repositories built against it.
The shape
flowchart TD
idea[Idea, bug, or request] --> kind{Does it change<br/>product behaviour?}
kind -->|Yes| specpr[Spec PR<br/>new or altered requirement]
kind -->|No| gov[Cite a GOV-R<br/>routine maintenance]
specpr --> review[Review: is this what<br/>we want the product to do?]
review -->|merged| impl[Implementation PR<br/>cites the requirement]
review -->|rejected| stop[No implementation happens]
gov --> impl
impl --> bot{Bot checks}
bot -->|citation resolves| merge[Merged]
bot -->|does not resolve| closed[Closed with guidance]
closed --> impl
The important edge is review --> impl: implementation begins after the spec
change merges, not alongside it.
A proposal from outside the maintainers enters one step earlier, as an RFC issue: the issue is the source of truth until a maintainer approves it, at which point the automation opens the spec PR above on the contributor’s behalf. The review, and everything after it, is identical.
Why spec-first, rather than together
Two PRs in flight simultaneously look tidier and are worse:
| Together | Spec-first |
|---|---|
| Reviewer sees behaviour and implementation at once | Reviewer answers “is this what the product should do?” without being anchored by working code |
| The spec change is shaped to match code already written | The code is shaped to match a decision already made |
| If the implementation is abandoned, the spec change is orphaned | The spec stands alone and remains true |
| Citation cannot be verified — the requirement isn’t merged yet | Citation resolves mechanically |
The second row is the substantive one. Reviewing a design next to its implementation reliably produces approval of the implementation, because working code is persuasive in a way a proposal isn’t. Separating them restores the question.
The three paths
1. New or changed behaviour
1. Open a spec PR adding or amending a requirement.
2. Review answers: should the product do this?
3. Merge.
4. Open the implementation PR citing the new ID.
The spec PR is often small — one requirement row and a paragraph of behaviour. It is not a document-writing exercise.
2. Implementing something already specified
Most work. The requirement exists; cite it and implement.
Spec: B2-R1, B2-R8
No spec PR needed — the decision was already made, possibly months earlier.
3. Routine maintenance
Dependency bumps, formatting, CI configuration, typo fixes. Cite GOV-R12.
chore: bump tokio to 1.48
Spec: GOV-R12
The community path — RFCs
The three paths above assume repo access. An idea from outside the maintainers enters through the RFC process instead: an issue form collects the proposal, a maintainer approves it on the issue, and only then does the automation scaffold a Draft and open the spec PR — after which it rejoins path 1’s review. No git is required of the contributor, and the issue remains the source of truth until the Draft merges and becomes Accepted.
When implementation reveals the spec is wrong
This will happen, and it’s the most interesting case. Implementation surfaces things design cannot — an interaction that doesn’t work, a requirement that’s impossible, two requirements that contradict.
Stop and fix the spec. Open a spec PR describing what was learned and what should change; merge it; continue.
What must not happen is implementing the better behaviour and leaving the spec describing the worse one. That is precisely the drift the rule exists to prevent, and it is most tempting exactly here — the code works, the deadline is close, and the spec change feels like paperwork.
If the discovery is urgent, that’s what the override is for: merge now, with the justification recorded, and correct the spec immediately after.
Bidirectional obligation
GOV-R7: a spec change altering an accepted requirement must state which implementation repos are affected.
This stops the spec drifting ahead into fiction — a specification describing behaviour nobody has built is as misleading as one describing behaviour that was replaced. Naming the affected repos makes the gap visible, and tracking issues are opened there.
Status vocabulary
| Status | Meaning |
|---|---|
| Draft | Proposed, not binding. Implementation MUST NOT cite it. |
| Accepted | Binding. Citable. |
| Superseded | Replaced; links to its replacement. Not citable for new work. |
| Withdrawn | Removed. Its number is retired permanently (GOV-R8). |
Draft requirements are not citable — otherwise the ordering guarantee collapses,
since anyone could merge a draft and implement against it in the same breath.
The gate refuses a trailer citing one (GOV-R48), saying it is Draft and which
document defines it. A requirement is Draft when the document defining it is: a
feature’s frontmatter status:, or the **Status:** line every other document
opens with. It is also Draft when its own row opens with *Draft:*, which is how
an approved proposal’s requirement sits in an Accepted feature until a pull
request removes the marker and so hardens it (rfc-process.md).
A Draft row is never a version’s goal.
A retired number is not a citation either, and the gate now says so
(GOV-R47). A withdrawal is recorded in place: the row stays so the number is
visibly gone rather than missing, which is what stops it being reused. That is
the right shape for the spec and the wrong answer for spec-check, which
resolved the row and passed — so an implementation could cite F3-R20, which has
been withdrawn for two versions, and be told nothing. It is refused now with the
sentence its own row carries, which names where the work went; being told a
number that plainly exists does not is the unhelpful half of the same refusal.
Related
- canonical-spec.md — the rule and the
GOV-Rnamespace - cross-repo-ci.md — how the ordering is enforced
- rfc-process.md — the community front-door that feeds this flow
- contributing.md — the same flow, from a contributor’s side
- overrides.md