You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
π€ Auto-generated by Claude Fable 5 (claude-fable-5) via Claude Code β NOT human-reviewed. Verify before acting. Design directed by the owner; this issue records the agreed direction and open questions.
PlayTree: recursive queue model behind the three playback buffers
The player's queue model becomes a tree with a cursor, and the three familiar buffers become views of it:
Currently Playing β the active leaf plus a small preload window.
Playlist β the flattened remainder of the tree from the cursor onward. May contain playlists inside playlists: albums as coherent units in a larger queue, provider playlists as lazy handles, "queue this album next" without splicing.
Search Results β staging subtrees populated by voice queries, grafted into the playlist when selected for playback.
This matches the wire triad (media / playlist / disambiguation) that ovos.common_play.play already carries; what changes is that nesting stops being eagerly flattened at decode time and becomes structure the player understands.
Core semantics (decided)
Playback policy attaches to nodes, not the global player. Shuffle the album order while playing each album in track order; repeat one sub-playlist; a sequential news-briefing node inside a shuffled music queue. The global shuffle/repeat flags become the root node's policy β current behavior is the degenerate single-node case.
next/previous always move by leaf, depth-first. "Skip this album/playlist" is a future distinct verb, not an overload of next.
Tree inside, flat on the wire. Every wire surface (status payload, playlist_position/playlist_size, disambiguation query, GUI views) reports flat projections in current traversal order. The frozen ovos.common_play.* contract does not change; only OCP-1 Β§4.5's media-entry shape needs to admit a playlist-as-entry.
Currently Playing as a list means the gapless preload window, nothing more for now. Transport verbs and track.state bind to exactly one active leaf. Multi-part logical tracks (audiobook chapters spanning seek/length arithmetic) are a possible later per-node "atomic group" policy, out of scope here.
Graft by copy, not reference. Selecting search results into the playlist snapshots them; a later search never mutates the live queue, and "save this search" is a coherent snapshot.
Failure recurses with bounds. A child subtree whose leaves all fail marks its parent entry failed and advances (preserving the existing all-failed hot-loop guards); recursion depth is bounded; cycle detection is mandatory β a stored playlist referencing itself must not hang the dispatcher.
Lazy expansion prefetches one ahead, sharing machinery with the preload window, so provider-playlist expansion never lands its latency on a track boundary.
playlist_position under per-node shuffle: defined as the index into the current flattened traversal order (queue views reorder when a node reshuffles) β needs a spec sentence.
Preload window size and whether backends participate (a load_track ahead of time on a second backend instance vs. serial preload on one).
How a lazy provider handle is represented in a MediaEntry (uri scheme? provider callback topic?) β interacts with the Β§4.5 shape.
Plan
OCP-1 Β§4.5 spec text: media-entry shape admitting playlist-as-entry, the flat-projection rule, and the traversal-order sentence for position fields (architecture repo; coordinated with the in-flight OCP-1 edits).
PlayTree model layer in ovos-media as its own module with exhaustive unit tests (nodes, cursor, per-node policy, flatten, failure propagation, cycle/depth guards, copy-graft) β draft PR, no player rewiring yet.
Adopt: PlayQueue reimplemented on the tree, buffers become views, preload window, lazy expansion. Post-v2-train, internal-only. The adoption pass also collapses _next_sibling_leaf/_prev_sibling_leaf and next_leaf/prev_leaf into direction-parameterized traversal β deferred from the model PR so its fuzz-verified logic ships unrefactored.
PlayTree: recursive queue model behind the three playback buffers
The player's queue model becomes a tree with a cursor, and the three familiar buffers become views of it:
This matches the wire triad (
media/playlist/disambiguation) thatovos.common_play.playalready carries; what changes is that nesting stops being eagerly flattened at decode time and becomes structure the player understands.Core semantics (decided)
next/previousalways move by leaf, depth-first. "Skip this album/playlist" is a future distinct verb, not an overload of next.playlist_position/playlist_size, disambiguation query, GUI views) reports flat projections in current traversal order. The frozenovos.common_play.*contract does not change; only OCP-1 Β§4.5's media-entry shape needs to admit a playlist-as-entry.track.statebind to exactly one active leaf. Multi-part logical tracks (audiobook chapters spanning seek/length arithmetic) are a possible later per-node "atomic group" policy, out of scope here.Open questions
playlist_positionunder per-node shuffle: defined as the index into the current flattened traversal order (queue views reorder when a node reshuffles) β needs a spec sentence.load_trackahead of time on a second backend instance vs. serial preload on one).Plan
PlayTreemodel layer in ovos-media as its own module with exhaustive unit tests (nodes, cursor, per-node policy, flatten, failure propagation, cycle/depth guards, copy-graft) β draft PR, no player rewiring yet.PlayQueuereimplemented on the tree, buffers become views, preload window, lazy expansion. Post-v2-train, internal-only. The adoption pass also collapses_next_sibling_leaf/_prev_sibling_leafandnext_leaf/prev_leafinto direction-parameterized traversal β deferred from the model PR so its fuzz-verified logic ships unrefactored.