Diff
## Summary
Add a notion of *stage* to Requested documents so RFCs can advertise where they are in their lifecycle — draft, open for comment, accepted, withdrawn — and so comments can be contextualized accordingly.
This is itself a Requested RFC. It's partly an honest proposal and partly a live demo of what the tool is for, so the comments matter more than the resolution.
## Motivation
A Requested document currently has two observable states: it exists, and it has some number of versions. Nothing tells a reader whether the author considers it:
- a half-formed thought from yesterday,
- a serious proposal actively soliciting feedback,
- a decided thing no longer accepting comment, or
- a withdrawn idea kept visible for posterity.
That distinction is the whole point of most RFC processes. Without it, every doc looks equivalently weighty, and commenters can't tell whether their feedback is welcome or whether they're arguing with someone's frozen position.
## Prior art
- **TC39** uses numeric [stages 0–4](https://tc39.es/process-document/). Advancement requires committee consensus; stages are linear and ordinal.
- **Python PEPs** use a status field (Draft / Active / Accepted / Final / Rejected / Withdrawn / Superseded).
- **IETF** uses Internet-Draft / Proposed Standard / Internet Standard / Historic.
- **Oxide RFDs** use a [state field](https://rfd.shared.oxide.computer/rfd/0001#_rfd_metadata_and_state) (prediscussion / ideation / discussion / published / committed / abandoned), but two of these reflect distinctions which may not be relevant here:
- ideation is smaller + less active than prediscussion
- published is a [determination](https://rfd.shared.oxide.computer/rfd/0005#_determination) of what to implement into a fully committed solution
Common thread: a small enumerated set of states, a roughly linear transition graph, and provenance for who advanced what and when.
## Proposed stage set
| stage | meaning |
|---|---|
| `draft` | Author is still writing. Comments welcome but everything is fluid. |
| `proposed` | Author considers this ready for serious feedback. The "open for comment" state. |
| `final-comment` | Author is preparing to lock the doc. Last call. |
| `accepted` | Author has decided. Doc is frozen; comments archived. |
| `withdrawn` | Author has abandoned the doc but is keeping it visible for context. |
Open questions on the set itself:
1. Five feels right, but four would also work — drop `final-comment` and let the author signal it informally in the body.
2. Should `accepted` and `withdrawn` be distinct, or collapsed into `closed` with a reason field?
3. Do we need a `superseded` state for docs replaced by a later proposal? (PEPs have it; TC39 doesn't.)
4. Should `draft` be the implicit default for newly-created documents, or should "unset" be a real state?
## Lexicon encoding
The interesting design question. Four options, in roughly increasing order of ceremony.
### Option A — field on `document`
```
fyi.requested.document.stage: string (knownValues: draft, proposed, ...)
```
Simplest. One mutable field on the existing record; bumping stage is a single `putRecord`. No history, no provenance — the author can rewrite the stage silently. Fine if you trust authors not to lie about their own docs (which, for a v1 personal-publishing tool, is probably fine).
### Option B — field on `documentVersion`
```
fyi.requested.documentVersion.stage: string
```
Each immutable version snapshot records its stage. Stage history falls out of the version chain for free. Comments — already pinned to a version CID — automatically carry the stage they were written against, so "show me all comments written while this was `proposed`" is a free query.
Cost: bumping the stage requires minting a new version even when the body hasn't changed. Arguably a feature: a stage transition *is* a meaningful checkpoint, and freezing the body at that moment is what the version chain is for.
### Option C — separate `stageTransition` record
```
fyi.requested.stageTransition {
document: at-uri,
version?: strongRef,
stage: string,
note?: string,
createdAt: datetime,
}
```
Each transition is its own record on the author's PDS. Current stage = most recent transition. Clean audit log, room for transition commentary ("Moving to FCP — API feels settled, last call on naming"), no need to mint a version for stage-only changes.
Cost: a new NSID and an extra `listRecords` call (or Constellation query) on every doc render.
### Option D — endorsements from other PDSes
```
fyi.requested.endorsement {
document: at-uri,
version: strongRef,
endorsedStage: string,
createdAt: datetime,
}
```
Stage advancement requires N endorsements from designated maintainers, each publishing on their own PDS. The atproto-native end state — no central committee, just a quorum visible across repos.
Out of scope for v1 (Requested has no concept of "maintainer" yet), but worth designing toward so we don't paint ourselves into a corner.
### Recommendation
Start with **B**. It piggybacks on machinery we already have, makes "what stage was this comment written against?" answerable for free, and forces a body checkpoint at each transition. The "every stage bump mints a version" objection is the actual feature.
Promote to **C** if/when authors complain about version-chain noise, or when transition notes start to matter. Hold D in reserve.
Also: stage values should be a `knownValues` open string, not a closed `enum`. Forks of Requested may want their own process names, and atproto idiom is to keep these open.
## UI implications
Assuming B:
- **Stage badge** on the document header, color-coded by stage.
- **Progression indicator** — TC39-style `● ● ○ ○ ○` is tempting but probably overkill for five stages. A single badge is enough.
- **Home page (`/`)** groups the signed-in user's docs by stage. `withdrawn` collapsed by default.
- **Comment composer** soft-warns when commenting on an `accepted` or `withdrawn` doc: "this doc is closed — your comment will be visible but the author has stopped iterating."
- **History view** distinguishes stage-only versions from substantive edits (small icon, dimmed row) so the chain stays readable.
- **Diff view** surfaces the stage transition in the header alongside the body diff.
## Open questions
1. Can authors *demote* a stage (`accepted` → `proposed`)? They own the doc, so yes — but the UI should make it visible rather than silent.
2. Should comments themselves carry a stage hint, or is the version-CID linkage enough?
3. Is there a place for **reader-side filtering** on a future global discovery view ("show me docs in `proposed` or `final-comment` only")?
4. How does this interact with private/unlisted docs, if those ever exist?
## Non-goals
- Committee voting or multi-author governance. That's Option D territory; not now.
- Automatic stage transitions based on time or comment activity. Stage is an author signal, not derived state.
- Cross-document dependency tracking ("this doc supersedes that one"). Interesting but orthogonal.