docs: the reseq probe's readings, and the invariants resequencing changes

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
Martino FerrariandClaude Sonnet 4.6 committed 2026-10-08 23:14:38 +02:00
1 parent 4549c622fc
commit eacb3f5efc
11 files changed
+258 -23

No files matched your search

+20
View File
@@ -96,6 +96,26 @@ Part of [CLAUDE.md](../../CLAUDE.md). These are rules that cost a defect to lear
the export guard in [probe-readings.md](probe-readings.md) for why it is no longer exactly one
value). Three steps at 2, 2.5 and
3 ULP of *the stream's uptime* — microseconds, not femtoseconds — is this defect.
- **Append is not the only write.** A backfill amends slots that a reservation wrote as NaN, and
the amend is split across threads for a reason:
- **Ring amend — producer thread.** `RingBuffer<T>::amend(absolute, v)` is a single relaxed
store, bounds-checked against `[produced_ - capacity, produced_)`. The same race class as a
push, and an `f32` cannot tear. Measurements and export read the ring directly, so they see
a repair immediately and no second notification is needed.
- **Pyramid amend — consumer (GTK main thread), inside `ChannelBuffer::acquire()`.** The
producer collects amended values in a plain `std::vector<Amend>` member and the consumer
drains it after its own append pass. `acquire()` is called under `model.mutex()`, and the
producer holds that same mutex for all of `on_data`, so the vector is correctly serialised
with no lock-free queue. The reason the pyramid amend cannot also be on the producer: a
bucket is a 32-byte non-atomic aggregate that the renderer reads **unlocked at paint time**,
so a producer writing it could be caught mid-bucket — a `count` that does not match its
`sum`, producing a wrong mean from a structure whose readers trust `count == 0` to mean
*absent*. On the consumer that cannot happen.
- **A hole is stamped at reservation; backfill changes values only.** The f64 time ring is
never amended. `neighbours()' binary search requires a monotonic array, and `window_x0_`
must remain valid; pre-stamping the hole at the declared cadence (exact in relative mode,
the bridge mechanism in stream mode) is what keeps both invariants, and it is why a late
packet's counter, not its arrival stamp, is what addresses the hole.
- **A dropped time slot is clamped, never answered with a sentinel.** `acquire()` pins
the published window to the value ring's base and both rings keep sliding afterwards —
their capacities are equal, so there is no slack — which means the oldest few samples