re: the main menu has no idle self-return -- and four of my own durations were a backlog

Two results and one retraction, all from the same session.

REFUTED: 'an ~8-10 s idle returns to the title' does not apply to the main menu.
Held untouched it stayed put for >= 60 s, correlation never leaving
0.9245-0.9249. That timer is real but belongs to the TITLE. It was the only
reason 'B leaves the main menu' was classed as authored, so Q5's B rule is
upgraded to measured-ordering: B is delivered (canary logs vk=5801) and is the
only input in >= 100 s before the return.

The PRESS (A) plate: the boot title presents build 4 WITHOUT the plate first --
green-glyph 154, against 159 on the committed no-plate capture and 753/977/1493
on plate titles -- and the plate arrives after. That is the port's third option.

RETRACTED: four durations taken the same day. classify_array costs 1503 ms per
frame; running it per frame against an 8 fps x11grab drained the pipe at
0.64 fps, so every classified frame was stale and increasingly so. It
manufactured 'plate 24.66 s after the title art', 'B->title 15.58 s', 'B->title
25.60 s' and 'A->menu 20.26 s'. The tell: a transition, a press and a fade do
not share a duration, and the two B figures GREW across a longer run.

A backlog preserves ordering and destroys durations, which is why the sequence
results above stand and every timing does not. The ring's period is unaffected
and that was checked, not assumed -- ring_period ran at 15.03 fps against a
requested 15.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01KNR5Y79D1T4bBr6gJQaWFP
This commit is contained in:
sylph-decoder
2026-08-29 11:50:46 +00:00
parent 724e06b134
commit 7a4a74f8d7
7 changed files with 427 additions and 8 deletions

View File

