157 lines
8.8 KiB
Markdown
157 lines
8.8 KiB
Markdown
# 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.
|