re: settle_time measured -- the title is drawn at 2 s, not at rest.t s 4.18

The port s boot sequencer paces every screen off rest.t, which is the last hold
keyframe rather than when a screen arrives. Measured on one cold boot: the
container had no Xenia storage root at all, so this is a fresh profile with no
shader cache, the slowest case.

  title build-in (first ink -> art fully drawn)   0.23 s
  title settled -> PRESS A plate on              2.247 s   (disc declares 120 units)
  plate pulse period                            ~2.37 s
  main menu build-in                             0.531 s
  B -> title                                     0.482 s
  A -> menu                                      3.763 s   DO NOT AUTHOR, see below

The title s rest.t is 251 units = 4.183 s and its art is finished at about 2 s,
so a sequencer pacing off rest.t holds it roughly twice as long as the game does.

Instrument controlled before the run: 9/9 on the content classifier including
the movie-frame and difficulty-screen negatives, 4/4 on the plate detector; the
run sampled 7.99 fps against a requested 8 with an independent one-shot grab
cross-checking every 20 s.

Records a refutation attempt of mine that FAILED. The probe s own marks gave a
plate delay of 3.203 s against the corpus s 2.13 s, which on a cold-cache boot
looked like a real effect. It was the instrument: the plate pulse period is an
internal clock for presentation rate and measures 2.369 s here against the
corpus s 2.3, so the run is not slowed, and re-measuring from content gives
2.247 s. The probe s title_static mark fires during the crossfade out of the
attract movie, before the wordmark has drawn -- glyph was still 0 when it fired.

Also a third independent reproduction of the A-path load stall: 13 frames,
1.53 s, surface mean 26.631 against the earlier 14/1.53 and 12/1.39 at 26.626.
This boot had no shader cache, so it is not a warm-cache artefact. Noted that
the earlier pair agreed to six decimals and mine agrees to three.

Reach: one run. The menu build-in and B->title rest on it alone.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01QsEPXWVaEpyfudtR6re1Pd
This commit is contained in:
sylph-decoder
2026-08-29 15:21:49 +00:00
parent 82281df804
commit 4bd4779f8b
4 changed files with 2385 additions and 0 deletions

View File

@@ -0,0 +1,81 @@
#!/usr/bin/env python3
"""Offline: when does each screen ARRIVE, and when does it SETTLE?
`rest.t` is the last hold keyframe, not when a screen stops moving -- the port
paces its boot sequencer off it and is late. This reads the timing probe's TSV
and reports, per screen segment:
arrive first frame the classifier labels that screen
settle first frame after `arrive` where inter-frame motion stays below the
quiet threshold for SETTLE_HOLD consecutive frames
dwell how long the label persists
The quiet threshold is CALIBRATED FROM THE RUN, not assumed: it is a multiple of
the motion floor observed while a label is stable and late in its segment.
"""
import sys
import numpy as np
SETTLE_HOLD = 4 # consecutive quiet frames before calling it settled
def main(path):
rows = []
meta = []
for ln in open(path):
if ln.startswith("#"):
meta.append(ln.rstrip())
continue
f = ln.rstrip("\n").split("\t")
if len(f) < 8:
continue
rows.append((float(f[0]), int(f[1]), float(f[2]), float(f[3]), f[7]))
if not rows:
print("no data rows"); return 2
t = np.array([r[0] for r in rows])
motion = np.array([r[3] for r in rows])
labels = [r[4] for r in rows]
n = len(rows)
fps = n / (t[-1] - t[0]) if t[-1] > t[0] else 0
print(f"{n} frames, {t[-1]-t[0]:.1f} s, {fps:.2f} fps")
for m in meta:
if m.startswith("#summary") or m.startswith("#event"):
print(" " + m)
valid = motion[motion >= 0]
if valid.size == 0:
print("no motion data"); return 2
floor = float(np.percentile(valid, 10))
quiet = max(floor * 3.0, 0.05)
print(f"\nmotion floor (10th pct) {floor:.4f} -> quiet threshold {quiet:.4f}")
# Segment by contiguous label.
segs = []
i = 0
while i < n:
j = i
while j + 1 < n and labels[j + 1] == labels[i]:
j += 1
segs.append((labels[i], i, j))
i = j + 1
print(f"\n{'screen':<14} {'arrive':>8} {'settle':>8} {'build-in':>9} {'leaves':>8} {'dwell':>8} {'frames':>7}")
for lab, a, b in segs:
if b - a < 2:
continue
settle = None
run = 0
for k in range(a, b + 1):
if 0 <= motion[k] < quiet:
run += 1
if run >= SETTLE_HOLD:
settle = t[k - SETTLE_HOLD + 1]
break
else:
run = 0
build = f"{settle - t[a]:9.3f}" if settle is not None else " -"
s = f"{settle:8.3f}" if settle is not None else " -"
print(f"{lab:<14} {t[a]:8.3f} {s} {build} {t[b]:8.3f} {t[b]-t[a]:8.3f} {b-a+1:7d}")
return 0
if __name__ == "__main__":
sys.exit(main(sys.argv[1]))