The bug was NOT residue type 2 — that lead was a reasonable inference from
"stereo-only, transient-heavy", and it was wrong. The cause was overlap-add
placement of early long blocks.
A block's window is centred on `center` and reaches n/2 either side. A file
opening [256, 256, 2048, ...] puts the first long block's centre at 832, so it
starts at -192 — before sample zero. Those leading samples lie outside the
stream and must be DROPPED. The code used center.saturating_sub(n/2), clamping
the start to 0, which slid the whole block 192 samples later. Every sample was
corrupted until the centres grew past n/2, then decoding was perfect again.
That shape is exactly why it read as a residue fault: a wrong head with a
correct body looks like "specific blocks have wrong amplitude", and
correlation averaged it to 0.82. Mono appeared flawless only because no mono
file in this corpus happens to open with an early long block — a corpus
accident, not a decoder property.
mono 47/47 exact, mean 1.00000 -> 186 files, mean 1.00000, min 1.00000
stereo 68/107 exact, mean 0.826 -> 370 files, mean 1.00000, min 1.00000
corpus 115/160 exact -> 556/556, zero decode errors
The 73 "frame-count mismatches" are afconvert trimming further than the
container specifies; afinfo's valid-frame counts match OUR output exactly and
every file still correlates at 1.0000.
The fix is extracted into a shared overlap_add because decode and debug_raw
each had their own copy — a diagnostic that can disagree with the decoder it
diagnoses is worse than no diagnostic.
New test is fixtured on a file that opens [256, 256, 2048, ...] and asserts
PER-SAMPLE agreement, not just correlation: correlation alone hid this at 0.82.
Decode cost 5.16 ms/file; 11.5 MB compressed expands to 143.3 MB of f32 PCM.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Two root causes, both found by building an oracle rather than guessing.
1. Amplitude ~75x low: the IMDCT applied a 2/n normalisation the encoder's
forward transform had already carried. Because 2/n varies with block size
it produced DIFFERENT errors on 256- vs 2048-sample blocks — exactly the
reported symptom. Removing it gives fit scale 1.0000.
2. Leading trim, the real remaining defect. The first audio packet produces NO
output (its window only primes the overlap-add) but we emitted from the
first block's centre, injecting half a priming window of garbage and
shifting everything early. And Vorbis carries encoder delay in the GRANULE
POSITION, which varies per file — afinfo confirms 128 / 1103 / 960 frames
on three samples — while our Ogg reader kept only last_granule and
discarded per-page granules, making it unrecoverable. Added per-page
granule tracking: the first page reporting a granule pins priming as
centre - granule, and valid audio starts at priming + blocksize_0/2. That
reproduces afinfo's numbers exactly on all three.
A premise in the brief was also wrong and worth recording: our output length
was already correct. afinfo reports valid frames matching OUR output — it is
afconvert that trims a further 128. The reference WAV was short, not us.
mono 47 files mean corr 1.00000 (min 1.00000) 47/47 exact
stereo 107 files mean corr 0.826 68/107 exact
Decode cost 5.13 ms/file average; 11.5 MB compressed expands to 143.3 MB of
f32 PCM, which is why the sample bank's LRU cap matters.
Honest remaining defect: ~39 stereo files decode wrongly and it is NOT
alignment — a full lag sweep peaks at 0.40-0.89 with fit scales 0.40-1.87, so
specific blocks have wrong amplitude. Mono being 47/47 rules out floor,
residue 0/1, MDCT, windowing and priming; coupling matches the spec's
square-polar mapping including reverse order; floor 0 is rejected rather than
mis-decoded; and both channels are identical in the failing files, so it is
not a swap. The failing set is transient-heavy impact/footstep sounds, so the
lead is residue type 2 partition counting on short blocks.
reference_decode.rs is no longer #[ignore]d: 3 real tests asserting mono
correlation > 0.999 and length == granule, plus a 3000-mutation fuzz that must
never panic, all skipping cleanly without fixtures.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>