Skip to content

feat(logger): keep session records on the card - #164

Merged
PurpleSentinel merged 1 commit into
mainfrom
feature/session-record-on-card
Aug 20, 2026
Merged

PurpleSentinel merged 1 commit into
mainfrom
feature/session-record-on-card

Conversation

@PurpleSentinel

Copy link
Copy Markdown
Contributor

Part of #137 and #38. Stage B of the session record: it survives the power cycle.

What it does

Session summaries are appended to /sdcard/sessions.bin and read back at boot, so Review
opens on the last session driven rather than on nothing.

One file of fixed-size framed records — magic, version, length, checksum each — rather
than a directory per session. This is the Review index; the per-session logs #38 will write
are a separate thing.

The design decision worth reviewing

A corrupt frame in the middle is stepped over, not treated as end-of-file. Stopping at the
first bad frame is the obvious implementation, and it throws away good sessions to protect a
bad one. Because frames are a fixed size, the reader steps to the next boundary and recovers
everything after the damage. There's a test that flips a byte inside the middle of three
records and asserts the third still comes back.

The card is never assumed to be there. The cache takes the record first, so a failed write
costs the durability of that record and nothing else — Review shows the session either way.
Losing the timer because a card misbehaved would be far the worse failure.

Host tests hit the real write path

The card mounts through VFS, so the store uses plain stdio — meaning these tests exercise the
actual code that runs on device, against real files:

Case Behaviour
Reopen after close 3 sessions, newest first, peaks intact
Frame truncated mid-record costs that record only; earlier sessions survive
Byte flipped in a middle frame stepped over; later sessions recovered
Path that cannot be opened write fails, session still reviewable, failure counted
File longer than memory newest 8 kept; window seeks to a frame boundary

That last one matters: seeking a fixed offset back from the end would start halfway through a
record and lose the newest session to a misalignment.

Verified on device, and what is not

Boot on the real card is clean:

sd-card name=SN32G capacity=30424 MB free=30409 MB
session summaries: open=1 recovered=0 skipped=0 truncated=0

open=1 is no_file — correct for a card with no sessions yet.

The end-to-end durability claim is not yet confirmed on hardware. Recording a session and
reading it back after a real power cycle needs someone to press START and pull the plug, and
that has not been done. The logic is covered by the host tests against real files, and the
store opens correctly on the device, but the full loop on the physical card is untested. Worth
doing before this is relied on at a circuit.

38 host suites, 70 simulator tests.

A trade I made rather than an oversight

The payload is the record's bytes, so the file is device-internal, not a portable export —
a host tool cannot assume the layout. Human-readable session output belongs with the
per-session logs, and a field-by-field codec would buy portability nothing needs yet. Easy to
revisit if reading sessions off the card on a laptop becomes wanted sooner.

Stage A left the record in RAM, so a driver's sessions were gone the moment the device
lost power. They are appended to the card now, and read back at boot, so Review opens on
the last session driven rather than on nothing.

One file of fixed-size framed records rather than a directory per session: this is the
Review index, and the per-session logs #38 will write are a separate thing. Each frame
carries its own magic, version, length and checksum, which is what makes a card pulled
mid-write cost only the record being written.

A corrupt frame in the middle is stepped over rather than stopping the read. Stopping at
the first bad frame is the obvious implementation and it throws away good sessions to
protect a bad one; because frames are a fixed size, the reader can step to the next
boundary and recover everything after the damage.

The card is never assumed to be there. A failed write costs the durability of one record
and nothing else - the cache takes it first, so Review shows the session either way.
Losing the timer because a card misbehaved would be far the worse failure, and this is
the subsystem that has never run on this device while a receiver is about to land on top
of it at 25 Hz.

Because the card mounts through VFS, the store uses plain stdio and the host tests
exercise the real write path rather than a mock: a reopen, a frame truncated mid-record
as an interrupted write leaves it, a byte flipped inside a middle frame, a path that
cannot be opened at all, and a file longer than memory where the window has to seek to a
frame boundary to avoid starting halfway through a record.

The payload is the record's bytes, which makes the file device-internal rather than a
portable export. Human-readable session output belongs with the per-session logs, and a
field-by-field codec would buy portability nothing needs yet.

Part of #137 and #38

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@PurpleSentinel
PurpleSentinel merged commit d276c84 into main Aug 20, 2026
3 checks passed
@PurpleSentinel
PurpleSentinel deleted the feature/session-record-on-card branch August 20, 2026 22:49
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants