5.8 KiB
5.8 KiB
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_orphanscounts every store entry that has both a<name>.cbd-store.tomlsidecar and a readable<name>audio file. Test: capture two distinct tracks (two store entries), reference neither → both listed. - G2 — Referenced entries excluded. An entry referenced by a
Playable::Storetoml under anyref_rootis not listed. Test: capture one track into a/crabidysave (which writes a store toml), thenlist_orphanswith that tree as a ref root → the entry is not an orphan; delete the save's toml → it becomes an orphan. - G3 —
/fsreferences count. APlayable::Storetoml under the/fsroot (asscan --capturewrites) 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.tomlinto the store → listed. - G6 — Fresh every call. No persisted orphan list; two consecutive
list_orphanscalls 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
/orphanschild advertisesis_queable,is_editable,is_deletable, andis_capturedalltrue, andis_downloadable = false. The root isis_queable = true,is_creatable = false. Verified by readingget_lib_node; test asserts the flags on a listed child. - G8 — Leaf carries exactly one track.
get_lib_node("/orphans/<seg>")returns a childless, queueable node with one track whoseis_capturedis true and whose metadata matches the sidecar. Test assertstracks.len() == 1andchildren.is_empty(). - G9 — Queueing resolves the audio. Resolving an orphan node (default
walk) yields one track whose
get_urls_for_trackreturnsstore_root/<name>. Test drivesresolve_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
protomessage and no binding/gesture tocbd-tuiorcbd-web: it relies solely on existingis_editable/is_deletable/is_queablehandling. (If this gate cannot hold, the design inarchitecture/orphans.mdmust be revisited before implementing.)
Rename safety
- G11 — Renames both files.
rename_orphan(old, new)renames the audio<old>→<new>and<old>.cbd-store.toml→<new>.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
StoreIndexlookups or a follow-up capture. - G13 — Rename validates and refuses collisions. An empty / separator /
leading-dot
newis rejected (InvalidInput); anewalready 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 andlist_orphansno 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_rootand never follows separators or... Verified by reasoning (mirrorsPlayable::Storebare-name validation) plus a test that a crafted/orphans/..%2Fxpath isMalformedPath, 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; nounwrap/expect/panic!/todo!remains in shipped code. A bad sidecar or track toml during the walk is skipped with a warning, never fatal (mirrorsStoreIndex::scanandfsdylisting). - 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.rsand every new publicCrabidyStore/fsdy::Clientmethod has a doc comment stating intent and error behavior. - G21 — Mount is optional and non-fatal.
/orphansmounts only when the store is present; its absence (no data/state dir) drops the subtree without affecting the server, exactly like/crabidyand/fs.get_lib_rootincludes theorphanschild only when mounted. Verified by reading the orchestrator wiring.