@@ -147,7 +147,7 @@ files, which is how the same ground got covered twice.
| [`structures/unit-struct-runtime.md`](structures/unit-struct-runtime.md) | Runtime `Unit` struct (craft / vessel definitions) — read from live guest memory | — |
| [`structures/weapon-struct-runtime.md`](structures/weapon-struct-runtime.md) | Runtime `Weapon` / `Shell` structs — read from live guest memory | — |
| [`structures/xbg7-mesh.md`](structures/xbg7-mesh.md) | XBG7 — mesh geometry (inside XPR2 model containers) | — |
| [`capture-harness-status.md`](capture-harness-status.md) | Why the harness stops reaching the title — and, since 2026-08-29, why there is no oracle at all | 🔴 **the decoder container has NO disc**: no ISO, no XEX, no pak anywhere on the filesystem. Root-caused to `06676d3` moving `/work` to a named volume without replacing the disc mount; `sylph-port` mounts it, `sylph-decoder` does not. Earlier sections: `screenshot` costs 10.8 s under xenia (92×), and `trace_gpu_stream` is a no-op in the Release build |
| [`capture-harness-status.md`](capture-harness-status.md) | Why the harness stops reaching the title — and the two instruments that could not see the disc | ✅ **the disc is BACK** (2026-08-29, container replaced at 11:07:38): `/disc` is a real 6.2 GB read-only mount and `screen list` returns 12 builds. The "no disc" section is withdrawn — and its two instruments were blind either way: `find / -xdev` cannot cross into a bind mount on another device, and `sylph-doctor` only ever looks under `/work`. Earlier sections: `screenshot` costs 10.8 s under xenia (92×), and `trace_gpu_stream` is a no-op in the Release build |
| [`title-crash-stl-tree.md`](title-crash-stl-tree.md) | The title-screen crash is an STL `map`/`set` erase on a bad iterator | ✅ CONFIRMED — the guest throws std::out_of_range from an STL |
| [`ui-paint-order-third-permutation.md`](ui-paint-order-third-permutation.md) | A third measured paint order — tool built and validated, screen not reached | ✅ the reader works and is CONFIRMED against both previously |
| [`ui-quad-class-foothold.md`](ui-quad-class-foothold.md) | The guest's UI quad class — a foothold found from the capture's vertex layout | 🟡 PROBABLE for the identification below (it is a static read, but |
@@ -162,3 +162,5 @@ files, which is how the same ground got covered twice.
| [`upstream-baseline.md`](upstream-baseline.md) | A stock-upstream baseline runs Stage 02 crash-free | ✅ CONFIRMED — upstream canary_experimental + only the pad |
| [`weapon-datasheet-runtime.md`](weapon-datasheet-runtime.md) | Weapon DATA SHEET — runtime capture (Route B) | 🟡 first dynamic capture, 2026-07-28. The Arsenal's Gallery Mode panel is a |
| [`xpr2-colour-check.md`](xpr2-colour-check.md) | XPR2 colours: channel order ✅ confirmed against the running game | — |
| [`focus-ring-spin-measured.md`](focus-ring-spin-measured.md) | The main menu's focus ring spins continuously — and how fast | ✅ **measured**: period **2.177 s** over 9 revolutions (8 evenly spaced autocorrelation peaks) = 120 units = 60 frames = 2.00 s at 30 Hz. A pulse is excluded — annulus total conserved to 0.4 % while per-bin brightness swings by 24. ✅ the ring is the **only** moving thing on the settled main menu (std exactly 0.000 elsewhere). 🔴 no angle is quoted: the angular estimator FAILED its own control (30° → 0°) |
| [`menu-idle-and-b-2026-08-29.md`](menu-idle-and-b-2026-08-29.md) | The main menu does not idle back to the title — and four durations that were a pipeline | ✅ **refuted**: no self-return in **≥ 60 s** untouched; the ~8–10 s idle belongs to the **title**. 🟡 Ⓑ→title ordering measured, latency not. 🔴 `classify_array` at **1503 ms/frame** drained an 8 fps stream at 0.64 fps and manufactured four latencies (24.66 s / 15.58 s / 25.60 s / 20.26 s) — all withdrawn; a backlog preserves ordering and destroys durations |

View File

@@ -617,3 +617,35 @@ neighbourhood, not just the line.
`10 144 of 10 148 references resolve`) → **withdrawn; it is on the disc.** It is
the `GP_STAGE_CLEAR` child the same scan named `8AX`. With the name decoded the
count is **10 148 of 10 148**. [`ratc-child-names.md`](structures/ratc-child-names.md)
## The oracle harness and the container (2026-08-29)
* "the decoder container has no disc" → **refuted the same day.** The container
was replaced and `/disc` is a real 6.2 GB read-only mount. Worse, both
instruments behind the claim were blind to the answer either way:
`find / -xdev` **cannot cross** into a bind mount on another device, and
`sylph-doctor` only checks `/work` and never `$SYLPHEED_DISC`. "sylph-doctor
agrees" was two instruments sharing one blind spot.
→ To test for the disc, ask the variable that names it:
`sylpheed-cli screen list "$SYLPHEED_DISC/dat/GP_TITLE.pak"`.
* "the main menu returns to the title on its own after ~8–10 s idle" → **refuted.**
The menu sat untouched for **≥ 60 s** without moving (correlation never leaving
0.9245–0.9249). The ~8–10 s idle is real but belongs to the **title**. This was
the only reason "Ⓑ leaves the main menu" was classed as authored.
* "whole-image statistics (green / white / mean) can tell the title from the
attract movie" → **refuted.** A frame of `ADV.wmv` with a bright green laser
reads green 0.0018 / white 0.086 / mean (53,67,76) — the title's numbers. A
probe built on it tapped Ⓐ into the movie and waited 120 s for a menu that was
never coming. → Correlate against a committed capture instead, and keep movie
frames as the negative controls.
* "a 360-bin angular cross-correlation can measure the focus ring's rotation
angle" → **refuted by its own control**: a synthetic **30°** rotation of a live
frame came back as **0°** (peak 0.596), while 90/180/270° came back exactly
(peak 1.000) — it only resolves exact pixel permutations. No angle was quoted;
the spin was established from brightness conservation instead.
* "a latency read off a classified `x11grab` stream is a duration" → **refuted.**
At 1503 ms per classification against an 8 fps stream the consumer ran at
0.64 fps, so frames were stale and increasingly so. Four "durations" died with
it. The tell was that a screen transition, a button press and a plate fade all
came out at ~20–25 s. → A backlog **preserves ordering and destroys
durations**; check consumed-fps against requested-fps before quoting a time.

View File

