tools: add assert_stage.py and a menu guard; record that the guard was not enough
assert_stage.py checks the DEFINITION table against an expected stage marker and
earned its keep immediately: its first live run reported MISMATCH -- the capture
had a live flight HUD and would have been filed as Stage 02, but was the S01
tutorial. That is exactly the failure that silently invalidated an earlier
cross-run comparison.
require_menu (launch_mission.sh) refuses to press until screen_id reads `menu`.
It is NOT sufficient, and this refutes my previous explanation: the run DID
confirm the menu and still loaded the tutorial. The real cause was that the
guard's own capture was a 10x710 sliver which classified as `menu` -- fixed
separately in 30e53f5.
Left open: whether the menu guard suffices now that slivers are rejected (not
re-run), and why the capture was a sliver at all when the other shots in the same
run were 1279x675.
This commit is contained in:
55
docs/re/nav-guards.md
Normal file
55
docs/re/nav-guards.md
Normal file
@@ -0,0 +1,55 @@
|
||||
# Nav guards — one works, one was not enough, and the real cause was a sliver
|
||||
|
||||
Added and exercised 2026-08-26 against a live run.
|
||||
|
||||
## ✅ Guard 2 works, and earned its keep on the first run
|
||||
|
||||
`tools/re-capture/assert_stage.py` states the expected stage and checks it against
|
||||
the **definition table** (definitions are the stage's cast and are present from
|
||||
load; instances arrive in waves). Its first live run:
|
||||
|
||||
```
|
||||
MISMATCH: UN_f101_TCAF_Acropolis is NOT in the 13 definitions
|
||||
UN_S01_Asteroid_cmesh_01a ... UN_e106_ADAN_Destroyer
|
||||
```
|
||||
|
||||
The run had reached a live flight HUD and would have been recorded as a valid
|
||||
Stage 02 capture. It was the **S01 tutorial**. Without this check the wrong-stage
|
||||
roster looks exactly like a right one — which is how the earlier cross-run
|
||||
comparison was silently invalidated.
|
||||
|
||||
Use it as the precondition for any runtime measurement:
|
||||
`./assert_stage.py UN_f101_TCAF_Acropolis` (exit 0 iff Stage 02 is loaded).
|
||||
|
||||
## ❌ Guard 1 was necessary but NOT sufficient — my explanation was wrong
|
||||
|
||||
`require_menu` in `launch_mission.sh` refuses to press until `screen_id.py` reads
|
||||
`menu`. [The previous note](stage-drift-is-navigation-not-save.md) said the
|
||||
tutorial was selected because the d-pad went out "from a state never confirmed to
|
||||
be the main menu". **That explanation is refuted:** this run confirmed the menu
|
||||
first, and *still* loaded the tutorial.
|
||||
|
||||
## ✅ The actual cause: the guard was shown a 10×710 sliver
|
||||
|
||||

|
||||
|
||||
The guard's own capture was **10 × 710** — not a frame at all. Every statistic in
|
||||
`screen_id.py` is an area fraction, so the sliver classified cleanly as `menu`
|
||||
(`green 0.0000, white 0.0157`). The guard passed on garbage, the fixed key
|
||||
sequence went out blind, and the selection landed on a tutorial entry.
|
||||
|
||||
🔑 **`bin/screenshot`'s own header already records this failure mode** from
|
||||
2026-08-18 — a second window of class `xenia_canary` meant grabs came back as
|
||||
slivers, and "a whole session's screen ids were noise". That fix hardened the
|
||||
**capture** side. It did not harden the **consumer**, so the same failure walked
|
||||
straight back in through a different path. Fixed now in `screen_id.py`: captures
|
||||
below 640×360 return `none` rather than a screen name (commit `30e53f5`).
|
||||
|
||||
## ❔ Still open
|
||||
|
||||
* Whether the menu guard is sufficient **now that the classifier rejects
|
||||
slivers** — not re-run. The sliver explains this run, but it does not prove the
|
||||
cursor/item-order assumption behind `dpad down` = LOAD GAME is correct.
|
||||
* Why the capture came back as a sliver at all when `bin/screenshot` is supposed
|
||||
to take the largest `xenia_canary` window by area. It succeeded for the other
|
||||
shots in the same run (1279×675), so it is intermittent, not systematic.
|
||||
Reference in New Issue
Block a user