The Decoder answered H3 in both halves (a482d9a, against a pre-registration
committed before they read the capture) and refuted two things I published an
hour earlier. Both are struck in place, not deleted.
1. units/frame is 2, not the 5 I inferred. Three consecutive gap-free steps of
exactly 23 on ptbtn00's own ramp; 255*2/22 = 23.18. My 4.4-frame prediction
is excluded by more than 2x.
My derivation was sound arithmetic on two unsound premises, both mine to
have used:
- an alpha step is not a clock rate. dA/frame = 255*(units/frame)/T, so
elements with different declared T show different steps at ONE clock.
Splash quads step 34 with T=15; the plate steps 23 with T=22.
- my "onsets" were first submissions, and on splash A both quads are
already at a=85 when first submitted -- biased late, and by a different
amount per element because the bias scales with T.
The three intervals agreed with each other because they SHARED the bias.
Three measurements with a common error are one measurement. That is the
shape I should have checked for and did not.
2. My claim that the t=160 anchor collapses `clock: "shared"` is WITHDRAWN. The
anchor is indeed t=160 -- ptcopyright, calibrating to t~168-176 -- but I
falsified the model using the 2.135 s figure, which is the one number the
same capture puts in dispute. Falsifying a model with the quantity that is
itself under dispute is the error. Against the new capture's own labels the
declared 54 and 76 units reconstruct at 44 and 66 -- short by 13-19 % in the
same direction, with empty labels a named candidate for the residual.
`clock: "shared"` stands, and the port keeps it.
Still open and now the only thing left on H3: units/second = 2 x guest fps, and
whether the guest is 30 Hz or 60 Hz is unestablished. 2x60 = 120 units/s puts
the plate at 1.97 s instead of 3.93 s, which is the size of what the human
reported. The Decoder asked me not to move off 60 on their account yet; I have
not.
Separately -- check-all is RED and stays red. verify-screen newly DIFFERS on six
screens outside its allowed set (main_menu, extras, main_menu_jp, extras_jp,
build_12, build_15). Measured, not diagnosed:
* not this iteration's doing, and excluded structurally rather than by a
passing test: sprites are read as bytes and built with
Image.load_png_from_buffer, so they never enter Godot's import pipeline and
the new `--import` step has no path to the drawn pixels;
* the difference is FULL-FRAME, exactly zero on unblended pixels (18 081 of
them agree to a hundredth of a level at ref 199/204/255) and gamma-shaped on
every blended one. That is a blend-SPACE divergence, not moved content;
* scored against live-main-menu.png the port is 16 % closer than the reference
(RMSE 3152 vs 3770) -- an ordering only, since both sides carry this
script's --pose=rest contamination, which has produced a false finding here
before.
Not widened. This allowance has twice been broadened with a reason that turned
out false, and "I measured it but cannot say which renderer is right" is not a
reason. New ask H4: what colour SPACE is the blend evaluated in -- the Decoder
has the equation from shader ucode, not the space.
Refutation attempts: both of this iteration's hits are against my own page from
last iteration. The Decoder's units/frame law and their anchor measurement both
survived the only check I could make of them -- their steps reproduce this
export's declared T on two screens at one clock.
Not settled: guest fps; which renderer's blend space is right; H1 (key repeat).
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_018AHUQvXGyNcKonSEWsgWcX
210 lines
12 KiB
Bash
Executable File
210 lines
12 KiB
Bash
Executable File
#!/usr/bin/env bash
|
|
# Run every check this port has, and say which ones assert.
|
|
#
|
|
# tools/port/check-all
|
|
#
|
|
# There are fourteen tools under `tools/port/` (eleven when this was written --
|
|
# the count is stated because it dates the sentence) and nothing ran them
|
|
# together, so
|
|
# each had to be remembered individually. That is the ninth instance of this
|
|
# port's recurring shape -- something correct, documented and unexercised -- one
|
|
# level up: the checks themselves were the thing nobody was running.
|
|
#
|
|
# ⚠️ It runs the tools that ASSERT. The exploratory ones -- `screen-strip`,
|
|
# `which-focus`, `strip-padding`, `verify-dwell`, `check-capture`,
|
|
# `verify-video-audio` -- produce artifacts for a person to look at and have no
|
|
# verdict to collect. Listing them here as passes would be inventing six.
|
|
set -euo pipefail
|
|
cd "${PROJECT_DIR:-/work}"
|
|
export DISPLAY="${DISPLAY:-:97}"
|
|
OUT="${OUT:-${TMPDIR:-/tmp}/check-all}"; mkdir -p "$OUT"
|
|
BIN="${CARGO_TARGET_DIR:-/sylph-home/port/target-container}/debug/sylpheed-export"
|
|
fail=0
|
|
|
|
step() { # name, expectation, command...
|
|
local name="$1" expect="$2"; shift 2
|
|
local log="$OUT/${name}.log" rc=0
|
|
"$@" >"$log" 2>&1 || rc=$?
|
|
case "$expect" in
|
|
must-pass)
|
|
[ $rc -eq 0 ] && printf ' %-24s ok\n' "$name" \
|
|
|| { printf ' %-24s 🔴 FAILED (rc=%d) -- %s\n' "$name" "$rc" "$log"; fail=1; }
|
|
;;
|
|
report-only)
|
|
printf ' %-24s ran (no verdict -- see below)\n' "$name"
|
|
;;
|
|
esac
|
|
}
|
|
|
|
# 🔴 GODOT'S SCRIPT CLASS LIST IS A BUILD CACHE, AND IT IS GITIGNORED.
|
|
#
|
|
# `port/.godot/global_script_class_cache.cfg` is what resolves a `class_name`,
|
|
# and `.gitignore` excludes `port/.godot/` -- correctly, it is derived. So a
|
|
# checkout that MERGES a commit adding a new `class_name` keeps a cache that
|
|
# does not list it, and every script referencing the new class fails to parse:
|
|
#
|
|
# SCRIPT ERROR: Parse Error: Identifier "Gamepad" not declared in the current scope.
|
|
# ERROR: Failed to load script "res://scripts/boot.gd" with error "Parse error".
|
|
#
|
|
# The whole project then refuses to load, from `--screen` to `--boot`, and the
|
|
# error names the symbol rather than the cache -- so it reads as a missing file
|
|
# or a bad merge. This is exactly what merging the human's input fix did on
|
|
# 2026-09-01: `gamepad.gd` arrived with `class_name Gamepad`, the cache in this
|
|
# container was warm and predated it, and the port did not run at all.
|
|
#
|
|
# A fresh clone has no `.godot/` and Godot builds one on first run, so nobody
|
|
# hits this until they merge into a working tree -- which is every iteration of
|
|
# this loop. Reimporting is cheap and idempotent, so it runs unconditionally
|
|
# rather than behind a staleness test that would itself need to be right.
|
|
echo "godot: reimporting so class_name resolves against a fresh cache"
|
|
DISPLAY="$DISPLAY" godot --headless --path port --import >"$OUT/godot-import.log" 2>&1 \
|
|
|| { echo " 🔴 godot --import FAILED -- see $OUT/godot-import.log"; fail=1; }
|
|
for c in $(grep -ho '^class_name [A-Za-z_][A-Za-z0-9_]*' port/scripts/*.gd | awk '{print $2}'); do
|
|
grep -q "\"$c\"" port/.godot/global_script_class_cache.cfg 2>/dev/null \
|
|
|| { printf ' %-24s 🔴 class_name %s is not in the class cache\n' class-cache "$c"; fail=1; }
|
|
done
|
|
echo
|
|
|
|
echo "asserting checks:"
|
|
step format-validator must-pass "$BIN" check
|
|
# The contract lives on a branch this checkout does not merge: HANDOFF on `main`
|
|
# is frozen at 926 lines while the live one is 4 111. Reading 70 unread sections
|
|
# by hand is how two days of deliveries went unread. These are the values that
|
|
# have been reduced to a check; the rest are still read by eye, or not at all.
|
|
step contract-values must-pass tools/port/contract-check
|
|
step contract-control must-pass tools/port/contract-check --control
|
|
# 🔴 The control harness itself is asserted. Every --control run says "each check
|
|
# fails on a perturbed contract"; none of them said "a broken control reports
|
|
# broken". A harness that silently approves a dead check is exactly as useless as
|
|
# a check that silently approves a dead value.
|
|
step control-harness must-pass tools/port/contract-check --selftest
|
|
step modding-rules must-pass tools/port/check-modding
|
|
# Every `kind` in authored/ is a claim about where a value came from, and until
|
|
# 2026-08-30 nothing checked what any of them rested on -- seven were resting on
|
|
# a sibling `why` that argued a different claim.
|
|
step authored-kinds must-pass tools/port/audit-kinds
|
|
# The classifier is asked whether it can tell grounded from ungrounded at all,
|
|
# rather than only what it found. Exit 2 = the harness is broken.
|
|
step kinds-harness must-pass tools/port/audit-kinds --selftest
|
|
# Band levels are alignment-free and carry their own known negative on every run;
|
|
# the difference-signal half of the same tool stays report-only and asserts
|
|
# nothing. See docs/port/DECISIONS.md -- the waveform question is still open.
|
|
step transcode-bands must-pass tools/port/verify-transcode-fidelity
|
|
# Asks whether the band measurement is LIVE, not just what it found. An empty
|
|
# band list makes every comparison read 0.0 dB and pass; that now exits 2.
|
|
step bands-harness must-pass tools/port/verify-transcode-fidelity --selftest
|
|
step capture-controls must-pass tools/port/check-capture-controls
|
|
step menu-audio must-pass env OUT="$OUT/audio" tools/port/verify-menu-audio
|
|
# 🔴 ADDED 2026-09-01 after a human found Ⓐ dead on a real controller while the
|
|
# unattended P5 walk passed. `--script` sends `InputEventAction`, which BYPASSES
|
|
# the input map, so every check here asserted the code BELOW the map and nothing
|
|
# about the map -- which was missing a joypad binding for `ui_accept` and
|
|
# `ui_cancel` entirely. The same blind spot hid a second defect: an
|
|
# `InputEventAction` is not an analog axis, so nothing could see that a held
|
|
# stick fired once per jitter.
|
|
step input-map must-pass tools/port/verify-input
|
|
step input-control must-pass tools/port/verify-input --control
|
|
# A stale index is worse than none: it answers "is this already decided?" with a
|
|
# confident no. That is not hypothetical -- see the entry it was built after.
|
|
step decisions-index must-pass tools/port/index-decisions --check
|
|
# A refuted claim asserted outside its correction is a lie the corpus tells a
|
|
# reader who greps for it. Registered claims must carry an explicit `[refuted]`.
|
|
# 🔴 The register check had NO executable control until 2026-08-31 -- every
|
|
# "planted a revival and it failed" in DECISIONS was done by hand, once. Four
|
|
# cases now drive it as a subprocess and read its real exit code, including an
|
|
# EMPTY REGISTER, which used to report clean forever.
|
|
step claims-control must-pass tools/port/check-claims --control
|
|
step refuted-claims must-pass tools/port/check-claims
|
|
echo
|
|
echo "reported, not asserted:"
|
|
# Not an assertion: being behind a peer's topic branch is the normal state, and a
|
|
# red line for it would be scenery within a day. It is here so the affordance is
|
|
# visible on every run -- reading a peer's head needs no merge and no human.
|
|
step peer-heads report-only tools/port/peer-head
|
|
step oracle-captures report-only env OUT="$OUT/oracle" tools/port/verify-capture
|
|
sed -n '/^screen /,$p' "$OUT/oracle-captures.log" | sed 's/^/ /'
|
|
# 🔴 `verify-capture` prints and always exits 0. Its own header is right that the
|
|
# numbers are not a target -- the captures carry the game's tone ramp, so RMSE has
|
|
# a floor and driving it lower is fitting the ramp. But "not a target" is not the
|
|
# same as "not a regression detector", and nothing here would notice `title_plate`
|
|
# moving off 0.00 %. Asserting it needs a stored baseline per row, which is a real
|
|
# design decision about what a baseline means when the pose is fitted. NAMED, not
|
|
# quietly skipped.
|
|
|
|
echo
|
|
echo "consistency (expected to differ, for a stated reason):"
|
|
rc=0; env OUT="$OUT/screens" tools/port/verify-screen >"$OUT/verify-screen.log" 2>&1 || rc=$?
|
|
differs=$(grep -c DIFFERS "$OUT/verify-screen.log" || true)
|
|
unexpected=$(grep DIFFERS "$OUT/verify-screen.log" | awk '{print $1}' \
|
|
| grep -vx -e title -e title_jp || true)
|
|
|
|
# 🔴 THE OLD ALLOWANCE WAS FALSE, AND MY FIRST REPLACEMENT REASON WAS ALSO
|
|
# WRONG. Both are recorded because the second error is the more instructive.
|
|
#
|
|
# It said: "the pin is not on main, so this compares two decoder eras". I
|
|
# replaced that with "the eras render identically -- 0 pixels different on three
|
|
# screens". 🔴 **That measurement was void**: the two binaries I compared had the
|
|
# same md5. I built one in a worktree at the pinned tag and one from the
|
|
# workspace, and both commits carry the record-layout fix, so I compared a
|
|
# binary with itself and reported the zero as evidence.
|
|
#
|
|
# Rebuilt properly against `origin/main`, which is the genuinely stale era
|
|
# (`rest t=70 [12 70 80 -]` against the fixed `rest t=12 [0 12 70 80]`):
|
|
#
|
|
# title 0 px main_menu 0 px title_jp 74 507 px
|
|
#
|
|
# ✅ The eras DO change pixels, and `title_jp` is one of the seven bundles where
|
|
# they do -- reproducing the Decoder's figure exactly, under their flags and
|
|
# mine. My "--animated masks it" hypothesis was wrong too.
|
|
#
|
|
# ✅ BUT THE ERA STILL CANNOT EXPLAIN THIS SCRIPT'S ROWS, for a reason I had not
|
|
# established: BOTH SIDES OF THIS COMPARISON ARE THE FIXED ERA. The exporter is
|
|
# pinned to `formats-pin-2026-08-30` and this reference is built from the
|
|
# workspace, and a binary built from each has the SAME md5. There is no era
|
|
# mismatch here to explain anything. Right answer, wrong evidence, and the wrong
|
|
# evidence was a broken experiment.
|
|
#
|
|
# The real reasons are per-screen and already documented:
|
|
# title -- the ptloop SWEEP PHASE residual, max 6 / over3 790, unchanged
|
|
# across every renderer change since P1 (DECISIONS.md).
|
|
# title_jp -- the `--pose=rest` sparkle handling. Adjudicated against the
|
|
# oracle: the port's SHIPPED pose scores r +0.9994 against the
|
|
# game where the reference scores +0.8727, and `--pose=rest` is
|
|
# what this script compares.
|
|
# ⚠️ title_jp is ALSO an era-sensitive bundle, so if this reference is ever
|
|
# built from a different era than the exporter's pin, that row's cause changes
|
|
# and this note stops applying. Check the md5s before trusting it again.
|
|
#
|
|
# So the allowance is now a NAMED SET, not a count with an excuse. A DIFFERS on
|
|
# any other screen fails the run, which a count never could.
|
|
# 🔴 SIX MORE SCREENS JOINED THIS SET ON 2026-09-01 AND THE SET WAS NOT WIDENED.
|
|
# main_menu, extras, main_menu_jp, extras_jp, build_12, build_15. Measured, not
|
|
# diagnosed: the difference is full-frame, it is EXACTLY ZERO on unblended
|
|
# pixels (18 081 of them agree to a hundredth of a level) and gamma-shaped on
|
|
# every blended one, so it is a blend-SPACE divergence rather than moved content.
|
|
# Scored against the live capture the port is 16 % closer than the reference --
|
|
# an ordering only, since both sides share this script's --pose=rest
|
|
# contamination. Left failing on purpose: this allowance has twice been widened
|
|
# with a reason that turned out false, and "I measured it but cannot say which
|
|
# renderer is right" is not a reason. docs/port/verify-screen-blend-divergence.md
|
|
if [ -n "$unexpected" ]; then
|
|
printf ' %-24s 🔴 DIFFERS on %s -- not in the allowed set\n' verify-screen "$(echo $unexpected | tr '\n' ' ')"
|
|
printf ' %-24s see docs/port/verify-screen-blend-divergence.md -- measured, cause open\n' ""
|
|
fail=1
|
|
else
|
|
printf ' %-24s %d DIFFERS, both named and explained per screen:\n' verify-screen "$differs"
|
|
printf ' %-24s title = sweep phase; title_jp = rest-pose sparkles (the port is\n' ""
|
|
printf ' %-24s closer to the GAME there than the reference is).\n' ""
|
|
fi
|
|
|
|
# Separately, and unrelated to the rows above: revert to the path dependency when
|
|
# the pin lands. Read from Cargo.toml so it cannot drift out of step again.
|
|
pin=$(sed -n 's/.*tag = "\([^"]*\)".*/\1/p' crates/sylpheed-export/Cargo.toml | head -1)
|
|
if [ -n "$pin" ] && git merge-base --is-ancestor "$pin" origin/main 2>/dev/null; then
|
|
printf ' %-24s ⚠️ %s has landed on main -- revert Cargo.toml to the path dep\n' pin "$pin"
|
|
fi
|
|
|
|
echo
|
|
[ $fail -eq 0 ] && echo "every asserting check passes" || echo "🔴 a check failed"
|
|
exit $fail
|