Replies: 1 comment
|
Hi @Plantucha, Thank you for this incredible audit and taxonomy of failure modes. The distinction you drew between empirical ground truth (validated against 1,478 real AirSense 11 files) and reasoned specification constraints is methodologically top-tier. Every single one of the 16 "one-line slips" you identified has been audited, validated, and hardened in our codebase. Furthermore, we implemented a dedicated host property test suite ( Here is how each failure mode and architectural observation was resolved: Category 1: Missing Data Sentinels (Slips 1–4)
Category 2: File Length & Record Count (Slips 5–7)
Category 3: Gating & Session Window (Slips 8–10)
Category 4: Day Labelling & Timezone Mechanics (Slips 11–14)
Category 5: Channels & Numerical Ranges (Slips 15–16)
The Three "Non-Bugs"We audited all three code patterns you highlighted:
Additional Improvements & Architecture Evolution
Huge thanks again for the incredible collaboration and insight! The updated codebase is now being tested internally. I will release it once testing is successful. |
Uh oh!
There was an error while loading. Please reload this page.
None of these are bugs today. Every one is a one-line slip that would
compile, would not crash, and would produce an EDF file that opens — while
being wrong in a way a user would eventually notice in OSCAR. This is a list
of failure modes and the property that distinguishes each one, not a list of
defects.
It exists because the exporter's rules are currently implicit: they live in
the control flow of
edf_gen.cand in whoever last read it. One of them hasalready been broken in a shipped release — #189, where SNT v2 missing samples
reached
SA2.edfas digital0and showed up as real zeros — so the list isnot hypothetical about the class, only about the instances.
Where a row says AS11-verified, the property was checked against a real
AirSense 11 SD card (233 day folders, 292 sessions, 1478 EDF files). The rest
are derived from the EDF format or from
edf_gen.c's own stated intent, andare marked reasoned.
Missing data
The AS11 marks an unavailable sample with
-1in the EDF. Getting that wrongdoes not look like an error; it looks like a patient whose pulse was 0.
INT16_MINis not recognised as missing, so it is scaled and clamped like real data — gaps become extreme values-1is the marker in 1478/1478 files)-1goes through the scale and lands on some other number; missing data reads as a measurementSA2.edfas-1— AS11-verified0instead of-1-1guard before dividing by the logical scale0after the divisionspool_to_edf()returns-1unchanged for a sentinel input — reasonedFile length and record count
An EDF header states the record count before any data is written, so a count
that disagrees with the bytes on disk produces a file readers cannot parse.
The failure mode is a crash-interrupted night, which is the common case.
sample_countis trusted over the measured file lengthsize == header + records × record— AS11-verified (holds in 1478/1478)Gating and the session window
The
.sntfiles capture from therapy start, but BRP/PLD/SA2 must begin at thegating signal (
_ZLErising, else MaskOn) and end at mask-off. Both edges areeasy to get subtly wrong, and the result is a night that is silently shifted
or padded rather than obviously broken.
Day labelling
A DATALOG day starts at noon, not midnight, so an after-midnight session
belongs to the previous folder. Two independent implementations of this exist
—
noon_day_folder()inedf_gen.candas11_time_noon_day()— which iswhat makes it checkable without pinning any expected value.
Channels and range
dig_maxthe header itself declares — AS11-verified (the machine declaresdig[-1000,1500]for flow, not fullint16).sntwith fewer channels than its map indexes is refused, not exported — reasonedThree that look like bugs and are not
Worth writing down so they are not "fixed" twice:
channels_in_file <= 0→< 0. Looks like a division-by-zero waitingto happen. A zero-channel file is refused by the channel-count and
channel-map checks before it reaches that arithmetic.
end <= sizeof(header)→<. For a file that is exactly a header, thefall-through computes
0 / frame, which is the same0the early returngives.
memset(hdr, ' ')→memset(hdr, 0). The EDF spec wants space padding,but every one of the 256 fixed-header bytes is subsequently overwritten by a
space-padded field, so the fill value never reaches the file.
What is not covered here
The list is about the reader —
edf_gen.c. The SNT writer(
session_writer.c) is where #189 actually originated, and none of theseproperties would have caught it at the point it was written; they catch it one
stage later, when the wrong bytes are read back. A writer→reader round trip is
the gap.
All reactions