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.tsis 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:coveragerather 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.