Files
Sylpheed/tools/port/verify-dwell
Sylpheed port agent 07da4f167f port: hold at 60 against a better 120, audit the switch, and name its falsifier first
The Decoder measures 120 units/s with a content-hash experiment carrying the
controls the withdrawn version lacked -- a static texture hashing constant (1
change in 403 samples) and movie luma not constant (102 distinct) -- against
pre-registered bands the observed 0.5739 falls inside. It is a better experiment
than either it replaces.

THE PORT HAS NOT MOVED. It is their third position on this number in one day,
reach is one boot, and they said themselves that a second independent boot before
a timeline is rewritten is the defensible call. Agreed.

⚠️ And 60 is not defended either -- its bracket was withdrawn this morning. Both
numbers are undefended. The port keeps the one it ships because switching on a
single capture is a worse failure than holding on none. That is the whole
reasoning and it is not evidence about the game.

 THE AUDIT THEY ASKED FOR COMES OUT CLEAN. "If seconds are baked in anywhere,
they all move." No seconds are baked into the timeline: every second this port
prints or acts on is computed as units / keyframe_units_per_second at the point of
use -- settle_time, exit_time, _overlay_quit_at, the boot log. audio.json's
loop_start_s / loop_end_s ARE seconds and correctly do NOT follow the constant;
they are positions in an audio file with no keyframe unit in them. So the switch
is one number in one file.

🔴 ONE EXCEPTION, AND IT WAS HIDING BEHIND A COMMENT ABOUT NOT DRIFTING.
tools/port/verify-dwell read black_hold_units from the authored file "so it cannot
drift again" -- and then divided by a literal 60.0. The value could not drift; the
conversion could, and would have gone silently wrong the moment the constant moved,
which is under active dispute right now. Harmless only because the hold is 0.
Fixed to read the rate from the same file it already opens.

That is the third time in this corpus a `why` has described a property the code
did not have, and the first where the comment and the defect were one line apart.

📌 AND THE FALSIFIER IS PRE-REGISTERED, BEFORE ANY SECOND BOOT, in
docs/port/units-per-second-switch-readiness.md. At 120 every declared interval
halves: the plate lands at 1.967 s, the publisher splash runs 2.125 s and the
developer 1.750 s. Three cold boots measured those splashes at 4.30/4.60/4.37 and
3.51/3.50/3.37.

So 120 and the dwell corpus cannot both be right in wall-clock seconds -- the same
collision that killed the 35 units/s proposal from the other direction, arriving
from the opposite side. Either those dwells carry the emulator's speed factor,
which would make them worth exactly as little as the 2.13 s route the Decoder has
already declined to lean on, or 120 is wrong. Naming that now is the point of
writing it before the boot rather than after.

What would move this port: a second independent boot agreeing, AND a statement on
whether the cold-boot dwell corpus survives the same speed-factor objection that
the 2.13 s route does not. The first without the second leaves a 2x contradiction
standing between two numbers the port would then hold at once.

Not settled: the constant; the clock origin, which every ratio and count above
survives untouched; the ~1.0-1.2 menu residual; the allowance's grep trigger.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_018AHUQvXGyNcKonSEWsgWcX
2026-09-01 19:26:36 +00:00

144 lines
6.9 KiB
Bash
Executable File

