Files
deepseek-harness/docs/rfc/implemented/process/2026-07-05-uniform-rfc-format.md

5.4 KiB

RFC: One gated in-file format for RFCs

Status: implemented

Problem

The tree's layout is uniform — the classification scheme path-encodes lifecycle and class and gates both — but the file insides never were. The corpus the format decision faced had two H1 spellings; some twenty-seven Status: line spellings once free-text rejection reasons are collapsed — bare enums, dated parentheticals duplicating what the filename and git already carry — plus three English files (and the zh counterpart of one of them) with no status at all; two body genres side by side (ADR-style Context/Decision/Consequences beside proposal-style Problem/Proposal/Risks), so every new RFC guessed its shape from whichever neighbor its author opened; thirty-nine files carrying a debt comment that flagged them as "legacy ADR/RFC body format" awaiting a unified template that was never actually defined; and nineteen implemented RFCs still carrying thirty occurrences of the proposal-era headings (Acceptance criteria, Plan, Migration plan, Proposal) that the documentation standard's slop checklist outlaws for implemented/ — outlawed, but enforced by nothing, so the proposed/implemented/ move could silently skip the rewrite implemented/AGENTS.md requires.

Decision

README.md § The file format is the in-file contract — the header block (# RFC: <title> plus a dateless, folder-agreeing Status: enum whose only content is the rejection reason), the per-lifecycle body skeleton (Problem opener everywhere; Proposal/Acceptance criteria/Risks in proposed/; present-tense Decision/Consequences with proposal-era headings banned in implemented/; frozen proposal shape in rejected/), a mandatory Alternatives considered section, and the canonical section vocabulary between which bespoke technical sections stay free-form. pnpm run verify-rfc-format (scripts/verify-rfc-format.ts) enforces every mechanical clause as part of doc-sync, so a lifecycle move that skips its rewrite now fails CI instead of review memory.

The whole corpus was normalized in the same change that defined the format — the pre-release stance: no transition period, no dual-format tolerance. The one grandfather is content, not format: alternatives are recorded, never invented, so a pre-format RFC whose alternatives are not reconstructible from the record carries the exact rfc-format: alternatives-not-recorded comment, which the gate accepts only for files dated before this RFC.

Alternatives considered

  • A full rigid template (one fixed section sequence per lifecycle, every RFC restructured to fit) — rejected: the big design RFCs carry eight to fifteen bespoke technical sections (package topology, wire contracts, schemas) that are load-bearing content, not drift; a rigid sequence would force destructive rewrites now and template-fighting forever.
  • Header-only normalization (H1 and Status, bodies untouched) — rejected: the debt markers flagged the body genre split, and leaving Context/Decision beside Problem/Proposal indefinitely resolves nothing.
  • No Status line (the folder already is the status; the three newest pre-format RFCs (and the zh counterpart of one) omitted the line) — rejected in favor of keeping a self-describing file: the drift risk that motivated dropping it is neutralized by gating the line against the folder instead.
  • Dated status (Status: implemented (accepted YYYY-MM-DD)) — rejected: the acceptance date is narrated history the writing rules keep out of docs; the filename carries first-proposed, git carries the rest, and the gate could check a date's format but never its truth.
  • A bare # <title> H1 — rejected: the RFC: prefix is the corpus-majority form and self-describes the genre when a file is read outside its tree; the index generator strips it, so index rows are identical either way.
  • ## What we give up as the implemented closer (the README's own phrase for what an RFC records) — rejected: it names only costs, and an honest consequences section records what the trade-off bought as well.
  • Convention without a gate (write the contract down, enforce by review) — rejected: the slop checklist already outlawed spec-speak in implemented/ by convention, and nineteen files show what convention alone achieves here.
  • A standalone FORMAT.md contract file — the first landed home; folded into README.md once the generated index moved out to INDEX.md: with the tables gone the README regained the room, and one front door carrying layout, classification, and format beats splitting the contract across two files.

Consequences

Every RFC now costs slightly more structure, and the mandatory Alternatives considered section is deliberate friction: a decision recorded without what it beat invites the re-litigation RFCs exist to prevent. Pre-format RFCs whose alternatives were not reconstructible carry the grandfather comment permanently — an honest gap on the record rather than fabricated rationale. doc-sync gains one gate, and moving an RFC between lifecycle folders is now real work at move time (the body rewrite the move always owed) instead of deferred cleanup nothing tracked. The thirty-nine debt markers are gone, resolved by the template they were waiting for.