88 lines
4.6 KiB
Markdown
88 lines
4.6 KiB
Markdown
# Quality gates — search via creatable nodes
|
|
|
|
Checklist for the `implement` stage. Automatic tests live in
|
|
`crabidy-core/src/lib.rs`, `tidaldy/src/lib.rs`, and
|
|
`cbd-tui/src/app/{bindings,mod}.rs` test modules; run with
|
|
`devenv shell -- cargo test --workspace` (network-dependent tidaldy tests
|
|
stay `#[ignore]`).
|
|
|
|
## Contract & wire
|
|
|
|
- [x] Proto changes are additive only: existing field numbers untouched;
|
|
`is_creatable` fields 7 (`LibraryNode`) / 4 (`LibraryNodeChild`);
|
|
`CreateLibraryNode` rpc present. Old clients keep working against the
|
|
new server.
|
|
- [x] `rpc.rs` (server) maps errors per the documented contract:
|
|
`NotSupported` → `failed_precondition`, `InvalidInput` →
|
|
`invalid_argument`, everything else → `internal`. No `color-eyre`
|
|
report or debug formatting of internals leaks into `Status` messages.
|
|
- [x] `ProviderOrchestrator::create_lib_node` routes `/tidal`-prefixed
|
|
parents to the Tidal client and answers anything else (including the
|
|
synthetic root `/`) with `NotSupported` — same prefix discipline as
|
|
`get_lib_node`.
|
|
- [x] The `CreateLibraryNode` command follows the existing bounded(1)-reply
|
|
rendezvous pattern; no new unbounded channels anywhere in the feature.
|
|
|
|
## Provider semantics (tidaldy)
|
|
|
|
- [x] `create_lib_node` trims the title; empty/whitespace → `InvalidInput`;
|
|
parent other than `/tidal/search` → `NotSupported`; idempotent (an
|
|
existing term returns its node, the term list holds no duplicates).
|
|
- [x] `search_terms` stores **raw** terms; the path segment is
|
|
`encode_segment(term)`; the node `title` shows the raw term. The lock
|
|
is never held across an `await`.
|
|
- [x] `get_lib_node(/tidal/search)` lists created terms as children (decoded
|
|
titles) and sets `is_creatable: true` on the node; an unknown term path
|
|
under search is implicitly (re)created, not an error — survives server
|
|
restarts with stale client caches.
|
|
- [x] The term node sets `is_queable: false` (see architecture/search.md:
|
|
`resolve_tracks` would otherwise sweep every artist/album result into
|
|
the queue). Its `tracks` are the track results with paths
|
|
`/tidal/search/<enc-term>/<track-id>`; artist/album results are
|
|
children with **canonical** `/tidal/artists/...` paths.
|
|
- [x] `search_tracks/artists/albums` fetch a single page with
|
|
`limit=SEARCH_RESULT_LIMIT` — they must NOT use
|
|
`make_paginated_request`'s fetch-everything loop.
|
|
- [x] `get_urls_for_track` and `get_metadata_for_track` work for
|
|
`SearchTrack` paths (via `track_id_from_path`).
|
|
- [x] The response models were verified against the live API (explorer
|
|
request) before the typed methods were finalized; deviations live in
|
|
`tidaldy::models`, not in ad-hoc serde attributes inline.
|
|
|
|
## No panics on user input (hard rule)
|
|
|
|
- [x] All `todo!()` stubs from api-design are gone (grep the workspace).
|
|
- [x] `encode_segment`/`decode_segment` are total: any client-supplied
|
|
segment decodes without panicking (lossy, not `unwrap`).
|
|
- [x] Search/create failures (network, auth, malformed) surface as
|
|
`ProviderError`/`Status`, never a panic; the TUI's create path handles
|
|
an error reply without crashing the orchestrate task.
|
|
|
|
## TUI behavior
|
|
|
|
- [x] While `app.input.is_some()`, the event loop routes keys exclusively to
|
|
`handle_input_key` — the bindings table (including `q`/quit and `?`)
|
|
is unreachable; `%` while the overlay is already open just inserts the
|
|
character.
|
|
- [x] `Library::update` applies nodes with no children and no tracks when
|
|
`is_creatable` (empty search node is enterable); genuinely empty
|
|
non-creatable nodes keep the existing skip behavior.
|
|
- [x] Creatable children are visibly marked in the library list and the pane
|
|
title hints at `%` when the open node is creatable.
|
|
- [x] The input overlay renders inside the library pane (bottom line) with
|
|
the typed buffer visible; it disappears on cancel/submit.
|
|
- [x] `RpcClient::create_library_node` evicts the parent's cache entry and
|
|
caches the created node (stale `/tidal/search` listings would
|
|
otherwise hide new terms).
|
|
- [x] On successful create the library navigates into the returned node
|
|
(`ReplaceLibraryNode`); on failure the library stays where it was.
|
|
|
|
## Code quality
|
|
|
|
- [x] Public items added in all five crates have doc comments matching final
|
|
behavior; the `%` binding appears in the help modal automatically.
|
|
- [x] New dependency: only `percent-encoding` (workspace-managed version);
|
|
nothing else added.
|
|
- [x] `devenv shell -- cargo fmt --check`, `cargo clippy --workspace`
|
|
(no new warnings), `cargo test --workspace` all pass.
|