fix: a condition leg is reported once it is held, so a working leg cannot read nan
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>
This commit is contained in:
1 parent
90d5d0e2d2
commit
c8f10f59dc
2 files changed
+40
-12
No files matched your search
@@ -601,10 +601,10 @@ Four legs, selected by `UDPSCOPE_PROBE_CONDITION_SHAPE`. Every leg prints one li
|
|||||||
```
|
```
|
||||||
|
|
||||||
Measured readings (`--rate 10000 --freq 5`, each on a fresh port). Shape 0's `level2=` and
|
Measured readings (`--rate 10000 --freq 5`, each on a fresh port). Shape 0's `level2=` and
|
||||||
`mode=` fields are from the `[search-probe]` run in `.superpowers/sdd/progress.md`; shapes 1–3
|
`mode=` fields are from the `[search-probe]` run in `.superpowers/sdd/progress.md`; shapes 2 and
|
||||||
were measured before those fields were added and their `level2=0.500000 mode=2` is read from
|
3 were re-measured with those fields present. **Shape 1's `level2=0.500000 mode=2` alone is read
|
||||||
the probe arm code (`condition_probe_arm` always sets `level2` to `0.5` and the mode after a
|
from the code** rather than from a run (`condition_probe_arm` always sets `level2` to `0.5`, and
|
||||||
latch is `Held=2`):
|
the probe now reports only once the mode is `Held=2`):
|
||||||
|
|
||||||
```
|
```
|
||||||
shape=0 type=1 cmp=0 width=0.010000 t0=1.710000 measured=0.004000 at0=nan earlier=nan level2=0.500000 mode=2
|
shape=0 type=1 cmp=0 width=0.010000 t0=1.710000 measured=0.004000 at0=nan earlier=nan level2=0.500000 mode=2
|
||||||
@@ -615,7 +615,16 @@ shape=3 type=3 cmp=0 width=0.010000 t0=4.120200 measured=0.300100 at0=nan earlie
|
|||||||
|
|
||||||
`measured` is the reading, not a phase. It is the pulse width read back from the held snapshot's
|
`measured` is the reading, not a phase. It is the pulse width read back from the held snapshot's
|
||||||
own stamps, which are edge-relative: the snapshot is the ground truth, not the mock's absolute
|
own stamps, which are edge-relative: the snapshot is the ground truth, not the mock's absolute
|
||||||
clock. Three things are worth knowing before calling a reading wrong:
|
clock.
|
||||||
|
|
||||||
|
**`t0` is not an assertion.** It is a stream stamp, and the stream clock is rebased by whichever
|
||||||
|
rebuild last dropped history, so the same leg reads a different `t0` on every run — leg 2 read
|
||||||
|
`1.7103`, `1.6975` and `1.8719` on three consecutive runs, and leg 3 read `2.6552` against a
|
||||||
|
`--quiet-at 4.0` stream. Read `measured`, `at0`/`earlier` and `mode`; read `t0` only as
|
||||||
|
*something* latched. A leg that is genuinely not working says so in `measured`/`at0`, or does not
|
||||||
|
latch at all.
|
||||||
|
|
||||||
|
Four more things are worth knowing before calling a reading wrong:
|
||||||
|
|
||||||
- **Leg 0**: `measured=0.004` is the injected glitch width (here the search-probe run used
|
- **Leg 0**: `measured=0.004` is the injected glitch width (here the search-probe run used
|
||||||
`--glitch-width 0.004`; the earlier standalone probe run read `0.002` with `--glitch-width 0.002`).
|
`--glitch-width 0.004`; the earlier standalone probe run read `0.002` with `--glitch-width 0.002`).
|
||||||
@@ -633,12 +642,20 @@ clock. Three things are worth knowing before calling a reading wrong:
|
|||||||
- **Leg 3**: `measured=0.300` is the dropout timeout. **This leg also uses `sine`**. A timeout of
|
- **Leg 3**: `measured=0.300` is the dropout timeout. **This leg also uses `sine`**. A timeout of
|
||||||
0.050 s against a sine crossing zero every 0.1 s latches on a healthy signal, so use 0.300 s
|
0.050 s against a sine crossing zero every 0.1 s latches on a healthy signal, so use 0.300 s
|
||||||
or longer; **use a 1.0 s window with 50 % pre** so the last crossing before the outage lies
|
or longer; **use a 1.0 s window with 50 % pre** so the last crossing before the outage lies
|
||||||
within the pre window.
|
within the pre window. It needs `--quiet-at`: with `--quiet-at -1` the leg correctly never
|
||||||
|
latches, which is the check that the dropout is not firing on the rebuild's own gap.
|
||||||
|
|
||||||
The channel-selection line `[condition-probe] <name>=<index> of <N> channels` is printed before
|
The channel-selection line `[condition-probe] <name>=<index> of <N> channels` is printed before
|
||||||
the trigger fires; if the channel is not found this reads `-1` and the probe fails immediately.
|
the trigger fires; if the channel is not found this reads `-1` and the probe fails immediately.
|
||||||
A failure line `[condition-probe] no latch after N polls` means the condition never fired — a
|
There are two failure lines, and they name different defects:
|
||||||
wrong shape, a missing mock flag, or the wrong signal selected.
|
|
||||||
|
- `no latch after N polls` — the condition never fired: a wrong shape, a missing mock flag, or
|
||||||
|
the wrong signal selected.
|
||||||
|
- `latched but never held` — the edge was accepted but the post window never filled, so there is
|
||||||
|
no snapshot to read. The report deliberately waits for `Held`: a finite `trigger_time()` only
|
||||||
|
means the edge was *accepted*, and every field is read from `display_snapshot()`, whose stamps
|
||||||
|
span x = 0 only once the event is held. Reporting on the latch alone printed `nan` for legs
|
||||||
|
that were working.
|
||||||
|
|
||||||
## `[stats-probe]`
|
## `[stats-probe]`
|
||||||
|
|
||||||
@@ -694,8 +711,13 @@ Measured output (port 8419):
|
|||||||
different clock — which is exactly the class of defect a search that merely "returns plausible
|
different clock — which is exactly the class of defect a search that merely "returns plausible
|
||||||
times" hides. Here `err=0`: exact agreement, not within tolerance.
|
times" hides. Here `err=0`: exact agreement, not within tolerance.
|
||||||
- `state=2` is `BufferSearch::State::Done` (the enum's ordinal). `state=1` would be `Running`.
|
- `state=2` is `BufferSearch::State::Done` (the enum's ordinal). `state=1` would be `Running`.
|
||||||
- `mode=4` after the jump is `DisplayMode::Paused` (the enum's ordinal). `mode=2` would be
|
- `mode=4` after the jump is `DisplayMode::Paused` (the enum's ordinal: `Live=0`, `Capturing=1`,
|
||||||
`Capturing`.
|
`Held=2`, `Waiting=3`, `Paused=4`). `mode=2` would be `Held` — the jump having left the held
|
||||||
|
event in place instead of publishing its own pause view.
|
||||||
|
- **`hits=` is a count, not a constant.** It depends on the retained span and on the arm phase,
|
||||||
|
both of which move between runs: the same invocation read `hits=12` at `armed t0=5.710000` and
|
||||||
|
`hits=11` at `armed t0=5.742000`. A count in the low tens is the reading; `hits=0` with
|
||||||
|
`agree=0` is the defect.
|
||||||
- **`placed=1 of 1 in view` is the correct answer, not an under-count.** The jump frames a 0.2 s
|
- **`placed=1 of 1 in view` is the correct answer, not an under-count.** The jump frames a 0.2 s
|
||||||
window and the glitches are 0.4 s apart (one per square period at 5 Hz / square half-frequency),
|
window and the glitches are 0.4 s apart (one per square period at 5 Hz / square half-frequency),
|
||||||
so only one hit can be in view at a time. `1 of 1` against `(12 found)` is the marks agreeing
|
so only one hit can be in view at a time. `1 of 1` against `(12 found)` is the marks agreeing
|
||||||
|
|||||||
+8
-2
@@ -8975,9 +8975,15 @@ gboolean condition_probe_report(gpointer user) {
|
|||||||
App* a = static_cast<App*>(user);
|
App* a = static_cast<App*>(user);
|
||||||
if (a->window == nullptr) return G_SOURCE_REMOVE;
|
if (a->window == nullptr) return G_SOURCE_REMOVE;
|
||||||
const double t0 = a->model->trigger_time();
|
const double t0 = a->model->trigger_time();
|
||||||
if (!std::isfinite(t0) || t0 <= 0.0) {
|
// A finite `t0` only says the edge was *accepted*: the mode is `Capturing` until the post
|
||||||
|
// window fills. Every field below is read from `display_snapshot()`, whose stamps span x = 0
|
||||||
|
// only once the event is `Held`, so reporting on the latch alone races the capture and
|
||||||
|
// prints `nan` for a leg that is working. Both waits share the one poll budget.
|
||||||
|
if (!std::isfinite(t0) || t0 <= 0.0 || a->model->display_mode() != DisplayMode::Held) {
|
||||||
if (++g_condition.waited < 200) return G_SOURCE_CONTINUE;
|
if (++g_condition.waited < 200) return G_SOURCE_CONTINUE;
|
||||||
std::fprintf(stderr, "[condition-probe] no latch after %d polls\n", g_condition.waited);
|
const bool latched = std::isfinite(t0) && t0 > 0.0;
|
||||||
|
std::fprintf(stderr, "[condition-probe] %s after %d polls\n",
|
||||||
|
latched ? "latched but never held" : "no latch", g_condition.waited);
|
||||||
std::fflush(stderr);
|
std::fflush(stderr);
|
||||||
return G_SOURCE_REMOVE;
|
return G_SOURCE_REMOVE;
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in new issue
Block a user