re: measure the boot-nav title gate — and withdraw my own diagnosis

Last iteration I said launch_mission died because skip_intro only tests for
the title on a static frame, gated at rmse <= 1500, and that run logged 1503
and 1549 just above the cut. I also said the fix was NOT to nudge 1500 but
to measure both signals through a boot first. Measured, and the diagnosis
does not survive.

boot_trace.sh logs the two signals skip_intro decides on -- frame-to-frame
RMSE and the is_title.py green-glyph count -- through a clean boot with no
presses at all. One run, 29 samples over 484 s:

  8 samples had rmse <= 1500, so the gate OPENED eight times
  0 samples had glyph > 0, so the title was never seen

At t=145 s the RMSE was 1205, comfortably inside the threshold, and the
glyph test was called and answered zero. A frame can be perfectly static
without being the title -- the intro movie has long quiet stretches, three
reading RMSE exactly 0. So 1503/1549 were almost certainly movie frames too,
and raising the constant would have admitted two more of them.

What is left is narrower and honest: the interactive title never appeared,
rather than appearing and being missed by a threshold.

The limitation is recorded rather than buried: the tracer intended 1 s
sampling and achieved 16.9 s, because each iteration forks two screenshots,
ImageMagick compare and a fresh Python. So this does NOT prove the title
never appeared -- only that it was absent from 29 samples. A window shorter
than ~17 s falls between them. The recorded next step is to make the tracer
sample at the rate it claims before concluding anything stronger.

Artifact: docs/re/captures/boot-signal-trace.tsv.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01PMRJjbxLqZtsb5Vb7KunPE
This commit is contained in:
Sylpheed RE agent
2026-08-25 22:42:33 +00:00
parent 501298de81
commit 608a0cc710
4 changed files with 181 additions and 19 deletions

View File

