← The specification

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.