crabidy/plan/summary.md

105 lines
5.8 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# Implementation summaries
## node-editing (2026-07-20)
Built per `plan/node-editing.md`: search-term nodes (created via `%`) are now
modifiable — `e` opens the input overlay prefilled with the current title and
renames (re-running the search; merge on title collision), `d` deletes
without confirmation (documented decision, architecture/node-editing.md D4).
Capabilities travel as `LibraryNodeChild.is_editable`/`is_deletable` (fields
5/6, child-only — no consumer for node-level copies), surfaced as a `[ed]`
marker; two new rpcs `RenameLibraryNode` (returns the renamed node, TUI
navigates into it) and `DeleteLibraryNode` (returns the refreshed parent).
All 59 workspace tests green; every gate in `quality/node-editing.md`
checked. Verified against the live Tidal API with a temporary ignored probe
(removed after passing): create `beatles` → rename to `rolling stones`
(in-place, 20 tracks / 40 children) → a track queued under the old term
still resolved a stream URL → delete emptied the listing.
The whole feature ran autonomously per standing instruction; decisions are
recorded in `architecture/node-editing.md` (options + rationale per topic).
### Deviations from plan / architecture (node-editing)
- **Self-rename bug caught by the gate tests**: the first
`rename_search_term` implementation deleted a term renamed to itself (the
merge branch removed the "old" slot). Fixed with an explicit `old != new`
guard; the architecture text ("merge on collision") now implicitly means
*distinct* titles.
- **`pane_bindings_only_match_their_own_pane` (help-modal suite) updated**:
it asserted plain `d` is unbound in the library — now it is
`LibraryDeleteNode` by design; the test's queue-only example key moved to
`c`.
- **`delete_library_node` also maps `InvalidInput``invalid_argument`**
although no provider raises it for delete today — keeps the error contract
uniform across the three node-mutation rpcs.
- **End-to-end check ran at the provider layer** (as with search): no
interactive terminal/audio device in this environment; the gRPC handler
and TUI layers above it are covered by unit tests and review.
- **Environment note**: builds/tests again ran with a session-local
`CARGO_TARGET_DIR` (owner-built artifacts in `target/`); no repo change.
## search (2026-07-20)
Built per `plan/search.md`: `%` inside `/tidal/search` opens a one-line input;
the term becomes a persistent (per-process) tree node holding Tidal search
results — 20 tracks queueable in place, plus artist/album results as canonical
`/tidal/artists/...` children. Creatable nodes carry an `is_creatable` flag
end-to-end (proto → provider → TUI marker `[%]` + pane hint). All 48 workspace
tests green; every gate in `quality/search.md` checked. Verified against the
live Tidal API: payload shapes match the existing models (probe kept as the
ignored `probe_search_shapes` test), and a full create→list→resolve-URL round
trip succeeded (`beatles` → 20 tracks / 40 children, idempotent, playable
stream URL from a search-track path).
The whole feature ran autonomously on user instruction; decisions were taken
without mid-stage confirmation and recorded in `architecture/search.md`
(options + decision per topic).
### Deviations from plan / architecture (search)
- **`Library::update` now concatenates tracks and children** (tracks first).
The old code showed tracks *instead of* children, which would have hidden
the artist/album results on term nodes — architecture assumed both would
render. Existing nodes are unaffected (they only ever carry one kind).
- **Search categories degrade independently**: a failing category logs and
contributes nothing; only all three failing is a `FetchError`. The plan
did not specify partial-failure behavior.
- **`get_lib_node` no longer requires a user id up front** — the gate moved
into the favorites arms (planned), which also means `create_lib_node`
validation works fully offline (used by the new unit tests).
- **End-to-end check ran at the provider layer** (temporary ignored test,
removed after passing) rather than driving the full TUI + server — no
interactive terminal/audio device in this environment. The gRPC handler and
TUI layers above it are covered by unit tests and review.
- **Environment note**: `target/` contains owner-built artifacts not writable
by this agent's user; builds/tests ran with a session-local
`CARGO_TARGET_DIR`. No repo change involved.
## help-modal (2026-07-20)
Built per `plan/help-modal.md`: `app/bindings.rs` (declarative
`BINDINGS` table + `lookup` + `key_label`), `app/help.rs` (overlay), the
`App::dispatch`/`DispatchResult` seam, and the rewired event loop in
`main.rs`. All 20 tests pass; every gate in `quality/help-modal.md` checked.
### Deviations from plan / architecture (help-modal)
- **Two-column modal layout.** The architecture assumed a single-column list;
the full table is ~50 rows and would not fit even a 100×40 frame. The modal
renders Global in the left column and Library + Queue stacked in the right
column, with the close keys as a footer line (`Close help: ?, Esc, q`)
derived from the `Scope::Help` bindings instead of a fourth listed group.
The open question "scroll vs truncate" stays resolved as truncate — but
after the column split the content fits ~34×94, so truncation only kicks in
on genuinely small terminals.
- **`Scope` derives `Hash`** (not in the stub) so the chord-uniqueness test
can use a `HashSet`.
- **`QueueInsertHere` description reworded** to "Insert library selection
after this track": `crabidy-server`'s `insert_tracks` splices at
`position + 1`. Same check confirmed the planned "Queue selection after
current track" wording for `LibraryQueueNext`.
- **`main.rs`** passes `tx` to `App::new` without the now-unneeded clone; the
`KeyCode`/`KeyModifiers`/`UiFocus`/`StatefulList` imports moved out with the
old match.