crabidy/quality/node-editing.md

92 lines
4.8 KiB
Markdown

# Quality gates — editable and deletable 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]`). 10 tests fail at gate-writing time — they define the
target.
## Contract & wire
- [x] Proto changes are additive only: existing field numbers untouched;
`LibraryNodeChild.is_editable = 5`, `is_deletable = 6`;
`RenameLibraryNode` and `DeleteLibraryNode` rpcs present. Old clients
keep working against the new server.
- [x] `rpc.rs` (server) maps errors per the documented contract for **both**
new rpcs: `NotSupported``failed_precondition`, `InvalidInput`
`invalid_argument`, everything else → `internal`. No `color-eyre`
report or debug formatting of internals leaks into `Status` messages.
- [x] `ProviderOrchestrator::{rename,delete}_lib_node` route `/tidal`-prefixed
paths to the Tidal client and answer anything else (including the
synthetic root `/`) with `NotSupported` — same prefix discipline as
`create_lib_node`.
- [x] Both new commands follow the existing bounded(1)-reply rendezvous
pattern; no new unbounded channels anywhere in the feature.
## Provider semantics (tidaldy)
- [x] `rename_lib_node` trims the new title; empty/whitespace →
`InvalidInput`; any path that is not a `SearchTerm` (including
`/tidal/search` itself) → `NotSupported`; validation happens before any
network call.
- [x] Rename replaces the term **in place** (keeps its list position);
renaming onto an existing term merges (the old slot is removed, no
duplicates ever); renaming an unknown term registers the new one
(stale-client forgiveness). Returns `get_lib_node(new_path)` — the
node at its new percent-encoded path.
- [x] `delete_lib_node` accepts only `SearchTerm` paths (`NotSupported`
otherwise), removes the term idempotently (unknown term → success),
and returns the refreshed `/tidal/search` parent node.
- [x] `rename_search_term` / `remove_search_term` follow the established
lock discipline: poison-tolerant, the `search_terms` lock is never
held across an `await`.
- [x] Term children returned by the `Search` arm set
`is_editable: true, is_deletable: true`; nothing else in the provider
sets either flag.
- [x] Queued search tracks keep playing after a rename/delete of their term:
`get_urls_for_track` / `get_metadata_for_track` resolve from the track
id embedded in the path, independent of term registration.
## No panics on user input (hard rule)
- [x] All `todo!()` stubs from api-design are gone (grep the workspace).
- [x] Rename/delete failures (network, auth, malformed paths from stale
clients) surface as `ProviderError`/`Status`, never a panic; the TUI's
rename and delete paths handle an error reply without crashing the
orchestrate task (log + stay put).
## TUI behavior
- [x] `e` opens the overlay only when the **selected** item `is_editable`,
prefilled with the current title; `d` sends `DeleteNode` only when the
selected item `is_deletable`; both are silent no-ops otherwise
(including when nothing is selected or the list is empty).
- [x] The overlay carries its purpose: submit sends `CreateNode` for
`InputPurpose::Create` and `RenameNode` for `InputPurpose::Rename`;
the rendered label distinguishes them (`new node:` vs `rename:`).
While the overlay is open the bindings table stays unreachable
(existing input-mode bypass, unchanged).
- [x] Delete is deliberately unconfirmed (architecture/node-editing.md D4);
the open question about confirmation for higher-value nodes is
preserved in the architecture doc, not silently dropped.
- [x] Modifiable children are visibly marked in the library list (`[e]`,
`[d]` or `[ed]` suffix, `COLOR_SECONDARY`), coexisting with the `[%]`
marker for creatable ones.
- [x] `RpcClient::rename_library_node` evicts the old path **and** the
parent entry, then caches the node under its new path;
`delete_library_node` evicts the deleted path and the parent, then
caches the returned parent. No stale `/tidal/search` listing can
resurrect an old term.
- [x] On successful rename the library navigates into the renamed node; on
successful delete it shows the refreshed parent; 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 `e`/`d` bindings appear in the help modal automatically.
- [x] No new dependencies.
- [x] `devenv shell -- cargo fmt --check`, `cargo clippy --workspace`
(no new warnings), `cargo test --workspace` all pass.