Issue
PiP can retry a deferred pause every 250 ms without a terminal outcome while public playback intent already says inactive. A permanently unpausable input can therefore continue playing while the observable intent remains paused.
Evidence
PiPController.swift:642-681 retries deferred pause in one loop while the mirror remains playing.
Player.swift:652-683 publishes inactive intent before a rejected or deferred native pause has settled.
PiPController.swift:851-881 mirrors playback intent into PiP control state.
- Existing tests cover transient pause rejection but not a permanently unpausable input.
Expected
Bound deferred retries, cancel them on media/generation/state changes, and return an observable settled or rejected result. Public intent and PiP controls must reconcile with the native outcome.
Acceptance criteria
- A permanently unpausable input settles to a typed rejection within a fixed bound and leaves state consistently playing.
- A transient opening/buffering rejection still pauses once capability becomes available.
- Replacement, stop, end, and a newer command cancel the old retry task.
- No endless task, duplicate pause, or paused UI over continuing playback.
Issue
PiP can retry a deferred pause every 250 ms without a terminal outcome while public playback intent already says inactive. A permanently unpausable input can therefore continue playing while the observable intent remains paused.
Evidence
PiPController.swift:642-681retries deferred pause in one loop while the mirror remains playing.Player.swift:652-683publishes inactive intent before a rejected or deferred native pause has settled.PiPController.swift:851-881mirrors playback intent into PiP control state.Expected
Bound deferred retries, cancel them on media/generation/state changes, and return an observable settled or rejected result. Public intent and PiP controls must reconcile with the native outcome.
Acceptance criteria