3.6 KiB
Implementation summaries
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::updatenow 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_nodeno longer requires a user id up front — the gate moved into the favorites arms (planned), which also meanscreate_lib_nodevalidation 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-localCARGO_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 theScope::Helpbindings 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. ScopederivesHash(not in the stub) so the chord-uniqueness test can use aHashSet.QueueInsertHeredescription reworded to "Insert library selection after this track":crabidy-server'sinsert_trackssplices atposition + 1. Same check confirmed the planned "Queue selection after current track" wording forLibraryQueueNext.main.rspassestxtoApp::newwithout the now-unneeded clone; theKeyCode/KeyModifiers/UiFocus/StatefulListimports moved out with the old match.