-
Notifications
You must be signed in to change notification settings - Fork 0
Open
Description
Problem
queueNeedsBuild currently encodes multiple transport-sync meanings behind a single Boolean:
- pending sync at natural boundary
- pending sync on next play/resume
- sync in progress / retry in progress
- degraded or recovered but not fully disarmed
That ambiguity is making boundary-swap behavior brittle and has already produced subtle state bugs.
Current failure modes
pendingSkipcan re-arm boundary swap even afterqueueNeedsBuildwas cleared, allowing a later hard pause when no sync is needed.- Deferred sync can be stranded after in-app pause + external resume because re-arming is tied to add-time playing state rather than explicit sync intent.
- Polling/arming/disarming logic is distributed across many call sites, which makes transitions hard to reason about and test.
Proposal
Replace queueNeedsBuild: Bool with an explicit transport sync state enum in domain state.
Example shape:
enum TransportSyncState: Equatable, Sendable {
case inSync
case pendingOnPlay
case pendingAtBoundary
case syncingAtBoundary
case retryPending(strategy: SyncStrategy, attempts: Int)
}
enum SyncStrategy: Equatable, Sendable {
case onPlay
case atBoundary
}Behavior goals
- Add while playing =>
.pendingAtBoundary - Add while paused/stopped/no queue =>
.pendingOnPlay - Boundary poller runs only in
.pendingAtBoundary+.playing - Skip/pause/remove/algorithm-change transitions become explicit and local
- Retry success/failure transitions cannot leave stale armed states
Incremental migration plan
- Add
transportSyncStatetoQueueEngineStatewith compatibility shim:- keep
queueNeedsBuildas computed bridge during migration
- keep
- Migrate reducer intents (
addSong,addSongsWithRebuild,play,pause,syncDeferredTransport,resyncActiveAddTransport) - Migrate
ShufflePlayerboundary-swap orchestration to consume enum states - Remove Boolean once all call sites and tests are migrated
- Add transition tests:
- paused add does not boundary-arm
- external resume re-arms when pending-on-play
- retry success clears armed/pendingSkip paths
Acceptance criteria
- No path can trigger boundary pause/swap when sync state is
inSync - No deferred sync intent can be stranded across pause/resume or external playback controls
- Boundary polling is only active when required by state
- Existing queue/transport invariant tests remain green; new transition tests added
Reactions are currently unavailable
Metadata
Metadata
Assignees
Labels
No labels