Finding
On a decode-loop error (engine.rs:333-342) the decode task emits EngineEvent::Error and then calls frame_tx.send(None).await.ok(). The frame channel uses None to mean end-of-stream, so the DSP task cannot distinguish an error termination from a clean EOS: it unconditionally emits EngineEvent::TrackEnded { source } (engine.rs:403) followed by PlaybackStopped. Every track that fails to decode is reported as a completed track.
Evidence
crates/akouo-core/src/engine.rs:341
frame_tx.send(None).await.ok();
DSP task at crates/akouo-core/src/engine.rs:403:
event_tx.send(EngineEvent::TrackEnded { source: source.clone(), }).ok();
Why this matters
Callers that count TrackEnded to advance the play queue, increment play-count metrics, or mark tracks as listened will record a false completion for every decode failure. Concrete consequences are play-count inflation, premature queue advancement, and inaccurate recently-played history — state that diverges from what actually played.
Desired correction
Distinguish error termination from EOS in the frame channel — for example, reserve None for a clean EOS and signal errors by dropping the sender or sending a dedicated error variant — and have the DSP task emit TrackEnded only on a clean EOS. Done when: a decode error produces EngineEvent::Error and EngineEvent::PlaybackStopped but not EngineEvent::TrackEnded.
Finding
On a decode-loop error (
engine.rs:333-342) the decode task emitsEngineEvent::Errorand then callsframe_tx.send(None).await.ok(). The frame channel usesNoneto mean end-of-stream, so the DSP task cannot distinguish an error termination from a clean EOS: it unconditionally emitsEngineEvent::TrackEnded { source }(engine.rs:403) followed byPlaybackStopped. Every track that fails to decode is reported as a completed track.Evidence
crates/akouo-core/src/engine.rs:341DSP task at
crates/akouo-core/src/engine.rs:403:Why this matters
Callers that count
TrackEndedto advance the play queue, increment play-count metrics, or mark tracks as listened will record a false completion for every decode failure. Concrete consequences are play-count inflation, premature queue advancement, and inaccurate recently-played history — state that diverges from what actually played.Desired correction
Distinguish error termination from EOS in the frame channel — for example, reserve
Nonefor a clean EOS and signal errors by dropping the sender or sending a dedicated error variant — and have the DSP task emitTrackEndedonly on a clean EOS. Done when: a decode error producesEngineEvent::ErrorandEngineEvent::PlaybackStoppedbut notEngineEvent::TrackEnded.