# Quality gates — progressive queueing Criteria for `architecture/progressive-queueing.md`. Automatic tests live in `crabidy-core/src/lib.rs` (default `resolve_tracks_into` walk, fake provider), `crabidy-server/src/lib.rs` (`PendingResolve` chunk application), `tidaldy/src/lib.rs` (offline path validation), and `cbd-tui/src/app/queue.rs` (indicator rendering). They fail while the stubs are unimplemented — that is the target state for `implement`. Run: `devenv shell -- cargo test --workspace` (session-local `CARGO_TARGET_DIR` when `target/` is owner-built). ## Channel and concurrency gates (verify by reading) - [x] **All new channels are bounded.** The chunk channel is small (≤ 8 chunks); forwarder → playback reuses the existing `bounded(64)`. No `unbounded()` anywhere in the feature. - [x] **No lock is held across an `await`.** The `pending` map and `queue` mutexes are locked, used, and released inside synchronous blocks only — same discipline as the existing playback handlers. - [x] **The playback loop stays the single writer of queue state.** Neither the forwarder task nor the provider resolve task touches `QueueManager` or broadcasts; they only send commands. - [x] **The provider loop never blocks on a resolve.** The `ResolveTracks` arm spawns; `GetTrackUrls` for the first chunk's track must be servable while a resolve is still streaming (deadlock check: playback awaiting `GetTrackUrls` + provider awaiting a chunk send must be impossible). - [x] **Channel semantics are documented where they are the contract**: sender-drop = finished, receiver-drop = cancel, on both `ProviderClient::resolve_tracks_into` and `ProviderCommand::ResolveTracks`. ## Cancellation gates - [x] **`Replace` and `Clear` cancel every pending op** before mutating the queue; `Queue`/`Append`/`Insert` cancel nothing. - [x] **Cancellation propagates to the network fetch**: the forwarder drops the chunk receiver, and both resolve implementations (default walk and tidaldy override) treat a failed chunk send as "stop fetching, return Ok" — verified by test for the default, by reading for tidaldy's page loop. - [x] **Late chunks for finished/cancelled ops are dropped silently** (no error, no queue mutation). ## Behavior gates - [x] **Immediate feedback**: accepting a resolve op broadcasts a `Queue` snapshot with `resolving = true` before the first chunk arrives. - [x] **`resolving` is true iff at least one op is pending**, and every queue broadcast from the playback loop goes through the one helper that sets it (grep: no direct `StreamUpdate::Queue(` construction in the op/chunk paths besides `broadcast_queue`). - [x] **Playback starts with the first chunk** that makes a track current (replace, or landing in an empty queue) and never restarts for later chunks of the same op — covered by the `PendingResolve` tests, plus reading the `apply_resolved_chunk` → `play_if_some` wiring. - [x] **Order preserved end-to-end**: pages arrive in collection order, nodes in listing order (pre-order walk — the old LIFO reversal must not reappear), multi-path requests resolve sequentially in request order, and `InsertAfter` keeps the whole op contiguous. - [x] **An op that finishes with zero tracks logs the existing "resolved to no playable tracks" warning** with enough context (paths). ## Error and robustness gates - [x] **No panics on provider failure, in any spawned task.** Unreadable nodes are skipped with a warning; a dead provider channel ends the op (with `ResolveFinished` still sent, so `resolving` clears) instead of leaving a stuck indicator. - [x] **Tracing spans survive the spawns**: forwarder and provider resolve tasks attribute their events to the originating request's span (`ProviderMessage::new` capture + `in_current_span`/explicit parent). - [x] **tidaldy page loop honors the existing token/refresh path** (reuses `make_request`) and adds no new retry logic. ## Wire and UI gates - [x] **Proto change is additive only**: `Queue.resolving = 4`, no rpc shape changes; field documented in the proto. - [x] **The TUI pseudo-item is render-only**: never in the list model, unreachable by selection/removal/navigation (`get_size` unchanged) — covered by tests. - [x] **Indicator style matches the pane** (`COLOR_SECONDARY`, inside the queue block, after the last track). - [x] **Old client / new server and new client / old server both degrade cleanly** (flag ignored / never set — reasoning check against the generated proto defaults). ## Documentation gates - [x] **`ProviderClient::resolve_tracks_into` docs state the full channel contract** (order, completion, cancellation, error policy). - [x] **Deviations from the architecture are recorded** in `plan/summary.md` under this feature.