# Quality gates — the `orphans` provider Gates for `architecture/orphans.md` and the `crabidy-server/src/orphans.rs` stub. Each is pass/fail by reading/reasoning or by a named test. Tests live in `crabidy-server/src/crabidy_store.rs` (the store methods) and `crabidy-server/src/orphans.rs` (the provider), run via `devenv shell -- cargo test -p crabidy-server`. ## Correctness of the orphan diff - [ ] **G1 — All items enumerated.** `list_orphans` counts every store entry that has both a `.cbd-store.toml` sidecar and a readable `` audio file. Test: capture two distinct tracks (two store entries), reference neither → both listed. - [ ] **G2 — Referenced entries excluded.** An entry referenced by a `Playable::Store` toml under **any** `ref_root` is not listed. Test: capture one track into a `/crabidy` save (which writes a store toml), then `list_orphans` with that tree as a ref root → the entry is **not** an orphan; delete the save's toml → it **becomes** an orphan. - [ ] **G3 — `/fs` references count.** A `Playable::Store` toml under the `/fs` root (as `scan --capture` writes) excludes its target. Test: hand-write a store toml under an fs ref root → its target is not an orphan. - [ ] **G4 — References outside ref roots do not count.** A store toml under a directory that is **not** a ref root does not rescue its target from being an orphan (documented boundary). Test asserts the target is still listed. - [ ] **G5 — Malformed residue is reclaimable.** A sidecar with no audio (or audio with no sidecar) is reported as an orphan, never as "referenced". Test: drop a lone `x.cbd-store.toml` into the store → listed. - [ ] **G6 — Fresh every call.** No persisted orphan list; two consecutive `list_orphans` calls straddling a reference change reflect the change (covered by G2's two-phase assertion). ## Presentation contract (reuse, no new wire) - [ ] **G7 — Child capability flags.** Every `/orphans` child advertises `is_queable`, `is_editable`, `is_deletable`, and `is_captured` all `true`, and `is_downloadable = false`. The root is `is_queable = true`, `is_creatable = false`. Verified by reading `get_lib_node`; test asserts the flags on a listed child. - [ ] **G8 — Leaf carries exactly one track.** `get_lib_node("/orphans/")` returns a childless, queueable node with one track whose `is_captured` is true and whose metadata matches the sidecar. Test asserts `tracks.len() == 1` and `children.is_empty()`. - [ ] **G9 — Queueing resolves the audio.** Resolving an orphan node (default walk) yields one track whose `get_urls_for_track` returns `store_root/`. Test drives `resolve_tracks_into("/orphans")` and checks the resolved URL is the store path. - [ ] **G10 — No proto/TUI/web change.** Confirm by inspection that the feature adds no field to any `proto` message and no binding/gesture to `cbd-tui` or `cbd-web`: it relies solely on existing `is_editable`/`is_deletable`/ `is_queable` handling. (If this gate cannot hold, the design in `architecture/orphans.md` must be revisited before implementing.) ## Rename safety - [ ] **G11 — Renames both files.** `rename_orphan(old, new)` renames the audio ``→`` **and** `.cbd-store.toml`→`.cbd-store.toml`; neither old name remains on disk. Test. - [ ] **G12 — Rename updates the index.** After a rename, the index resolves the same content hash / provider ids to the **new** name and no longer to the old (so a subsequent capture de-dups against the renamed entry). Test via `StoreIndex` lookups or a follow-up capture. - [ ] **G13 — Rename validates and refuses collisions.** An empty / separator / leading-dot `new` is rejected (`InvalidInput`); a `new` already taken by another store audio or sidecar is refused without touching disk. Tests for both. - [ ] **G14 — Rename is reference-safe by construction.** Only unreferenced entries are exposed under `/orphans`, so a rename never invalidates a live toml. Verified by reasoning against the diff definition; no test needed beyond G2. ## Delete safety - [ ] **G15 — Deletes both files.** `delete_orphan(name)` removes the audio and the sidecar and drops the entry from the index. Test asserts both files gone and `list_orphans` no longer lists it. - [ ] **G16 — Idempotent.** Deleting an already-gone entry returns `Ok` (a refreshed root), not an error. Test. - [ ] **G17 — Delete stays inside the store root.** The name is a validated bare file name; delete joins it onto `store_root` and never follows separators or `..`. Verified by reasoning (mirrors `Playable::Store` bare-name validation) plus a test that a crafted `/orphans/..%2Fx` path is `MalformedPath`, not a file operation. ## Always-on rules (AGENTS.md) - [ ] **G18 — No panics on input or I/O.** Every error path (missing entry, unreadable dir, bad toml, taken rename target, malformed path) is a typed `ProviderError`/`StoreError`; no `unwrap`/`expect`/`panic!`/`todo!` remains in shipped code. A bad sidecar or track toml during the walk is skipped with a warning, never fatal (mirrors `StoreIndex::scan` and `fsdy` listing). - [ ] **G19 — Bounded work, no unbounded channels.** The reference walk and enumeration use ordinary async fs iteration; if any channel is introduced it is bounded. No new external calls (so no timeout/retry surface is added). - [ ] **G20 — Public items documented.** Every public item in `orphans.rs` and every new public `CrabidyStore`/`fsdy::Client` method has a doc comment stating intent and error behavior. - [ ] **G21 — Mount is optional and non-fatal.** `/orphans` mounts only when the store is present; its absence (no data/state dir) drops the subtree without affecting the server, exactly like `/crabidy` and `/fs`. `get_lib_root` includes the `orphans` child only when mounted. Verified by reading the orchestrator wiring.