Files
jellytau/docs/specs/SPEC-REVIEW-CHECKLIST.md
T
dtourolle 96abc3afef 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.
2026-08-21 18:29:09 +02:00

4.3 KiB

Spec review checklist

Run a spec past this before accepting it. It exists because JellyTau's backend/frontend boundary is a stated rule with, historically, no gate — the rule lived in the architecture docs, but nothing forced a spec author to check a new design against it, and a "minimal-change" spec quietly leaked domain taxonomy into the frontend (see scoped-search-boundary.md). This checklist is the human gate. The CI check (scripts/check-frontend-boundary.sh) is only a crude tripwire for one leak signature — it does not replace this.

Copy the boxes into the review comment (or the PR) and tick them.

Boundary (the one that bites)

  • The spec has a filled-in "Layer assignment" table, and it assigns logic, not files. A spec without this section is not ready to review.
  • No domain vocabulary is placed in the frontend. In particular: Jellyfin item-type sets that define a category (what "Music"/"TV"/"Movies" means), query-shaping rules, business rules, reachability/sync policy. If the frontend names a set of item types to define a category, that is a leak — it belongs behind an opaque enum the backend expands.
  • "The backend already accepts this parameter" was not used as the reason to place the deciding logic in the frontend. Accepting a parameter ≠ owning the decision of its value.
  • The Scope: / effort framing is not optimizing for "least backend change." "Frontend only, no Rust changes" is a description, never a goal. The goal is correct layer placement; sometimes that is more Rust work.
  • Ran the litmus test on each borderline responsibility: would it change if Jellyfin's API changed? → Rust. Only if the UI were redesigned? → frontend. Borderline defaults to Rust.
  • Single-type presentation (itemType: "Movie", "this page shows albums") is not over-corrected into the backend. The rule targets category taxonomy, not every mention of a type. Don't invent a backend enum per list page.

IPC contract

  • Anything crossing the boundary has its wire shape specified.
  • camelCase rule accounted for: top-level params auto-convert; nested structs get #[serde(rename_all = "camelCase")]; tagged unions match tags on both sides; events are kebab-case. (CLAUDE.md §IPC, 04-type-sync-and-threading.md.)
  • Any result that arrives twice (command return and a later event — e.g. the search cache/server merge) has both payloads in the new shape.
  • bindings.ts is regenerated from Rust, not hand-edited.

Requirements & traceability

  • Linked to existing URs, or new URs/DRs are allocated in requirements.md.
  • Requirement-implementing code will carry // TRACES: comments (CLAUDE.md).
  • Traceability coverage stays ≥ 88% (the CI gate — a ratchet, so check 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

  • If this spec revises/supersedes another, the older spec gets a banner pointing here — no two specs silently contradicting.
  • Acceptance criteria include the standard gates: bun run check, bun run test, bun run check:boundary, and (if Rust changed) cargo fmt/cargo clippy/bun run test:rust.
  • Notes flag that a parallel Claude session may be active in the repo.

If any Boundary box can't be ticked, the spec is not ready — fix the layer assignment first. Every other section can be negotiated; that one is the whole reason this file exists.