crabidy/quality/build-features.md

8.8 KiB

Quality gates — build features

Criteria an implementation of architecture/build-features.md must satisfy. Each is pass/fail by reading/reasoning or by running one command; automated coverage lives in crabidy-server/src/settings.rs (built-in vs configured providers), crabidy-server/src/cli.rs (features, scan extensions), and crabidy-server/src/provider.rs (the mount registry: dispatch, ordering, absent providers).

The default build is unchanged (highest priority)

  • G1 — cargo build (no flags) links exactly what it links today. Every feature is in default, so the default dependency graph is identical: cargo tree -p crabidy-server before and after differ in nothing but the optional/feature annotations. (gate: diff the tree.)
  • G2 — No behaviour change at default features. The full build mounts the same providers in the same order (crabidy first, orphans last, rest alphabetical), persists the queue, captures, serves the web UI, decodes Opus, and streams spectrum frames. (tests: the existing suites all pass unchanged.)
  • G3 — The proto is untouched. No .proto change, no feature-conditional RPC, no client-side feature knowledge. cbd-tui and cbd-web build and run against any server build. (gate: git diff shows no crabidy-core/crabidy/v1/*.proto change.)

Feature hygiene

  • G4 — Every gated dependency is optional = true and reachable only through its feature. No dep: alias is enabled by a path other than its own feature; no gated crate is named in a non-optional dependency line. Applies to tidaldy, ytdy, fyyd, absdy, soundclouddy, jamendody, fsdy, blake3, reqwest, realfft, tonic-web, include_dir (crabidy-server), symphonia + symphonia-adapter-libopus (audio-player), notify-rust (cbd-tui).
  • G5 — Feature names match the runtime vocabulary. The provider features are spelled exactly as the providers entries: tidal, youtube, fyyd, abs, soundcloud, jamendo, fs (D3).
  • G6 — --no-default-features compiles, links, and runs for crabidy-server, cbd, cbd-tui, and audio-player. The provider-less server starts, answers Init, serves an empty library root, and shuts down cleanly (D2).
  • G7 — Every curated matrix entry builds warning-free under cargo clippy -- -D warnings: defaults; --no-default-features; each provider alone; fs alone; defaults minus opus; minus spectrum; minus web-ui; cbd-tui --no-default-features. Exposed as one devenv script (D11). No #[allow(dead_code)]/#[allow(unused)] added to silence a combination — unused code under a feature combination is a signal to move the #[cfg], not to allow it.
  • G8 — flake.nix names its features explicitly. The native package no longer passes a bare --no-default-features (which after D1 would mean "no providers at all"); it lists what it wants. The aarch64 cross build still ships web-ui (D10). (gate: read flake.nix; nix build .#crabidy yields a binary whose features output lists the providers.)

The mount registry

  • G9 — A provider is named in exactly two places. Its Cargo.toml feature line and its registration in ProviderOrchestrator::build. No #[cfg(feature = …)] for a provider anywhere else in crabidy-server (the fs feature is the documented exception — it also gates the store, capture, orphans, persistence, and scan, per D5).
  • G10 — Dispatch is preserved exactly. For every mounted provider, is_track_path, get_urls_for_track, get_metadata_for_track, get_lib_node, create_lib_node, rename_lib_node, delete_lib_node, and resolve_tracks_into reach the same client for the same paths as the old chain: a mount owns <root> and <root>/… and nothing else (/fsx is not /fs). (tests: mount_owns_its_root_and_children_only, dispatch_reaches_the_owning_mount.)
  • G11 — An unowned path degrades, never panics. No mount → the same errors as today: MalformedPath for lookups/track paths, NotSupported for create/rename/delete, false for is_track_path, with the same warn!. (tests: unowned_paths_are_typed_errors.)
  • G12 — The root listing offers only mounted providers, ordered crabidy → alphabetical → orphans. A provider built out is simply absent — clients need no signal. (test: root_lists_mounted_providers_in_order.)
  • G13 — resolve_tracks_into still dispatches dynamically. Providers that override the trait default (paged resolves) keep their override through Arc<dyn ProviderClient>. (test: a fake provider whose override is observed.)

fs (local files and persistent state)

  • G14 — Without fs, nothing references fsdy, the store, captures, or orphans. crabidy_store, capture, and orphans are not compiled; Playback holds no store; restore_current and the persister are absent or inert.
  • G15 — Store-dependent RPCs degrade cleanly. CaptureLibraryNode and SaveQueue answer Unimplemented (never a panic, never a hang) with a message naming the missing fs feature. Existing clients treat it as any other RPC error.
  • G16 — scan without fs fails with a clear message naming the feature, exit code non-zero, no partial writes. The clap surface (and so completions and the man page) is unchanged (D9).
  • G17 — A queue still works without persistence. Queue, play, next, shuffle, repeat behave normally; only survival across restarts is lost, and the startup log says so once.

opus

  • G18 — With opus off, symphonia, symphonia-adapter-libopus, and the bundled libopus C build are gone. cargo tree -p audio-player --no-default-features shows neither crate; the build needs no cmake/ ninja. (gate: build in an environment without cmake.)
  • G19 — An Opus file in an opus-less build fails as an undecodable file, not a panic. build_source returns an Err whose message names the missing feature; playback logs it and moves on, exactly as for a corrupt file (hard rule: no panic on input).
  • G20 — scan indexes .opus if and only if the feature is on. AUDIO_EXTENSIONS contains "opus" under opus and not otherwise; the other extensions are unaffected. (tests: scan_indexes_opus_with_the_feature / scan_ignores_opus_without_the_feature.)

spectrum, web-ui, notifications

  • G21 — Without spectrum, realfft is gone and no FFT task is spawned; the update stream simply carries no SpectrumFrame. Clients (TUI f, web) still run; their bars stay dark. Player::spectrum_tap() keeps its signature (D8).
  • G22 — Without web-ui, no tonic-web, no include_dir, no embedded bundle, and the gRPC route still serves native HTTP/2 clients. (Existing behaviour; only re-verified.)
  • G23 — Without notifications, cbd-tui links no notify-rust and the now-playing path compiles to nothing; every other TUI behaviour is unchanged, including the config key (an ignored key must not break the config parse).

Discoverability

  • G24 — features prints the truth. crabidy-server features and cbd features list exactly the compiled providers plus the compiled extras, one per line. (test: build_features_lists_providers_then_extras.)
  • G25 — The startup log names the build. One info! line lists the compiled features; a providers entry this binary cannot mount produces one warn! naming it. Neither aborts startup (fail-open library layer). (test: unavailable_providers_reports_built_out_and_unknown_names.)
  • G26 — The default crabidy-server.toml lists only built-in providers, so a pruned-by-build binary never writes a config full of names it will warn about. (test: ensure_default_lists_only_built_in_providers.)
  • G27 — The docs describe the flags. docs/src/ gains a build-features page (in SUMMARY.md) with the feature table, the "what you lose" column, and two worked examples (local-files appliance; tidal + web UI). README points at it.

Hard rules (always apply)

  • G28 — No panics on input or environment. No unwrap/expect added on config, path, or stream data in any gated code; a missing feature is an error value or an absent mount, never a panic. todo!()/unimplemented!() from the stub stage are all gone.
  • G29 — Errors stay typed at the boundaries. ProviderError for provider paths, CaptureError/Status for RPCs, Box<dyn Error> only in CLI entry points. No color-eyre report reaches a client.
  • G30 — No secrets in the new paths. The features output and the startup lines carry feature names only — no config values, no credentials.