@@ -0,0 +1,120 @@
# 🔴 The main menu does NOT self-return to the title — and three "latencies" were my own pipeline
**Status:** one ✅ **measured** negative, one 🟡 ordering-only result, and one
🔴 **instrument defect that voids three numbers I took the same day.** Taken
2026-08-29.
## ✅ Refuted: "an ~8–10 s idle returns to the title" does not apply to the main menu
HANDOFF's residue table downgraded *Ⓑ leaves the main menu* to **authored**, on
the grounds that "an ~8–10 s idle also returns to the title, and nobody has
separated the two". That reason is now gone.
**Measured:** the main menu was held with **no input at all** and classified every
~1.2 s by [`screen_match.py`](../../tools/re-capture/screen_match.py):
| phase | duration untouched | screens seen |
|---|---|---|
| period capture | 24 s | menu only |
| idle probe | **60 s** (49 samples) | **menu only** |
Correlation against the committed main-menu capture never moved outside
**0.9245 – 0.9249** across the whole idle window — not a drift, not a fade, a
screen sitting still. Conservatively that is **≥ 60 s of continuous idle with no
self-return**, against a claim of 8–10 s.
✅ **And the 8–10 s idle is real — it belongs to the TITLE.** Immediately after
this run, a probe that expected to find the title still on screen found it had
left on its own into the attract movie. So the corpus's idle timer is a property
of the **title screen** (title → `ADV.wmv` → title), and the residue table
attached it to the wrong screen.
**What this gives the port:** the idle alternative that made Ⓑ unprovable is
refuted *on the screen in question*. Ⓑ is no longer competing with a timer there.
## 🟡 Ⓑ on the main menu: the ordering survives, the timing does not
Ⓑ was **delivered** — Canary's own log records `[file-pad] keystroke vk=5801
down` / `up` and `XamInputGetKeystrokeEx -> user=0 vk=5801`, so this is not a
dropped press. In both runs the menu was followed by the title, and in both runs
**Ⓑ was the only input** in a window of ≥ 100 s either side.
🟡 **But it is still two observations with a confound I cannot yet exclude**, and
the reason is the next section: the "latency" I measured is worthless, so I
cannot say the return followed Ⓑ *promptly*. What stands is ordering plus the
absence of any other cause:
* no input for ≥ 100 s before → no transition;
* Ⓑ delivered → transition to the title.
**Classification: measured ordering, unmeasured timing.** The port should keep
Ⓑ→title, and it is now better supported than "authored" — but it is not yet a
timed measurement.
## 🔴 The defect: an oracle that cost 1503 ms per frame produced three fake latencies
`screen_match.classify_array` does a ±8 px ZNCC search over a 675×1279 surface
against two references. **Measured: 1503 ms per frame.** A probe calling it on
every frame of an 8 fps `x11grab` stream therefore drained the pipe at
**0.64 frames/s** — verified from the probe's own trace, 107 samples over 166 s.
The pipe backed up at ~7.4 fps, so every frame classified was **stale, and
increasingly so**. That is not a subtle bias; it manufactured three numbers:
| reported | actually |
|---|---|
| plate appears 24.66 s after the title art | unknown |
| Ⓑ → title in 15.58 s (run 1) | unknown |
| Ⓑ → title in 25.60 s (run 2) | unknown |
| Ⓐ → menu in 20.26 s | unknown |
🔴 **All four are withdrawn.** The tell was that they are all ~20–25 s: a screen
transition, a button press and a plate fade do not share a duration, but a
backlog does. The two Ⓑ figures *growing* 15.6 → 25.6 s across a longer run is
the backlog accumulating, and it is the signature to remember.
⚠️ **What a backlog does and does not destroy.** It delays every frame by the
same growing amount, so it **preserves ordering** and destroys **durations**.
That is why the ordering results above survive and every duration here does not.
✅ **Fixed and re-controlled.** `screen_match` now has a `fast=True` path
(4× decimation, ±2 decimated px) at **38–75 ms**, a 20–60× reduction, and the
control was re-run on **both** paths: 8/8 each, with the fast path agreeing with
the exact path to **±0.005** on every score.
✅ **The ring measurements are NOT affected**, and this was checked rather than
assumed: `ring_period.py` does a greyscale conversion and a crop per frame, and
achieved **15.03 fps against a requested 15** — it kept up exactly, so its
timestamps carry no backlog. Its period also has an internal check a drifting
clock cannot pass: eight *evenly spaced* autocorrelation peaks
([`focus-ring-spin-measured.md`](focus-ring-spin-measured.md)).
## 🟡 The `PRESS Ⓐ` plate: sequence answered, duration not
The port asked whether the boot title is build 4 alone, build 4 with the plate
composited from the start, or build 4 **then** the plate after a delay.
✅ **It is the third.** On the boot title the green-Ⓐ glyph count went
**154 → 781** with the title art already matching at 0.946. The 154 is the
decisive number: the committed no-plate capture
`live-title-build4-no-plate.png` reads **159** with the same counter, and plate
titles read 753 / 977 / 1493. So the title genuinely presents **without** the
plate first, and the plate arrives afterwards.
🔴 **How long afterwards is NOT measured** — that figure came from the backlogged
probe and is withdrawn with the rest. The port needs one more run with the fast
path to get it.
## Instrument controls, now committed
The negative controls for `screen_match` are **movie frames**, because that is
the class the oracle exists to reject — a statistics-based oracle
(green/white/mean) called a frame of `ADV.wmv` containing a bright green laser
`title`, and a probe built on it tapped Ⓐ into the movie and then waited 120 s
for a menu that was never coming.
An earlier version of the control list pointed at two **scratch** grabs, and a
later run of the same probe overwrote one of them — turning a negative control
into a title frame and failing the control for the wrong reason. They are now
committed fixtures under
[`captures/instrument-controls/`](captures/instrument-controls/).