4.0 KiB
4.0 KiB
Quality gates: captures
Criteria the implementation must satisfy beyond the automatic tests
(crabidy-server/src/capture.rs, crabidy-server/src/capture_store.rs,
fsdy/src/lib.rs, plus the TUI tests added during implementation). Each
gate is pass/fail by reading the code.
Shared walk (refactor)
- Bookmarks and download captures run through one walk
(
capture::capture_into/write_tree);bookmark_storekeeps no copy of the worklist, caps, tmp-and-swap, or cleanup logic. - The refactor is behavior-preserving for bookmarks: every existing
bookmark_storetest passes unchanged (module path ofCaptureErroraside). - The walk stays iterative (worklist), all-or-nothing, and removes the temp folder on every failure path — including failed downloads and the byte budget.
Download sink
- Every external call is bounded: connect timeout on the shared HTTP client and one per-track deadline covering URL fetch, request, and the whole body stream. No retries.
- Bodies are streamed to disk (never buffered whole) and counted
against the capture's byte budget while streaming; exceeding it is
TooLarge, not partial data left behind. - Non-2xx responses and transport errors are typed
(
CaptureError::Download) — no panic on any network condition. - Download log lines carry paths, names, and counts — never stream URLs (they embed tokens) and never file contents.
- The toml is written only after its audio file succeeded, with a
relative
fileplayable naming the sibling (TrackFile::from_track_with_file); the audio name shares the toml's order prefix and sanitizer (capture::audio_file_name). - Downloads run sequentially inside the one spawned capture task; the orchestrator loop keeps serving commands during a capture.
Opt-in (is_downloadable)
- Tidal sets the flag centrally: nodes are downloadable when queueable
or when they list tracks; children mirror
is_queable. No per-arm copies to drift. - Every other provider (fs, queues, bookmarks, captures, orchestrator
root) leaves the flag
false— a capture can never be built from another capture's or bookmark's links masquerading as sources. - The server enforces the blessing at the capture root (directory
source: its own node; track source: its parent node) with
CaptureError::Unsupported; an unreadable root isBadSource.
RPC and orchestrator
CaptureLibraryNodeRequest.downloadis additive: old clients (no flag) keep getting bookmarks, byte-for-byte.- Error mapping:
InvalidName/BadSource→invalid_argument;TooLarge/Disabled/Unsupported→failed_precondition; download/walk/write failures →internal. - The orchestrator routes
/capturesin everyProviderClientmethod (same completeness as/bookmarks), andget_lib_rootlists thecaptureschild only when the instance exists. - Captures init is non-fatal: no config dir or an unopenable store
disables download captures and the
/capturesmount, never the server (and never bookmarks). /capturesmounts with an editable top level (no reserved names): captures are renamable (e) and deletable (d) like bookmarks.
TUI
W(shift) is bound inScope::Librarywith a help description and passes the bindings-table invariant tests unchanged;wbehavior is untouched.- The capture overlay opens for
Wonly when the bare selection is queueable and downloadable; tracks inherit their node's flag; marks are ignored. Label:capture(vsbookmark). MessageFromUi::CaptureNodecarriesdownload; a failed capture is logged and never tears down the poll loop.
Hygiene
- New public items are documented; docs state error/edge behavior.
clippy -D warnings,fmt,taplo,markdownlintclean on the whole workspace; all tests green.architecture/captures.mdreconciled where the implementation diverged (e.g. the exact tidal flag rule).