rebuild_locked() replaced the store, so produced() restarted at 0 while the
producer's tick_ kept counting: a hole's slot and tick addressing then described
a buffer that was gone, forget_holes_before() could not retire it, and a
backfill's amend fell outside the ring -- repairing nothing while the hole was
still marked repaired, which is the band reporting the opposite of the truth. A
re-plan generation is the signal rather than the stride/channel-count guard,
which a reconnect with an identical CONFIG leaves unchanged. slot_base_ is left
alone: it is relative mode's clock origin and must not walk backwards when the
user retypes the window.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
A packet that needed a slot and found none was neither held nor delivered: no
counter recorded it and the consumer reserved a hole nothing could ever backfill.
It now commits the gap to free a slot and takes the ordering decision once more
against the sequence that commit left behind, bounded to one retry; past that it
is delivered in order with the counters it skipped as its `lost`, never flagged
late, because a packet ahead of the sequence has no hole to be looked up by. A
duplicate can now replace its slot at a full ring, as hold_packet's own comment
already promised, and the 20 ms default window is a named constant.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Fix the false trailing clause in the udps_stats_t::late_resequenced comment,
move udps_held_t from the tunable-limits section to internal-state next to
udps_slot_t, and add braces to three braceless if bodies to match house style.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
.superpowers/sdd/ is scratch and gitignored; that one report was tracked
by accident in an earlier phase.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
The four original items are done. What replaces them: the invisible
riser, relative timing, named configurations, frame storage for
forensics, opening exported waveforms, the plot context menu, drag
resize, an event cache with replay, and a preferences dialog.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
--drop-every/--drop-burst withhold datagrams the counter and stream clock
have already advanced over, and --reorder-every inverts a pair on the
wire; both are deterministic for the reason --glitch-at is, since a probe
asserts the spacing of what it finds and a random count is not a figure.
A `noise` signal gives the dense-trace and intensity-floor paths a input
that is not piecewise smooth.
verification.md records the measured readings, including the one that is
a finding rather than a baseline: a burst past kGlitchPackets (256) is
read as a producer clock glitch, each bridge advances the anchor by one
packet span against a timeline 300 ahead, and four consecutive failures
then throw the stream onto the arrival clock.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
notify::selected passes a GParamSpec* ahead of the user data and
GtkSpinButton::value-changed does not, so on_math_param_changed read the
pspec as its MathDialog* and faulted on the first field it touched --
which is to say on opening the math editor and picking a source.
The probe missed it because filling the form sets the dropdown to the
value it already holds, and GObject emits no notify for that: a channel
sourcing channels().front() picks index 0 on a dropdown already at 0.
math_probe now opens on a channel sourcing the *last* acquired signal,
which does move the selection, and reads back the source the handler
wrote into the node.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Two complaints, not one: the glitch is a row dropped before any style
knob is consulted, and the thinness is a choice udpscope made and never
revisited -- it asks deps/plotter for a trace thinner than the library's
own default.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Twelve tasks in five phases, so relative timing ships before any of
the client-side reordering work lands.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
The two were asked for together and are one design: the packet counter is what
makes a hole addressable, so relative timing is the coordinate system in which
resequencing is arithmetic rather than inference.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
The earlier correction moved the claim rather than fixing it: four places still
said the float-equality test "never fires on a real-valued signal", and a +/-1
square is a real-valued signal -- a standalone check against a band of [1, 1]
fired 19 times, because `inside` is true at +1 and false at -1, so the signal
changes side on every transition.
All four now state the measured behaviour: an exact float-equality test against
the level, which an ordinary signal never satisfies and a signal sitting at the
level satisfies on every transition. Neither answer is a band, which is the
reason the second spin is clamped an increment away rather than the detector
special-cased -- the same conclusion, now resting on a true premise.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
A finite trigger_time() only says the edge was accepted; the mode is Capturing
until the post window fills. Every field the report prints is read from
display_snapshot(), whose stamps span x = 0 only once the event is Held, so
reporting on the latch alone raced the capture: leg 2 printed
`measured=nan at0=nan ... mode=1` on one run and the documented
`at0=-0.500907 earlier=-0.498185 mode=2` on the next. The report now waits for
Held under the same poll budget, and says `latched but never held` when it runs
out -- a different defect from `no latch`, so the line names which.
The readings are corrected against three consecutive leg-2 runs and one leg-3
run: `t0` is a rebased stream stamp and varies every run, so it was never an
assertion; `hits=` likewise tracks the arm phase (12 at one arm, 11 at another).
The mode ordinals were wrong -- `mode=2` is `Held`, not `Capturing`. Shapes 2
and 3 are now measured rather than read from the arm code; shape 1 still is not.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
--glitch-width defaulted to 0.0, so --glitch-at alone produced no glitch and no
warning — the same class of silent no-op that cost a debugging cycle earlier on this
branch. The default is now 0.002 s (2 ms), matching the standalone probe run.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- 08-trigger.txt: names all four condition shapes and the buffer search; fixes the first
paragraph and 'How to reach it' to match what the panel actually contains (fix 3).
- 10-measurements.txt: adds a Statistics bullet — one observation per recompute, what
resets the history, what does not (fix 3).
- probe-readings.md: re-quotes condition-probe lines with level2= and mode= fields;
corrects leg-2 window geometry (0.2 s / 10 % pre, not 1.0 s / 50 %); moves the
wide-window reason to legs 1 and 3; fixes the search-probe scheduling note
(search_probe calls condition_probe directly; do not also set CONDITION_MS) (fix 6).
- verification.md: corrects shape-2 window geometry to match the code (fix 7).
- invariants-session-and-export.md, README.md: document the measure_stats session key —
position, type, default false (fix 8).
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- The comment in `feed_window()` and three companion sites claimed a zero-width band
"never fires, because no sample can be on a different side of it than its neighbour".
That is false: `inside = value >= lo && value <= hi` with `lo == hi == 1.0` is true at
+1 and false at -1, so a ±1 square fires 19 times in 20 samples. The correct reason
the panel refuses one is that it reduces the condition to a float-equality test on a
real-valued signal, which in practice never fires (fix 4).
- `EventDetector::condition()`, `BufferSearch::channel()` and `BufferSearch::condition_`
were confirmed unused by grep and deleted (fix 10).
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- A buffer rebuild mid-scan (CONFIG or window change) now calls `search.clear()` beside
`reset_measure_stats()` at both sites; without it the scan kept stale at_/end_ and could
report Done over fabricated hits (fix 1).
- `search_marks_label` now carries `PANGO_ELLIPSIZE_END` so the side pane's minimum width
is bounded; the longest text (~58 chars) was driving the pane width (fix 2).
- `update_measures()` gains a third `accumulate` parameter (no default) so every call
states its intent; the Statistics toggle now passes `false`, stopping the same window
being counted twice and deflating sd on repeated toggles (fix 5).
- `search_jump()` records whether `publish_pause_view()` returned an empty snapshot and
`update_search_panel()` appends "(no longer in the buffer)" to the position label when
it did (fix 9).
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
place_search_marks() places the selected hit unconditionally to keep it marked when stepping
to it, but the label must distinguish this case from hits that are actually visible on screen,
so it does not lie about what is in view. add sel_off_view to track when the selected hit is
off screen, introduce a shown count that excludes it, and emit a third label case when only
the selected hit is off screen.
The plan's Task 8 named the search probe as its test but never extended it, and leaned on the
exit dump instead -- which stops the tick from Live, where no hit is in view, so it reads
placed=0 for a correct implementation and a broken one alike.
- The statistics label in measures_row() now carries PANGO_ELLIPSIZE_END,
matching the kind label's own treatment, so a long reading cannot widen
the pane beyond its measured minimum.
- The toggled handler on measures_stats_check now returns early when
updating_panels is set; apply_layout() sets updating_panels around its
gtk_check_button_set_active() call and then sets the Reset button's
sensitivity directly, so the loaded state is fully applied without a
spurious schedule_layout_save().
- The measures_row() header comment now names both labels that
update_measures() rewrites and explains the two-line layout.
- gtk_widget_set_sensitive on measures_stats_reset is null-checked in the
toggled handler, matching every neighbouring handler in the file.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>