5.1 KiB
5.1 KiB
Plan — progressive queueing
Ordered tasks for the implement stage. Inputs:
architecture/progressive-queueing.md, the workspace stubs, gates in
quality/progressive-queueing.md. Tests:
devenv shell -- cargo test --workspace (13 failing at plan time = the
target: 5 in crabidy-core, 5 in crabidy-server, 2 in cbd-tui, 1 in tidaldy).
Use the session-local CARGO_TARGET_DIR if target/ contains artifacts
owned by the repo owner.
1. Default chunked resolve (crabidy-core)
- Implement the
resolve_tracks_intodefault body: track path → single chunk fromget_metadata_for_track(failure → warn,Ok, no chunk — matches today's skip); node path → depth-first pre-order walk (stack of paths, children pushed in reverse so siblings pop in listing order), per node: skip unreadable with a warning (root failure →Err), skip non-queueable, sendtracksas one chunk when non-empty; a failed send (receiver gone) → returnOkimmediately. Verify: all 5default_resolve_*tests pass.
2. PendingResolve state machine (crabidy-server lib)
- Implement
new/cancel_flag/cancel/applied/apply_chunk.apply_chunk:Replace→replace_with_tracksfor the first chunk (returns current track), then mutate kind toAppend;Append→append_tracks;InsertAfter(pos)→insert_tracks(pos)then advance the cursor bytracks.len()(clamping isinsert_tracks' job); countapplied. Verify: the 5 op tests pass (replace_op_*,insert_after_op_*×2,append_op_*,cancel_flag_*).
3. Playback loop wiring (crabidy-server)
- Implement
broadcast_queue(snapshot →Queue, setresolvingfrom the pending map, broadcast) and route the remaining directStreamUpdate::Queue(...)broadcasts inhandle_commandthrough it. Verify: gate "resolving is true iff at least one op is pending". - Implement
start_resolve: allocate op id, insertPendingResolve, immediatebroadcast_queue, spawn the forwarder (tokio::spawn+in_current_span): per path in order — check the cancel flag (set → stop), openflume::bounded(4)chunk channel, sendProviderCommand::ResolveTracks, forward each chunk asApplyResolvedChunk(checking the cancel flag between chunks, drop the receiver on cancel); after all paths (or on any exit path) sendResolveFinished. Track the op's paths for the zero-track warning. Verify: gates "immediate feedback", "cancellation propagates", "no panics";cargo check. - Implement
apply_resolved_chunk(look up op — unknown id: drop silently; lock queue,apply_chunk,broadcast_queue, thenplay_if_someoutside the locks),finish_resolve(remove op, warn whenapplied() == 0with the op's paths,broadcast_queue), andcancel_pending_resolves(cancel + clear map; no broadcast needed — the caller mutates and broadcasts next). Verify: gates "playback starts with the first chunk", "late chunks dropped"; existing playback tests still green.
4. tidaldy page-streamed resolve
- Implement
make_paginated_request_into(same loop asmake_paginated_request,sink(page.items)per page, stop onfalse). Verify: gate "token/refresh path reused";cargo check. - Implement the
resolve_tracks_intooverride:parse_pathfirst (foreign →MalformedPathbefore any I/O); track paths → one metadata chunk; pre-order worklist walk wherePlaylistandAlbumnodes streamtracks/itemspages as chunks (Track::to_protoper page, no playlist-metadata fetch) and all other node kinds fall back toget_lib_node(tracks as one chunk when queueable, children onto the worklist in listing order). Failed sends → stop,Ok. Verify:resolve_rejects_foreign_paths_before_any_network_callpasses; gate "order preserved end-to-end".
5. TUI indicator (cbd-tui)
- Implement
Queue::loading_dots(1 + (elapsed_ms / 400) % 3 dots) and render the pseudo-item: whenresolving, push one extraListItem(dots,COLOR_SECONDARY) after the track rows, computed from a monotonic clock at render time;self.liststays untouched. Verify:loading_dots_cycle_one_to_three,resolving_queue_renders_trailing_dots_itempass; the three guard tests stay green.
6. End-to-end + gates sweep
- Exercise the full path against the live API if the local tidal config is available (temporary ignored probe: resolve a multi-album artist through the orchestrator, assert multiple chunks arrive, in listing order, first chunk before the walk completes; drop the receiver mid-stream and confirm fetching stops). Note the outcome in the summary; if unavailable, rely on the offline tests and say so.
- Sweep: no
todo!()left (workspace grep), fmt + clippy + tests green, everyquality/progressive-queueing.mdbox checked, docs updated where behavior shifted. Append the outcome + deviations toplan/summary.md.