preserve transport outage validation evidence

This commit is contained in:
Jay
2026-08-17 14:30:56 -04:00
parent 291c6b54e6
commit 1cf0a9ac77
9 changed files with 176 additions and 26 deletions
+16 -6
View File
@@ -81,12 +81,22 @@ before that first valid frame separately from CRC failures after synchronization
Acquisition runs in a dedicated higher-priority task and writes complete samples
to a 512-entry RAM queue. The lower-priority output task batches up to eight
records per frame. At 100 Hz this queue represents about 5.12 seconds of
decoupling from a blocked or disconnected transport. A failed write retains and
retries the same encoded packet rather than dequeuing more samples, so the queue
accumulates the outage backlog. After reconnection, the oldest retained data is
sent first. If the queue fills, acquisition drops new samples rather than
overwriting older ones; sequence gaps and the cumulative lost-sample counter
expose that permanent loss.
decoupling when the transport reports backpressure or failure accurately. A
failed write retains and retries the same encoded packet rather than dequeuing
more samples, so the queue accumulates the outage backlog. After reconnection,
the oldest retained data is sent first. If the queue fills, acquisition drops
new samples rather than overwriting older ones; sequence gaps and the cumulative
lost-sample counter expose that permanent loss.
That retry guarantee requires the transport's success result to mean that the
complete frame was accepted for eventual delivery. The current USB Serial/JTAG
VFS/stdio path does not fully satisfy that contract: if the host remains
connected but stops draining, its internal timeout can discard bytes while the
stdio write appears successful. CRC and sequence checks make that loss visible
to a receiver, but it does not increment the device's drop counter. A direct
driver path with bounded transmit-drain waits can report this condition; an
application acknowledgement and replay window is required for end-to-end
delivery confirmation.
Receivers report bytes left in an incomplete trailing frame when capture ends.
Those bytes cannot pass CRC validation and are not silently admitted as samples.
+34 -5
View File
@@ -15,6 +15,8 @@ data.
encoder/parser contract cases
- ESP-IDF firmware build and flash on the assembled ESP32-C3 prototype
- Live USB capture followed by independent offline re-decoding
- Tracked three- and seven-second hardware-outage captures with regression
assertions for integrity, retention order, and overflow accounting
## USB text-conversion finding
@@ -27,6 +29,22 @@ Before binary output begins, firmware now changes the USB Serial/JTAG VFS transm
mode to `ESP_LINE_ENDINGS_LF`, which means no byte modification. Startup logs and
readable metadata are flushed first.
## USB VFS resilience qualification
The 5.12-second queue guarantee applies when the transport reports failure or
backpressure accurately. The current ESP-IDF USB Serial/JTAG VFS/stdio path
surfaces a physical disconnect, but it has a weaker connected-stall case: when a
host remains connected and stops draining, the lower-level timeout can discard
bytes even though stdio reports a successful write. Firmware therefore cannot
retain that particular frame or increment its drop counter. The receiver still
detects the loss through CRC resynchronization and packet/sample sequence gaps.
ESP-IDF's direct USB Serial/JTAG driver provides bounded writes and an explicit
transmit-drain wait, allowing a connected stall to become observable to the
transport policy. That is a useful improvement for the common transport layer.
It is not proof of receiver delivery; application acknowledgements and replay
are needed for that stronger guarantee and are planned with BLE integration.
## Final hardware capture
`captures/binary_v1_smoke2.trk` and its decoded CSV contain:
@@ -58,11 +76,11 @@ at 100 Hz). The hardware capture's zero timing anomalies and zero loop overruns
confirm that packet encoding, CRC, float metadata, and USB output did not disturb
the acquisition cadence.
Output failure is transactional: firmware retains and retries the same encoded
packet with a scheduler delay instead of discarding it or dequeuing more samples.
The queue therefore accumulates a disconnected-transport backlog. If an outage
outlasts the queue, acquisition drops and counts new samples while preserving the
oldest queued data for ordered delivery after reconnection.
When output failure is reported, handling is transactional: firmware retains and
retries the same encoded packet with a scheduler delay instead of discarding it
or dequeuing more samples. The queue therefore accumulates the transport backlog.
If an outage outlasts the queue, acquisition drops and counts new samples while
preserving the oldest queued data for ordered delivery after reconnection.
## Forced transport-outage validation
@@ -80,3 +98,14 @@ then dropped 138 new samples after reaching capacity. Delivery resumed at sample
timestamp difference from sample 511 to 650 was exactly 1,390,000 us, matching
139 sample intervals, and no saturation flag was emitted. This verifies both the
oldest-data retention policy and the new exact timestamp re-anchor after overflow.
The exact validated byte streams are tracked as executable regression fixtures:
- `tests/fixtures/forced_outage_3s.trk`, SHA-256
`01482816cdaa668e4681c33c8baa1df331d733b9bbcbc4f448ece25e88185ad6`
- `tests/fixtures/forced_outage_7s.trk`, SHA-256
`2ea8a5742944bdebc13bec2ccdbceba75f0bb71e48c856b0f86285878e190cd3`
The protocol tests verify both hashes, fragmented parsing with no CRC/header or
trailing-byte errors, the complete sequence ranges, the sole 138-sample overflow
gap, cumulative counters, and the exact 1,390,000 us timestamp re-anchor.