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
Status: Ready Parent:#1 Audit baseline:4258b8d2cfb98bb4809ad698028aeb905b0c732c Priority: P2 — History playback retains its player after natural completion and lacks a complete lifecycle contract Depends on: the Phase 0/1 pipeline fixes; may be implemented independently afterward
Problem
AudioPlayback.play() creates an AVAudioPlayer, starts it, and stores it in a retained property. The property is cleared only when stop() is explicitly called or another play replaces it.
Natural playback completion has no delegate/completion path, so the completed player and any resources it retains remain owned by Oigo for the rest of the application session. Playback errors after startup, replacement races, History window closure, and repeated play actions also have no explicit operation-generation or UI-state contract.
This is not the largest V1 blocker, but it violates the repository's release rule that session-specific resources must be released after every terminal path and makes repeated playback/resource measurements ambiguous.
Required behavior
Normal completion releases the current AVAudioPlayer and associated playback state promptly.
Explicit stop, replacement by another recording, decode failure, History closure where appropriate, and application termination all converge on one idempotent cleanup path.
A late completion callback from an older player cannot clear or change a newer active player.
Repeated playback does not accumulate players, file descriptors, decoded buffers, delegates, timers, or tasks.
Playback state is truthful enough for History to present Play/Stop or completion feedback without polling.
No audio path, filename, or session identity enters ordinary diagnostics.
Phased implementation plan
Phase A — Add a playback operation contract
Model one active playback generation containing the player and a monotonically changing operation ID.
Add a small retained delegate/proxy or equivalent completion hook.
Define terminal outcomes: completed, stopped, replaced, decode/start failure, and shutdown.
Keep the public surface small and independent of dictation capture/transcription state.
Phase B — Centralize idempotent teardown
Clear the active player only when the callback/command matches the current generation.
Stop and release an existing player before installing a replacement.
Release delegate/proxy and completion closures on every terminal path.
Ensure stop() is safe before start, after completion, and when called repeatedly.
Phase C — Integrate truthful History behavior
Let History reflect active/completed/stopped state through bounded callbacks on the main actor.
Disable or relabel controls only for the currently playing session.
Stop playback before deleting its session and during application termination.
Decide explicitly whether closing History stops playback; enforce and test the chosen behavior.
Phase D — Lifecycle verification
Add deterministic lifecycle tests for natural completion, stop, replacement, start failure, late callback, delete-during-playback, History closure, and shutdown.
Run 100 short playback cycles and track live players, file descriptors, memory, and completion callbacks.
The current player reference is nil promptly after natural playback completion.
Stop, replacement, failure, deletion, window lifecycle, and shutdown use one idempotent release path.
A late callback from player A cannot clear or alter active player B.
Starting a new recording stops/releases the previous player before retaining the replacement.
Deleting a session cannot leave its recording actively referenced or playing.
History displays truthful playback state without a recurring polling timer.
One hundred playback cycles show no growth in active players, delegates, tasks, file descriptors, or memory beyond the documented tolerance.
Dictation capture, transcription, insertion, and idle performance are unchanged.
Diagnostics remain payload-free and contain no local audio path or user/session identity.
Out of scope
Waveforms, scrubbing, speed control, playlists, or audio editing
Multiple concurrent recordings
Media-key integration
Replacing AVAudioPlayer without measured need
Handoff
Implement after the V1 P0/P1 dictation path is dependable. Add completion, stop, replacement, delete, History-close, and shutdown rows to #12's lifecycle matrix.
Status: Ready
Parent: #1
Audit baseline:
4258b8d2cfb98bb4809ad698028aeb905b0c732cPriority: P2 — History playback retains its player after natural completion and lacks a complete lifecycle contract
Depends on: the Phase 0/1 pipeline fixes; may be implemented independently afterward
Problem
AudioPlayback.play()creates anAVAudioPlayer, starts it, and stores it in a retained property. The property is cleared only whenstop()is explicitly called or another play replaces it.Natural playback completion has no delegate/completion path, so the completed player and any resources it retains remain owned by Oigo for the rest of the application session. Playback errors after startup, replacement races, History window closure, and repeated play actions also have no explicit operation-generation or UI-state contract.
This is not the largest V1 blocker, but it violates the repository's release rule that session-specific resources must be released after every terminal path and makes repeated playback/resource measurements ambiguous.
Required behavior
AVAudioPlayerand associated playback state promptly.Phased implementation plan
Phase A — Add a playback operation contract
Phase B — Centralize idempotent teardown
stop()is safe before start, after completion, and when called repeatedly.Phase C — Integrate truthful History behavior
Phase D — Lifecycle verification
Acceptance criteria
Out of scope
AVAudioPlayerwithout measured needHandoff
Implement after the V1 P0/P1 dictation path is dependable. Add completion, stop, replacement, delete, History-close, and shutdown rows to #12's lifecycle matrix.