Release v0.31.0 — report parity + the inverted rescue (0.29.0 → 0.31.0) #40

Merged
serversdown merged 31 commits from dev into main 2026-09-18 16:46:45 -04:00
6 changed files with 143 additions and 40 deletions
Showing only changes of commit 904522a9c5 - Show all commits
+31 -7
View File
@@ -87,13 +87,37 @@ within 2%** (was 66.9% and 56.6%).
Combined across both corpora: **292/292 waveform files, 2,330,916/2,330,916 Combined across both corpora: **292/292 waveform files, 2,330,916/2,330,916
samples exact.** Production IDFW truncations 41 → 22. samples exact.** Production IDFW truncations 41 → 22.
**Known open — diagnosed but NOT verified:** 23/575 production IDFW files ### Fixed — `40 NN` int16 blocks with NN > 8
(4%), all UM12947 between 2025-07-14 and 2025-09-23, stop the block walker on
tag `40 0c`. `data_block_len()` caps the `40 NN` int16 block at `NN > 0x08`, `data_block_len()` rejected any `40 NN` block with `NN > 0x08`. The cap had
but these files use NN up to 196. Both verified corpora only ever use no evidence behind it: every corpus available when it was written used only
NN ∈ {1,2,3,4,8}, so the cap is untested there and lifting it leaves both at NN ∈ {1,2,3,4,8}, so it was never exercised. Loud UM12947 events use NN of
100.000% — which is *not* evidence it decodes these correctly. Needs Thor CSV 12, 16, 20 … up to 196, and because the block walker stops at the first
exports for UM12947 in that date range (the 9-10-26 upload starts 2025-09-25). unrecognised tag rather than raising, rejecting them surfaced as **silently
short channels** (e.g. Tran 1812 / Vert 2132 / Long 2324 on a file whose
export has 2324 for all three). The bound is the buffer, not a constant.
Verified against Thor exports for UM12947 (2025-07-14 … 09-25, 167
waveforms): length mismatches **22 → 0**, **1,476,242/1,476,249** samples
exact. These are not truncated recordings — the exports carry full sample
counts.
`tests/test_waveform_codec.py` asserted the cap as intended behaviour; that
assertion was wrong and has been replaced with one pinning the opposite,
carrying the evidence.
### Result across all three ground-truth corpora
**459 waveform files, 3,807,158 / 3,807,165 samples exact.** Production
IDFW: **575/575**, zero truncations, zero decode failures, median PPV error
−0.0007% across 8 units. Series-3 re-verified **unchanged at 14,338/14,338**
after every shared-codec change.
The 7 residual samples each differ by one 4th-decimal tick and are **Thor's
own rounding**: intersecting the per-sample rounding constraints over that
corpus is infeasible (the binding pair contradict by 2.3e-11, 7e-5 relative),
so no single linear LSB reproduces every printed value. `_GEO_LSB_IPS` is
already pinned to ~1e-11 — do not retune it to chase these.
--- ---
+14 -5
View File
@@ -47,11 +47,20 @@ Read this first when picking the project back up.
was invisible and Vert came up exactly 512 short), and the histogram was invisible and Vert came up exactly 512 short), and the histogram
interval record is **56 bytes, not 72** — `16 × n_channels + 8`, derived per interval record is **56 bytes, not 72** — `16 × n_channels + 8`, derived per
segment from the cumulative interval counter, never assumed. segment from the cumulative interval counter, never assumed.
**Still open:** 23/575 prod IDFW files (4%), all UM12947 2025-07-14..09-23, - **`40 NN` blocks are not capped at NN=8 (2026-09-11).** `data_block_len()`
stop the walker on tag `40 0c` — `data_block_len()` caps `40 NN` at NN>8 but rejected `NN > 0x08`, a guard with no evidence behind it — the corpora
these use up to 196. **Diagnosed, NOT verified** — no Thor export exists for available when it was written only used NN ∈ {1,2,3,4,8}. Loud UM12947
those dates. Do not ship the cap change without one; see events use NN up to 196, and since the walker stops at the first
`docs/idf_protocol_reference.md`. unrecognised tag rather than raising, this surfaced as silently short
channels. Verified on 167 UM12947 waveforms: length mismatches 22 → 0,
1,476,242/1,476,249 samples exact.
- **Production IDFW is now 575/575** — zero truncations, zero decode
failures, median PPV error −0.0007% across 8 units (was 41 truncated + 1
failing, −3.3%). Across all three ground-truth corpora: **459 files,
3,807,158/3,807,165 samples exact**; the 7 stragglers differ by one
4th-decimal tick and are Thor's own rounding — no single linear LSB can
reproduce every printed value (the constraints are infeasible by 7e-5
relative), so do NOT retune `_GEO_LSB_IPS`.
- **Open, not blocking:** 14 sensitive-range files show an exact 8x - **Open, not blocking:** 14 sensitive-range files show an exact 8x
(= 10.0/1.25) units discrepancy; `scripts/backfill_sidecars.py --force` also (= 10.0/1.25) units discrepancy; `scripts/backfill_sidecars.py --force` also
inserts DB rows for store files that have none (one-time per store) and the inserts DB rows for store files that have none (one-time per store) and the
+36 -25
View File
@@ -178,6 +178,39 @@ channels come out the same length.
`00 00`, so every run of three zero bytes looks like a body start and each `00 00`, so every run of three zero bytes looks like a body start and each
costs a full trial decode (~0.5 s/file measured, vs 6 ms/file now). costs a full trial decode (~0.5 s/file measured, vs 6 ms/file now).
### `40 NN` is not capped at NN=8 (2026-09-11)
`data_block_len()` rejected any `40 NN` int16 block with `NN > 0x08`. The cap
had no evidence behind it — every corpus available when it was written used
only NN ∈ {1, 2, 3, 4, 8}, so it was never exercised. Loud events use much
wider blocks:
| corpus | `40 NN` values | walker stops |
|---|---|---|
| first + 3-channel corpora | 1, 2, 3, 4, 8 | none |
| UM12947 2025-07..09 | 2, 4, 8, **12, 16, 20 … 196** | every value > 8 |
Because `walk_body`/`run` stop at the first unrecognised tag rather than
raising, this surfaced as **silently short channels** — e.g. Tran 1812 /
Vert 2132 / Long 2324 on a file whose export has 2324 for all three. The
real bound is the buffer (and the caller's record end), not a magic constant.
Verified against Thor's exports for UM12947 (2025-07-14 … 2025-09-25, 167
waveforms): length mismatches **22 → 0**, and **1,476,242 / 1,476,249**
samples exact.
⚠ These events are **not** truncated recordings, which was the competing
hypothesis — the exports carry the full sample count.
**The 7 residual samples are Thor's rounding, not ours.** Each differs by
exactly one 4th-decimal tick (e.g. decoded 3.3551 vs export 3.3550).
Intersecting the per-sample rounding constraints over this corpus is
**infeasible** — the binding pair (count 2013 → 0.6247, count 4351 → 1.3501)
contradict by 2.3e-11, i.e. 7e-5 relative. No single linear LSB can
reproduce every printed value, so Thor is not doing plain round-half-up on
`count × LSB`. Do not retune `_GEO_LSB_IPS` to chase these; it is already
pinned to ~1e-11.
### Mic-disabled units are a distinct shape (2026-09-10, second corpus) ### Mic-disabled units are a distinct shape (2026-09-10, second corpus)
Some units run with the microphone disabled — **3 channels, not 4** — and that Some units run with the microphone disabled — **3 channels, not 4** — and that
@@ -218,32 +251,10 @@ files that previously decoded no intervals at all.
### What is still open ### What is still open
- **23 of 575 production IDFW files (4%)** still decode with unequal channel - ~~23 of 575 production IDFW files~~ — **RESOLVED 2026-09-11.** Production
lengths (22) or fail outright (1). All are **UM12947, 2025-07-14 to IDFW is now **575/575** with zero truncations and zero decode failures
2025-09-23**. The `Tran/Vert/Long 3072 / MicL 0` group was the 3-channel (median PPV error −0.0007%). See "`40 NN` is not capped at NN=8" above.
shape above and is fixed; what remains is ragged, e.g.
`T1812 / V2132 / L2324 / M2324`.
**Diagnosed but NOT verified.** These files stop the block walker on tag
`40 0c`, because `data_block_len()` caps the `40 NN` int16 block at
`NN > 0x08`:
```python
if hi == 0x40: # int16 BE data block
return (None, None) if (nn == 0 or nn > 0x08) else (2 * nn + 2, nn)
```
The affected files use NN of 12, 16, 20 … up to 196 — every value above 8
halts the walk, which is why the channel comes up short. Both verified
corpora only ever use NN ∈ {1, 2, 3, 4, 8}, so the cap has never been
exercised, and lifting it leaves both at 100.000%.
⚠ **Do not ship the cap change on that evidence.** "Doesn't regress the
known-good corpus" is not "produces correct values here", and a too-loose
guard can accept a false `40 NN` inside data and emit plausible-but-wrong
samples — the exact failure mode this whole effort was about. It needs
Thor CSV exports for UM12947 events between **2025-07-14 and 2025-09-23**;
the `9-10-26-csv-req` upload starts at 2025-09-25 and misses them.
- Mic → psi scale is still the rough `2.14e-6` regression, not derived. - Mic → psi scale is still the rough `2.14e-6` regression, not derived.
- Per-channel `int16 field4` in the IDFH interval record (possibly - Per-channel `int16 field4` in the IDFH interval record (possibly
time-of-peak) and the 8-byte tail (PVS data) remain undecoded. time-of-peak) and the 8-byte tail (PVS data) remain undecoded.
+12 -1
View File
@@ -758,7 +758,18 @@ def data_block_len(body: bytes, p: int) -> Tuple[Optional[int], Optional[int]]:
hi = t0 & 0xF0 hi = t0 & 0xF0
nn = ((t0 & 0x0F) << 8) | t1 nn = ((t0 & 0x0F) << 8) | t1
if hi == 0x40: # int16 BE data block if hi == 0x40: # int16 BE data block
return (None, None) if (nn == 0 or nn > 0x08) else (2 * nn + 2, nn) # NN was capped at 0x08 until 2026-09-11. That cap had no basis: the
# two corpora available at the time only ever used NN in {1,2,3,4,8},
# so it was never exercised. Loud UM12947 events use NN of 12, 16,
# 20 ... up to 196, and every value above 8 halted the walk, which
# surfaced as silently short channels (walk_body/run stop at the first
# unrecognised tag rather than raising). Verified against Thor's own
# exports: 22 length-mismatched files -> 0, and the affected corpus
# went to 1,476,242/1,476,249 samples exact. The real bound is the
# buffer; the caller additionally clamps to the record end.
if nn == 0 or p + 2 * nn + 2 > len(body):
return None, None
return 2 * nn + 2, nn
if nn == 0 or nn % 4: if nn == 0 or nn % 4:
return None, None return None, None
if hi == 0x00: if hi == 0x00:
+29
View File
@@ -291,3 +291,32 @@ def test_three_channel_histogram_uses_56_byte_intervals():
assert decoded == pytest.approx( assert decoded == pytest.approx(
_header_float(header, f"{channel}PPV"), rel=0.02 _header_float(header, f"{channel}PPV"), rel=0.02
) )
# ─── `40 NN` blocks with NN > 8, verified 2026-09-11 ───────────────────────
IDFW_WIDE40 = FIXTURES / "UM12947_20250806134504.IDFW"
def test_wide_forty_nn_block_does_not_truncate_channels():
"""Loud events use `40 NN` blocks with NN well above the old cap of 8.
``data_block_len()`` rejected NN > 0x08, which halted the block walk
part-way through a record. The walker stops at the first unrecognised
tag instead of raising, so this surfaced as silently short channels —
here Tran 1812 / Vert 2132 / Long 2324 where the export has 2324 for all
three. The affected files use NN of 12, 16, 20 ... up to 196.
"""
rows = _parse_export(IDFW_WIDE40.with_suffix(".IDFW.csv"))[1]
result = read_idf_file(IDFW_WIDE40)
for index, channel in enumerate(GEO_CHANNELS):
decoded = result.samples[channel]
assert len(decoded) == len(rows), (
f"{channel}: {len(decoded)} samples, export has {len(rows)}"
)
expected = [row[index] for row in rows]
bad = sum(
1 for c, v in zip(decoded, expected)
if abs(geo_count_to_ips(c) - v) >= 5e-5
)
assert bad == 0, f"{channel}: {bad} samples differ from Thor's export"
+21 -2
View File
@@ -712,8 +712,27 @@ def test_forty_nn_is_a_data_block_not_a_segment_header():
""" """
assert data_block_len(b"\x40\x02\x00\x01\x00\x02", 0) == (6, 2) assert data_block_len(b"\x40\x02\x00\x01\x00\x02", 0) == (6, 2)
assert data_block_len(b"\x40\x08" + bytes(16), 0) == (18, 8) assert data_block_len(b"\x40\x08" + bytes(16), 0) == (18, 8)
# NN > 8 is not a data block
assert data_block_len(b"\x40\x0c" + bytes(24), 0) == (None, None)
def test_forty_nn_is_not_capped_at_eight():
"""NN > 8 is a perfectly ordinary `40 NN` block.
This test previously asserted the opposite (`40 0c` -> (None, None)),
codifying a guard that had no evidence behind it: the only corpora
available then used NN in {1,2,3,4,8}, so the cap was never exercised.
Loud UM12947 events use NN of 12, 16, 20 ... up to 196, and rejecting
them halted the block walk mid-record — surfacing as silently short
channels, since the walker stops at the first unrecognised tag rather
than raising. Lifting the cap took that corpus from 22 length-mismatched
files to 0, and 1,476,242 of 1,476,249 samples now reproduce Thor's own
CSV export exactly (the 7 stragglers differ by one 4th-decimal tick).
Verified 2026-09-11; see docs/idf_protocol_reference.md.
"""
assert data_block_len(b"\x40\x0c" + bytes(24), 0) == (26, 12)
assert data_block_len(b"\x40\xc4" + bytes(392), 0) == (394, 196)
# The real bound is the buffer: a block that cannot fit is not a block.
assert data_block_len(b"\x40\xc4" + bytes(8), 0) == (None, None)
assert data_block_len(b"\x40\x00" + bytes(8), 0) == (None, None)
def test_record_chain_is_followed_by_length_not_by_tag_sniffing(): def test_record_chain_is_followed_by_length_not_by_tag_sniffing():