#!/usr/bin/env bash
# Check the port's boot pacing against captures of the real game.
#
# tools/port/verify-dwell
#
# WHY THIS IS A TOOL AND NOT A ONE-OFF. Doing it by hand once already refuted a
# 🔴 I had filed myself: `docs/port/BLOCKED.md` said `rest.t` was the wrong settle
# landmark AND that "everything the sequencer paces off it is therefore late".
# The first half is true; the second was wrong, and I nearly re-paced screens
# that already matched the game to 0.05 s.
#
# ⚠️ A PORT'S TRANSITION INTERVAL IS NOT THE ORACLE'S VISIBLE SPAN. They differ
# by the black hold between screens, and confusing the two cost this corpus 0.6 s
# once and 0.48 s on the plate delay. So the comparison here is explicit: the
# port's interval is checked against the oracle's span PLUS the measured hold.
#
# 🔴 AND THE VERDICT DOES NOT COME FROM THE FILMSTRIP ANY MORE. It used to
# measure ink spans from `--film` frames. The boot's black hold is 0.17-0.23 s
# (HANDOFF Q7) -- shorter than the 0.25 s cadence meant to observe it -- so when
# the black frame fell between samples two screens merged into one span and this
# tool reported `developer logos` as 93 s against an oracle of 3.5 s. Filming at
# 0.1 s made it WORSE: 2.5x the screenshots slows the run enough that the capture
# catches up in bursts, and the publisher span came back as 7.80 s.
#
# The sequencer already knows exactly when it changed screens and prints it.
# Sampling a picture to rediscover a number the program can state is how this
# went wrong. The filmstrip is kept, and marked advisory.
#
# THE EXPECTED NUMBERS ARE THE ORACLE'S, NOT THE PORT'S: three cold boots from
# `docs/re/boot-order-and-splash-dwell.md`, quoted as a test fixture. Nothing in
# the port derives them and nothing may.
set -euo pipefail
cd "${PROJECT_DIR:-/work}"
export DISPLAY="${DISPLAY:-:97}"
OUT="${OUT:-$(mktemp -d)}"
mkdir -p "$OUT"
INTERVAL="${INTERVAL:-0.25}"
echo "running the boot (the intro is skipped -- the splashes are what this measures)"
timeout "${TIMEOUT:-300}" godot --path port --resolution 1280x720 -- \
--boot --skip-at=1 "--film-interval=$INTERVAL" "--film=$OUT/f" \
>"$OUT/boot.log" 2>&1 || true
INTERVAL="$INTERVAL" python3 - "$OUT" <<'PYEOF'
import glob, os, re, subprocess, sys
out = sys.argv[1]
INTERVAL = float(os.environ.get("INTERVAL", "0.25"))
# The boot's black gap, measured in the DRAW STREAM (4 presented frames at
# 2.284 units/frame = 9.1 units), not from luminance -- luminance cannot separate
#
# ⚠️ 2.284 IS NOT A GENERAL RATE AND THIS LINE USED TO READ AS IF IT WERE.
# It is the disc used as its own clock ON ONE CAPTURE, which ran at 13.1 fps
# against ~28 elsewhere: `palogo_sqex` declares alpha >= 1 for 239.8 units and
# was drawn in 105 frames of that run. Correct for converting THAT run's frame
# count; not a constant, and not HANDOFF Q1's 2 units per rendered frame, which
# is a different quantity measured at normal speed. See DECISIONS.md.
# the outgoing fade's tail from true black. The +/-1 frame range is 6.9-11.4
# units = 0.114-0.190 s. HANDOFF Q7's luminance figure of 0.17-0.23 s overlaps
# only at the top, and the draw-stream number is the one to use.
HOLD_LO, HOLD_HI = 0.114, 0.190
# 🔴 THAT IS THE GAME'S GAP. THE PORT'S IS AUTHORED AND IS CURRENTLY 0.
#
# This tool built its target as `oracle span + the GAME's black gap` and compared
# the port against it -- correct only while the port inserted that gap. It does
# not: `black_hold_units` went to 0 (four measured gaps, 0/6/4/6 units, no rule;
# see authored/timing.json). So the port is expected to run SHORT by the gap, and
# on `publisher_logo` it does -- 0.131 s below the unslacked target, which the
# 0.15 s wall-clock slack was quietly absorbing into an "agrees".
#
# Read from the authored file so it cannot drift again, and REPORT the shortfall
# rather than hide it. A verdict that passes because the slack happens to exceed
# a known omission is not a verdict.
#
# 🔴 AND THE RATE WAS HARDCODED WHILE THE VALUE WAS NOT. This line read
# `black_hold_units` from the file -- so it "cannot drift again" -- and then
# divided by a literal 60.0. The value could not drift; the conversion could,
# and would have gone silently wrong the moment `keyframe_units_per_second`
# moved. It is under active dispute right now (60 vs 120), so this is a live
# hazard rather than a tidy-up. Harmless only because the hold is currently 0.
import json as _json
_timing = _json.load(open("authored/timing.json"))
_UPS = float(_timing.get("keyframe_units_per_second", 60))
PORT_HOLD = float(_timing.get("black_hold_units", 0)) / _UPS
marks = []
for line in open(os.path.join(out, "boot.log"), errors="replace"):
m = re.match(r"\s+-> (\S+) at ([0-9.]+) s", line)
if m:
marks.append((m.group(1), float(m.group(2))))
if not marks:
print("no transitions in the boot log -- see", os.path.join(out, "boot.log"))
raise SystemExit(2)
ORACLE = [
("publisher wordmark", [4.297, 4.604, 4.370]),
("developer logos", [3.508, 3.503, 3.366]),
]
starts = [0.0] + [t for _, t in marks]
print()
print("%-20s %-14s %-26s %s" % ("screen", "port interval", "oracle span (3 boots)", "verdict"))
bad = 0
for k, (name, runs) in enumerate(ORACLE):
if k + 1 >= len(starts):
print("%-20s %-14s %s" % (name, "-", "no such transition this run")); continue
d = starts[k + 1] - starts[k]
lo, hi = min(runs) + PORT_HOLD, max(runs) + PORT_HOLD
game_lo, game_hi = min(runs) + HOLD_LO, max(runs) + HOLD_HI
ok = lo - 0.15 <= d <= hi + 0.15
bad += 0 if ok else 1
print("%-20s %-14s %-26s %s"
% (name, "%.2f s" % d, "%.3f / %.3f / %.3f" % tuple(runs),
"agrees" if ok else "DIFFERS"))
print()
print(" Target = oracle SPAN + the PORT's authored hold (%.3f s); the GAME's" % PORT_HOLD)
print(" measured gap is %.3f-%.3f s, so a port with hold 0 runs short by that." % (HOLD_LO, HOLD_HI))
print(" 0.15 s of slack for wall-clock jitter -- which is LARGER than the gap,")
print(" so a shortfall of that size passes unless it is reported separately:")
print(" transitions:", ", ".join("%s@%.2f" % m for m in marks[:4]))
frames = sorted(glob.glob(os.path.join(out, "f_*.png")))[:120]
if frames:
means = [float(subprocess.run(["convert", f, "-colorspace", "Gray", "-format",
"%[fx:mean*255]", "info:"], capture_output=True, text=True).stdout or 0)
for f in frames]
ink = [m > 0.0 for m in means]
spans, i = [], 0
while i < len(ink):
if ink[i]:
j = i
while j < len(ink) and ink[j]: j += 1
spans.append((i * INTERVAL, j * INTERVAL)); i = j
else:
i += 1
print()
print(" advisory -- filmstrip ink spans at %.2f s, which CANNOT resolve a" % INTERVAL)
print(" %.2f-%.2f s hold and merges screens whenever it misses one:" % (HOLD_LO, HOLD_HI))
for a, b in spans[:4]:
print(" %6.2f - %6.2f s (%.2f s)" % (a, b, b - a))
raise SystemExit(1 if bad else 0)
PYEOF
rc=$?
echo "artifacts in $OUT"
exit $rc