docs(specs): make "a spec becomes an architecture doc" the written rule
The sixteen specs folded in last commit were folded because someone noticed they had gone stale, not because anything said they should be. Without the rule written down the directory drifts straight back to a mix of promises and descriptions, and neither can be trusted: you cannot tell from a file whether it describes the build or proposes a change to it. So: docs/specs/ holds only unshipped work, there is no "Implemented" resting state, and the fold-in and the deletion happen in the same commit. The template now asks for the destination architecture doc **up front**, which is a design check rather than bookkeeping — a feature that fits no existing doc usually has an unclear layer assignment, and it is cheaper to find that out at spec time. It also tells the author which half of what they are writing is durable (invariants, rejected alternatives, the defect a decision prevents) and which half dies with the file (phases, migration steps, acceptance criteria). The review checklist gains a Lifecycle section, including the case that gets lost otherwise: out-of-scope work worth doing has to be written where it will still be found after the spec is gone.
This commit is contained in:
@@ -227,6 +227,34 @@ Before accepting a spec, run it past
|
|||||||
a spec around "no Rust changes required" — correct layer placement is the goal,
|
a spec around "no Rust changes required" — correct layer placement is the goal,
|
||||||
not minimal backend churn.
|
not minimal backend churn.
|
||||||
|
|
||||||
|
### 🔴 A spec becomes an architecture doc when it ships
|
||||||
|
|
||||||
|
`docs/specs/` holds **only work that has not shipped**. There is no "Implemented"
|
||||||
|
resting state for a spec file: when the last acceptance criterion is met, fold
|
||||||
|
the design into [docs/architecture/](docs/architecture/README.md) and **delete
|
||||||
|
the spec in the same commit**.
|
||||||
|
|
||||||
|
This is not tidying. A directory that mixes promises with descriptions makes both
|
||||||
|
unreliable — you cannot tell from a file whether it describes the build or
|
||||||
|
proposes a change to it, and stale specs then quietly disagree with the code
|
||||||
|
while reading as authority.
|
||||||
|
|
||||||
|
- **Every spec names its destination up front** — the template's "Destination on
|
||||||
|
completion" line. Deciding at spec time which architecture doc will absorb it
|
||||||
|
is a design check in itself: a feature that fits no existing doc is usually a
|
||||||
|
feature whose layer assignment is unclear.
|
||||||
|
- **Carry the reasoning, not the plan.** The architecture doc gets the *why* a
|
||||||
|
future change still needs — invariants, rejected alternatives that would be
|
||||||
|
re-attempted, the defect a piece of code exists to prevent. Acceptance
|
||||||
|
criteria, phase breakdowns and migration steps die with the spec; git history
|
||||||
|
keeps them.
|
||||||
|
- **Deferred work outlives its spec.** Anything the spec listed as out-of-scope
|
||||||
|
and still worth doing goes beside the code it concerns, not into the void.
|
||||||
|
- **Rewrite inbound references before deleting** — source comments and CI
|
||||||
|
scripts cite spec paths, and `check-doc-links` only sees markdown.
|
||||||
|
- **Partially implemented is a real status.** A spec stays until *all* of it
|
||||||
|
ships, with the header naming what is left.
|
||||||
|
|
||||||
## Conventions
|
## Conventions
|
||||||
|
|
||||||
### Rust Backend
|
### Rust Backend
|
||||||
|
|||||||
@@ -53,6 +53,18 @@ Copy the boxes into the review comment (or the PR) and tick them.
|
|||||||
- [ ] Traceability coverage stays ≥ 88% (the CI gate — a ratchet, so check
|
- [ ] Traceability coverage stays ≥ 88% (the CI gate — a ratchet, so check
|
||||||
`bun run traces:coverage` rather than trusting this number).
|
`bun run traces:coverage` rather than trusting this number).
|
||||||
|
|
||||||
|
## Lifecycle
|
||||||
|
|
||||||
|
- [ ] **"Destination on completion" names a real architecture doc and section.**
|
||||||
|
This spec file is deleted when it ships; something has to absorb the
|
||||||
|
design. If nothing fits, the layer assignment is probably unclear — go back
|
||||||
|
to that table.
|
||||||
|
- [ ] The spec separates the **durable half** (invariants, rejected alternatives,
|
||||||
|
the defect a decision exists to prevent) from the **disposable half**
|
||||||
|
(phases, migration steps, acceptance criteria). Only the first is folded in.
|
||||||
|
- [ ] Anything listed as out of scope but still worth doing is written where it
|
||||||
|
will be found after this file is gone — beside the code it concerns.
|
||||||
|
|
||||||
## Conflicts & hygiene
|
## Conflicts & hygiene
|
||||||
|
|
||||||
- [ ] If this spec revises/supersedes another, the older spec gets a banner
|
- [ ] If this spec revises/supersedes another, the older spec gets a banner
|
||||||
|
|||||||
@@ -6,12 +6,27 @@
|
|||||||
"Layer assignment" — read its comment before writing it.
|
"Layer assignment" — read its comment before writing it.
|
||||||
|
|
||||||
Before merging a spec, run it past docs/specs/SPEC-REVIEW-CHECKLIST.md.
|
Before merging a spec, run it past docs/specs/SPEC-REVIEW-CHECKLIST.md.
|
||||||
|
|
||||||
|
LIFECYCLE: this file is temporary. docs/specs/ holds only unshipped work — when
|
||||||
|
the last acceptance criterion is met, the design is folded into
|
||||||
|
docs/architecture/ and this file is deleted in the same commit. Write it
|
||||||
|
knowing that: the durable half is the reasoning (invariants, rejected
|
||||||
|
alternatives, the defect a decision prevents), and the disposable half is the
|
||||||
|
plan (phases, migration steps, acceptance criteria).
|
||||||
-->
|
-->
|
||||||
|
|
||||||
**Status:** Proposed <!-- Proposed | Accepted | Implemented | Superseded -->
|
**Status:** Proposed <!-- Proposed | Accepted | Partially implemented | Superseded.
|
||||||
|
NOT "Implemented" — a fully shipped spec is folded into docs/architecture/
|
||||||
|
and deleted. See "Destination on completion" below. -->
|
||||||
**Requirements:** <!-- UR-xxx → DR-yyy; allocate new DRs in requirements.md. -->
|
**Requirements:** <!-- UR-xxx → DR-yyy; allocate new DRs in requirements.md. -->
|
||||||
**UX spec:** <!-- link to the relevant ux-flows.md section, or "n/a". -->
|
**UX spec:** <!-- link to the relevant ux-flows.md section, or "n/a". -->
|
||||||
**Supersedes / revises:** <!-- link any spec this changes, or delete this line. -->
|
**Supersedes / revises:** <!-- link any spec this changes, or delete this line. -->
|
||||||
|
**Destination on completion:** <!--
|
||||||
|
Which architecture doc absorbs this design when it ships, and roughly which
|
||||||
|
section. e.g. "05-platform-backends.md — a new section beside
|
||||||
|
ExoPlayerBackend". Name it NOW: a feature that fits no existing doc usually
|
||||||
|
has an unclear layer assignment, which is worth finding out at spec time.
|
||||||
|
This spec file is deleted in the same commit that folds it in. -->
|
||||||
|
|
||||||
## Summary
|
## Summary
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user