# RB-09 MAJOR: decoder returns partial audio on read/decode errors

**Severity:** MAJOR
**Path:** `crates/audio/src/decode.rs:58-79`
**Source:** [2026-04-22 code review](../code-review-2026-04-22.md)
**Labels:** release-blocker, major, audio, data-integrity
**Status:** RESOLVED (2026-04-22)

## Resolution

`decode_audio_file` now propagates every `SymphoniaError` other than the
explicit end-of-stream `UnexpectedEof`:

- `SymphoniaError::ResetRequired` → error (mid-stream discontinuity).
- Any other packet-read error → `MagnotiaError::AudioDecodeFailed`.
- `decoder.decode(&packet)` errors → bubble via `?` instead of
  counter-then-skip.

The decode logic was refactored into an internal
`decode_media_stream(mss, hint)` so tests can inject a custom
`MediaSource`. The regression test `FlakyCursor` returns a valid WAV
header followed by an injected `io::Error` after 1024 bytes; the
`mid_stream_io_error_propagates_instead_of_returning_partial_audio` test
asserts the caller receives `Err`, not an `Ok` with a truncated samples
vector. Companion tests cover the happy path and the
file-does-not-exist path.

The optional `decode_audio_file_best_effort` variant suggested in the
original issue was not added — no caller needs it today.

## Problem

`decode_audio_file`:
- Breaks the read loop on packet-read errors (truncated / corrupt inputs)
- Counts and skips per-packet decoder errors
- Still returns `Ok` if any samples were produced before the break

A corrupt or truncated input file is silently accepted as partial audio. Callers have no way to distinguish "file decoded cleanly" from "file was bad and we handed you half of it".

## Acceptance

- Propagate read and decode errors to the caller (return `Err`) — match the pattern used in `read_wav` (fixed in the 2026-04-22 quick-wins batch, commit `b665754`).
- Optional: expose a `decode_audio_file_best_effort` variant if anyone genuinely wants the partial-audio-on-error behaviour. Today no caller needs it.
- Regression tests: (a) truncated MP3; (b) corrupted FLAC; (c) valid file continues to decode successfully.

## Fix scope

Medium. Error-propagation pattern is the same as the `read_wav` fix, but the symphonia packet-loop has several skip branches to audit.

## Dependencies

- None — standalone fix.
