re: a title negative that survives its own cross-check
Three earlier "the title never appears" claims came from instruments later found broken -- a stale pixel oracle, a 41 s sampling interval, a freezing stream. This one carries its own evidence. title_probe_xchecked.py restarts its capture stream every 30 s AND prints its reading beside an independent `import` grab every 60 s: 1851 frames in 560.2 s = 3.30 fps cross-checks 9, disagreements 1 max glyph 0 t= 62s stream 6.05 | import 0.07 disagree (a fade, logos mid-transition) t=123s stream 7.40 | import 7.49 agree t=183s stream 8.18 | import 8.29 agree t=243s stream 0.23 | import 0.10 agree t=311s stream 89.68 | import 89.51 agree t=371s stream 80.97 | import 81.58 agree t=426s stream 117.43 | import 117.72 agree t=487s stream 77.71 | import 76.25 agree t=546s stream 70.43 | import 70.55 agree Eight of nine agree within 2%, fps held at 3.30 with no collapse to 1.60, and the surface moved through dark and bright phases. So the frames were live: over 560 continuous seconds from launch, sampled 3.3 times a second, the interactive title's green (A) plate never appears while the game renders throughout. The final frame correlates 0.0145 / -0.0047 / 0.0102 with our title / main menu / EXTRAS renders -- attract-movie content, not a UI screen. Why remains unknown. live-title-press-a.png with its 753 glyph pixels proves the title was reachable from this container on 2026-08-28, and clearing the shader cache fixed the black surface but not this. The two emulator-side questions (gamma control, 8AX vs ptbase) are therefore blocked on a characterised failure rather than a suspicion. Neither blocks the five menu screens, so I am returning to static work; the probe is committed for whoever picks it up. METHOD: a probe that cross-checks itself turns "no result" into a result.
This commit is contained in:
@@ -77,6 +77,29 @@ alongside it.
|
||||
| **Q10** | **What are a music bank's sub-waves?** `BGM_001.slb` is three sub-waves — 10 KB, 4.47 MB, 4.67 MB — and we currently **concatenate them blindly** into one 347 s track. Two near-equal halves could be intro + loop, or two variations, or two halves of one piece. A menu that loops its music needs to know which | The role of each sub-wave, established for at least the menu BGM. "Concatenate" is a decision, not a default — right now it is a default nobody chose |
|
||||
| **S1** | ~~**Ready Room probe.**~~ **DONE 2026-08-28 — [no-go](../re/ready-room-probe.md).** It is 2D and enumerates fine, but the pak is briefing/tactical-map content, not the Ready Room menu | ✅ go/no-go written |
|
||||
|
||||
## 🔴 Emulator-side questions are blocked — the title is not reachable here
|
||||
|
||||
**Status 2026-08-29, instrument-verified.** Two open items need a running menu:
|
||||
the gamma control behind [tone curve](../re/structures/ui-render-tone-curve.md),
|
||||
and separating `8AX` from `ptbase` in
|
||||
[8AX](../re/structures/ui-8ax-fullres-background.md). Both are blocked.
|
||||
|
||||
✅ **The negative is now solid.** A probe that restarts its capture stream every
|
||||
30 s and cross-checks itself against an independent grabber every 60 s
|
||||
(9 checks, 8 agreeing to within 2 %) ran **560 continuous seconds from launch at
|
||||
3.30 fps**: the interactive title's green Ⓐ plate never appeared, while the game
|
||||
rendered throughout. The final frame correlates 0.0145 / −0.0047 / 0.0102 with
|
||||
our title / main-menu / `EXTRAS` renders — attract-movie content.
|
||||
|
||||
❔ **Why is unknown.** `live-title-press-a.png` (753 glyph pixels) proves it was
|
||||
reachable from this container on 2026-08-28. Clearing the shader cache fixed a
|
||||
*black surface* but not this.
|
||||
|
||||
⚠️ Neither blocked item blocks the five menu screens. See
|
||||
[capture-harness-status](../re/capture-harness-status.md) for the full trail,
|
||||
including three earlier "the title never appears" claims that were withdrawn
|
||||
because the instrument was broken each time.
|
||||
|
||||
## 🟡 Needs one more run — a Japanese-locale capture
|
||||
|
||||
Recorded rather than worked around, per "do not improvise around a blocker".
|
||||
|
||||
@@ -544,3 +544,10 @@ agent's loop prompt, i.e. nowhere durable. See [`README.md`](README.md) for the
|
||||
"2 391 frames, zero hits" reads as overwhelming and collapses to nothing once
|
||||
the frames may all be the same frame. Sample count is not evidence of coverage
|
||||
unless the samples are known to be independent.
|
||||
* **A probe that cross-checks itself turns "no result" into a result.** Three
|
||||
successive "the title never appears" claims were withdrawn because the
|
||||
instrument was broken each time. The version that finally held prints its own
|
||||
reading beside an independent grabber's every 60 s — 9 checks, 8 agreeing to
|
||||
within 2 % — so the negative arrives with its own evidence that the frames were
|
||||
live. Building the cross-check into the tool costs a few lines and is what
|
||||
separates a measurement from a silence.
|
||||
|
||||
@@ -223,3 +223,59 @@ single A/B does not exclude run-to-run variation. The old caches are kept in
|
||||
|
||||
❔ **Still no title.** Even rendering, `max glyph 0` — but that number now comes
|
||||
from a stalling probe, so it establishes nothing either way.
|
||||
|
||||
---
|
||||
|
||||
## ✅ A negative I can finally stand behind — measured with a self-validating probe
|
||||
|
||||
**2026-08-29.** Three earlier "the title never appears" claims came from
|
||||
instruments that were later found broken (a stale pixel oracle, a 41 s sampling
|
||||
interval, a freezing stream). This run used
|
||||
[`tools/re-capture/title_probe_xchecked.py`](../../tools/re-capture/title_probe_xchecked.py),
|
||||
which restarts its stream every 30 s **and cross-checks itself against an
|
||||
independent `import` grab every 60 s**, printing both numbers.
|
||||
|
||||
```
|
||||
1851 frames in 560.2 s = 3.30 fps
|
||||
cross-checks 9, disagreements 1
|
||||
max glyph 0
|
||||
```
|
||||
|
||||
| t | stream | import | |
|
||||
|---|---|---|---|
|
||||
| 62 s | 6.05 | 0.07 | disagree — a fade, the boot logos are mid-transition |
|
||||
| 123 s | 7.40 | 7.49 | agree |
|
||||
| 183 s | 8.18 | 8.29 | agree |
|
||||
| 243 s | 0.23 | 0.10 | agree |
|
||||
| 311 s | 89.68 | 89.51 | agree |
|
||||
| 371 s | 80.97 | 81.58 | agree |
|
||||
| 426 s | 117.43 | 117.72 | agree |
|
||||
| 487 s | 77.71 | 76.25 | agree |
|
||||
| 546 s | 70.43 | 70.55 | agree |
|
||||
|
||||
Eight of nine agree to within 2 %, the fps held at 3.30 (no collapse to 1.60),
|
||||
and the surface plainly moved through dark and bright phases. **The frames were
|
||||
live and the negative is real:**
|
||||
|
||||
> ✅ **Measured — over 560 continuous seconds from launch, sampled 3.3 times a
|
||||
> second by a cross-validated probe, the interactive title's green Ⓐ plate never
|
||||
> appears, while the game renders throughout.**
|
||||
|
||||
The final frame correlates **0.0145** with our title render, **−0.0047** with the
|
||||
main menu and **0.0102** with `EXTRAS` — it is attract-movie content, not a UI
|
||||
screen at all.
|
||||
|
||||
## ❔ Why, still unknown
|
||||
|
||||
`live-title-press-a.png` is committed and carries 753 glyph pixels, so the title
|
||||
*was* reachable from this container on 2026-08-28. Nothing found so far explains
|
||||
the change. Clearing the shader cache fixed the *black surface* but not this.
|
||||
|
||||
## Where this leaves the emulator-side questions
|
||||
|
||||
The two open items that need a running menu — the gamma control
|
||||
([tone curve](structures/ui-render-tone-curve.md)) and separating `8AX` from
|
||||
`ptbase` ([8AX](structures/ui-8ax-fullres-background.md)) — remain blocked, now
|
||||
on a well-characterised and instrument-verified failure rather than on a
|
||||
suspicion. Neither blocks the five menu screens. **Returning to static work**;
|
||||
the probe is committed for whoever picks this up.
|
||||
|
||||
50
tools/re-capture/title_probe_xchecked.py
Executable file
50
tools/re-capture/title_probe_xchecked.py
Executable file
@@ -0,0 +1,50 @@
|
||||
"""Fixed probe + a live cross-check against an independent grabber.
|
||||
|
||||
Stream is restarted every 30 s (a single long-lived one freezes). Every 60 s an
|
||||
`import` grab of the same display is taken and compared: if the two disagree by
|
||||
more than a few percent, the stream is lying and the run's numbers are void.
|
||||
"""
|
||||
import subprocess, sys, time, os
|
||||
import numpy as np
|
||||
from PIL import Image
|
||||
W,H,SURF = 1280,720,45
|
||||
LIMIT = float(sys.argv[1]) if len(sys.argv)>1 else 540
|
||||
RESTART = 30
|
||||
def _open():
|
||||
return subprocess.Popen(["ffmpeg","-loglevel","error","-f","x11grab","-draw_mouse","0",
|
||||
"-video_size",f"{W}x{H}","-i",":98","-r","4","-f","rawvideo","-pix_fmt","rgb24","-"],
|
||||
stdout=subprocess.PIPE, bufsize=W*H*3*2)
|
||||
def independent():
|
||||
subprocess.run(["/usr/local/bin/screenshot","/tmp/xcheck.png"],capture_output=True)
|
||||
try: return float(np.asarray(Image.open("/tmp/xcheck.png").convert("RGB")).astype(int)[SURF:].mean())
|
||||
except Exception: return -1.0
|
||||
p=_open(); n=W*H*3
|
||||
t0=time.time(); seg=t0; lastx=t0; lastr=-1
|
||||
frames=0; best=0; disagree=0; checks=0
|
||||
while time.time()-t0 < LIMIT:
|
||||
if time.time()-seg > RESTART:
|
||||
p.kill(); p=_open(); seg=time.time()
|
||||
buf=p.stdout.read(n)
|
||||
if len(buf)<n:
|
||||
p.kill(); p=_open(); seg=time.time(); continue
|
||||
a=np.frombuffer(buf,np.uint8).reshape(H,W,3).astype(int)
|
||||
frames+=1
|
||||
sm=float(a[SURF:].mean())
|
||||
r,g,b=a[:,:,0],a[:,:,1],a[:,:,2]
|
||||
c=int(((g>130)&(g-r>45)&(g-b>45)).sum())
|
||||
if c>best:
|
||||
best=c
|
||||
if c>=400:
|
||||
Image.fromarray(a[SURF:].astype(np.uint8)).save("/sylph-home/re/shots/probe3-title.png")
|
||||
print(f"*** TITLE t={time.time()-t0:.1f}s glyph={c}",flush=True)
|
||||
if time.time()-lastx > 60:
|
||||
lastx=time.time(); checks+=1
|
||||
iv=independent()
|
||||
bad = iv>=0 and abs(iv-sm) > max(3.0, 0.15*max(iv,sm))
|
||||
if bad: disagree+=1
|
||||
print(f" t={int(time.time()-t0):4d}s stream {sm:7.2f} | import {iv:7.2f} "
|
||||
f"{'<-- DISAGREE' if bad else 'agree'} glyph {c}",flush=True)
|
||||
p.kill(); dt=time.time()-t0
|
||||
print(f"{frames} frames in {dt:.1f}s = {frames/dt:.2f} fps")
|
||||
print(f"cross-checks {checks}, disagreements {disagree}")
|
||||
print(f"max glyph {best}")
|
||||
Reference in New Issue
Block a user