@@ -1033,25 +1033,31 @@ premise was wrong.**
Candidates: the **7 `.embsec_` sections** (VAs 0x84D00000x86AC000, ~129 KB
total, executable) or a hashed record in `hidden/MiscBin.pak`. **Finding it
gives the actual per-phase clear condition for every stage.**
* 🚧 **(2026-08-25) BLOCKED — the live test of the `reset_phase_threads` rename
never got to run, because boot-nav cannot reach the title.** The experiment is
ready and worth doing: built-in 100 clears the trigger container and frees
every thread but the caller, so at a phase terminator **both**
`[phase+272+20]` (triggers queued) and `[phase+216+8]` (coroutines alive)
should collapse; if they climb straight through a phase boundary instead, the
reading is wrong. `tools/re-capture/phase_watch.py` now prints both counters —
**written this session but never yet exercised against a live guest.**
**The blocker, measured:** `skip_intro.sh` only tests for the title when the
frame is static, gated at `rmse <= 1500`. A 381 s run produced 18 "waiting it
out" samples, and two of them — **1503 at 104 s and 1549 at 139 s** — sat just
above the cut, so `is_title.py` was never even called and the single allowed
press was never spent. The attract loop then restarts and the wait never ends.
▶️ **First step, and it is NOT "raise the constant":** log `rmse` *and* the
`is_title.py` glyph count every second through a boot, so the true-title and
attract-demo distributions can be seen; only then decide the gate. Tuning 1500
to make one run pass would be fitting to a single sample. Note the surrounding
comments are emphatic that tapping through the movies is what breaks the
title, so the press budget really is one.
* **(2026-08-25) My own boot-nav diagnosis, MEASURED AND WITHDRAWN.** I said
the run died because `skip_intro.sh` gates the title test at `rmse <= 1500`
and the run logged 1503/1549, just above the cut. Measured over a clean
no-press boot ([`boot-nav-title-gate.md`](boot-nav-title-gate.md),
`captures/boot-signal-trace.tsv`): the gate **opened eight times** in 29
samples, and at `t=145 s` the RMSE was **1205** — inside the threshold — with
`is_title.py` answering **0 glyph pixels**. The glyph count was 0 in *all* 29
samples over 484 s. A static frame is not the title; the intro movie has long
quiet stretches, three of them reading RMSE exactly 0. So the gate is not what
stopped it, and raising the constant would have admitted two more movie frames.
🟡 Narrowed: **the interactive title never appeared**, rather than appearing and
being missed. ❔ **But the run does not prove that** — the tracer intended 1 s
sampling and achieved **16.9 s** (two screenshots + ImageMagick `compare` + a
fresh Python per iteration), so a title window under ~17 s falls between
samples. ▶️ First step: make the tracer sample at the rate it claims — one
long-lived Python process computing both signals — then re-run. Second: check
whether the fast 2026-08-25 run had a warm shader cache that this one, started
after `rm -f /dev/shm/xenia_*`, did not.
* 🚧 **(2026-08-25) STILL UNRUN — the live test of the `reset_phase_threads`
rename.** Built-in 100 clears the trigger container and frees every thread but
the caller, so at a phase terminator **both** `[phase+272+20]` (triggers
queued) and `[phase+216+8]` (coroutines alive) should collapse; if they climb
straight through a phase boundary instead, the reading is wrong.
`tools/re-capture/phase_watch.py` prints both — **written, still never
exercised against a live guest.** Blocked behind the boot-nav item above.
* 🟡 **(2026-08-25) The legacy IDXD string-pool reader is wrong far more often
than assumed** — now measurable for the first time, since the record table gives
a ground truth. Verified by hand: `FCSRange` (the module doc's own canonical

View File

@@ -0,0 +1,85 @@
# The boot-nav title gate — my own diagnosis, measured and withdrawn
Status: ❌ **the previous diagnosis is WITHDRAWN.** 🟡 the real failure is
narrowed but not settled. ❔ the measurement has a limitation that matters, and
it is stated below rather than buried.
## What I claimed last iteration
`launch_mission.sh` failed to reach the mission: 381 s of `skip_intro.sh`
printing "movie … waiting it out", 18 times, and the ready room never arrived.
`skip_intro.sh` only tests for the interactive title when the frame is **static**,
gated at `rmse <= 1500`, and that run logged **1503 at 104 s** and **1549 at
139 s** — just above the cut. I wrote that the gate had therefore blocked the
title test and eaten the run.
I also wrote, correctly, that the fix was *not* to nudge 1500, and that the first
step was to measure both signals through a whole boot. That is what this is.
## The measurement
`tools/re-capture/boot_trace.sh` logs, without pressing anything, the two signals
`skip_intro.sh` decides on: the frame-to-frame RMSE (two grabs 0.6 s apart) and
the green-glyph pixel count from `is_title.py` — independent tests for "is this
static" and "is this the interactive title".
One clean boot, no input at any point:
[`captures/boot-signal-trace.tsv`](captures/boot-signal-trace.tsv).
```
29 samples spanning 484 s
8 samples with rmse <= 1500 (the gate OPENED eight times)
0 samples with glyph > 0 (the title was never seen)
```
The eight low-RMSE samples: `t=12, 29, 62` (rmse 0), `t=99` (1486), `t=115`
(1350), `t=145` (**1205**), `t=316` (0), `t=484` (0).
## ❌ Why the old diagnosis is wrong
The gate is not what stopped it. It **opened eight times**, and at `t=145` the
RMSE was **1205** — comfortably inside the threshold — so `is_title.py` was
called and answered **0 glyph pixels**. A frame can be perfectly static and still
not be the title; the intro movie has long quiet stretches, and three samples
read an RMSE of exactly 0.
So `1503`/`1549` in the failing run were almost certainly *also* not the title,
and raising the threshold to admit them would have admitted two more movie
frames, not the title. The instinct to leave the constant alone was right; the
reason I gave for it was wrong.
## 🟡 What the failure actually is
Narrowed, not settled: **the interactive title never appeared at all** in 484 s
of a no-press boot — not "appeared and was missed by the gate". The glyph count
was 0 in all 29 samples, including the last one at 484 s where the frame was
completely static (rmse 0).
A static frame with no glyph at 484 s is consistent with the attract loop having
returned to a title that, per `menu_draw_capture.sh`, "accepts nothing at all" —
but this run never pressed anything, so nothing can have broken it. That points
at the boot itself, not at the navigation.
## ❔ The limitation, stated plainly
**The intended sampling rate was 1 s; the achieved rate was 16.9 s.** Each
iteration takes two screenshots, runs ImageMagick `compare` and starts a Python
interpreter, and that costs ~15 s per loop in this container. So 29 samples cover
484 s with big gaps between them.
That means this run does **not** prove the title never appeared — only that it
was absent from every one of 29 samples. A title window shorter than ~17 s could
fall between two samples. Before concluding anything stronger, the tracer needs
to get cheap enough to sample at the rate it claims: keep one Python process
alive and compute the RMSE and the glyph count in it, instead of forking
`compare` and a fresh interpreter every second.
## What this does not settle
* Whether the title ever appears on this boot path at all.
* Whether the earlier "readyroom at 9 s, IN FLIGHT at 37 s" run (recorded
2026-08-25 in `BACKLOG.md`) used a warm shader cache that this run lacked —
this one was started after `rm -f /dev/shm/xenia_*`, which the fast run may not
have been.
* The live test this was all for — whether the trigger container and the
coroutine list both collapse at a phase terminator — remains unrun.

View File

@@ -0,0 +1,30 @@
secs rmse glyph
12 0 0
29 0 0
47 11264 0
62 0 0
80 3250 0
99 1486 0
115 1350 0
130 1512 0
145 1205 0
159 2714 0
171 2712 0
189 34429 0
201 30721 0
218 10379 0
234 12487 0
252 14940 0
273 23650 0
293 12200 0
308 35782 0
316 0 0
332 8713 0
351 21680 0
369 7567 0
386 4642 0
412 9647 0
436 6524 0
458 18867 0
476 11594 0
484 0 0
1 secs rmse glyph
2 12 0 0
3 29 0 0
4 47 11264 0
5 62 0 0
6 80 3250 0
7 99 1486 0
8 115 1350 0
9 130 1512 0
10 145 1205 0
11 159 2714 0
12 171 2712 0
13 189 34429 0
14 201 30721 0
15 218 10379 0
16 234 12487 0
17 252 14940 0
18 273 23650 0
19 293 12200 0
20 308 35782 0
21 316 0 0
22 332 8713 0
23 351 21680 0
24 369 7567 0
25 386 4642 0
26 412 9647 0
27 436 6524 0
28 458 18867 0
29 476 11594 0
30 484 0 0