Files
Sylpheed/tools/port/contract-check
Sylpheed port agent 7ebf5fc8c5 port: assert the scan boundary I had hand-verified, and give audit-kinds a self-test
check-claims --control plants a revival in docs/port/ and requires exit 1. That
the plant lands INSIDE a scanned directory was a property I checked manually, one
time, and wrote up -- the exact pattern I had criticised in this same tool one
iteration earlier. A fifth case now plants the identical text OUTSIDE the scanned
root and requires 0, so the pair asserts the boundary is real: same text, 1 inside
and 0 outside. Either half alone is consistent with the tool scanning everything,
or nothing. Five cases: clean 0, unmarked 1, marked 0, outside-root 0, empty
register 2.

audit-kinds has always reported what it found and was never asked whether it can
find anything, while its clean runs are cited as evidence that fifteen labels are
grounded. --selftest pushes three synthetic rows through the real classifier and
reads its verdict: citing nothing must read BARE, a real path ok, a missing path
DANGLING. Verified two-directionally -- an extractor stubbed to accept everything
returns exit 2. Asserting in check-all.

All four submenus are now measured to reset -- LOAD GAME, TUTORIAL and OPTIONS
joining EXTRAS -- and the main menu remains the only screen that remembers. Three
of the four are not in this export, so no authored value changes.

NOT promoted to a rule, deliberately. 'Submenus reset' at 4/4 is better evidence
than the 2/2 that made wrap a menu-wide rule, and adopting it would change nothing
today because the only submenu this port ships is already measured. What it would
do is pre-decide the next screen from a generalisation instead of a measurement --
the trap that nearly let a derived rule overwrite EXTRAS' measured opening item.
The guard prints the 4/4 finding beside its per-screen values so the evidence is
visible without being load-bearing.

MISSION-SELECT-versus-top-item stays open: none of the three separates it, each
opens on its own first item, and NEW GAME is untested.

Remaining without a harness self-test: verify-transcode-fidelity. Every asserting
check passes, 13 of them.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01N7FiFFFwbvG2uxdcEh8HyF
2026-08-31 01:33:42 +00:00

516 lines
25 KiB
Python
Executable File
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
#!/usr/bin/env python3
"""Reconcile the numbers the CONTRACT states against the numbers the PORT ships.
`docs/port/HANDOFF.md` is the contract, and this port reads it from `main` --
where it is frozen at 926 lines while the live document, on the Decoder's branch,
is 4 111. Two days of deliveries addressed to the port landed on a page the port
does not open. Reading 70 unread sections by hand is how that gets missed again.
So the values are checked instead of read. Each check names a quantity, pulls it
OUT OF THE LIVE HANDOFF TEXT by pattern -- never restating it here, or this file
would be a third copy to go stale -- and compares it against the port's own
`export/` tree or `authored/` mapping.
Three outcomes, and the third is the point:
ok the contract and the port agree
MISMATCH they disagree; one of us is wrong and this says which values
ANCHOR the pattern no longer matches the contract -- the check has STOPPED
CHECKING. Reported as loudly as a mismatch, because a check whose
anchor has drifted passes forever while measuring nothing.
Reads the newest HANDOFF on ANY ref, not the working tree's, and says which.
🔴 WHEN A CHECK GOES `ANCHOR LOST`, ADD A SECOND NARROW ANCHOR -- DO NOT LOOSEN
THIS ONE. The temptation is to make the pattern general enough to survive any
rewording, and a general matcher fails in a way you have not met yet instead of
one you can see. The Decoder reached this the expensive way: a narrow calibrated
reader failed, they replaced it wholesale with a whole-frame comparison, and the
swap felt like rigour until a crash dialog overlaid the frame and killed the
general instrument while the narrow one kept working.
"""
import json, re, subprocess, sys, os
FAIL = 0
def git(*a):
return subprocess.run(["git", *a], capture_output=True, text=True).stdout
def contract():
"""The newest HANDOFF anywhere, and how far the working tree's copy is behind."""
sha = git("log", "--all", "--format=%h", "--", "docs/port/HANDOFF.md").split()[0]
mine = git("log", "-1", "--format=%h", "--", "docs/port/HANDOFF.md").strip()
text = git("show", f"{sha}:docs/port/HANDOFF.md")
behind = len(git("log", "--all", "--not", "HEAD", "--format=%h",
"--", "docs/port/HANDOFF.md").split())
print(f" contract: {sha} ({len(text.splitlines())} lines)")
print(f" my copy : {mine} ({len(git('show', f'{mine}:docs/port/HANDOFF.md').splitlines())} lines)"
f"{'' if behind == 0 else f' <- {behind} HANDOFF commit(s) unread'}")
return text
def report(name, want, got, ok):
global FAIL
if want is None:
FAIL += 1
print(f" {name:<30} 🔴 ANCHOR LOST -- the contract no longer states this")
elif ok:
print(f" {name:<30} ok contract {want} port {got}")
else:
FAIL += 1
print(f" {name:<30} 🔴 MISMATCH contract {want} port {got}")
def jload(p):
return json.load(open(p)) if os.path.exists(p) else None
def el(screen, prefix):
d = jload(f"export/screens/title/{screen}.json")
if not d:
return None
return next((e for e in d["elements"] if e["id"].startswith(prefix)), None)
# --- the checks ------------------------------------------------------------
def check_fade_quads(h):
"""The fade-in that a broken helper reported 5x too slow for years.
The contract prints the three builds' `pteff00` poses in one fence. The port
animates that quad from its OWN export, so agreement here is two readers of
the same bytes -- theirs rebuilt after the record-layout fix, mine the pinned
crate -- and a disagreement would mean one reader never got the fix.
"""
for screen, build in (("title", 4), ("main_menu", 5), ("extras", 6)):
m = re.search(rf"build {build} \([^)]*\)\s+pteff00\.prm\s+(.+)", h)
want = None
if m:
want = [(int(t), int(a)) for t, a in re.findall(r"t=\s*(\d+)\s*α=(\d+)", m.group(1))]
e = el(screen, "pteff00")
got = [(k["t"], int(k["fade_argb"][2:4], 16)) for k in e["keyframes"]] if e else None
report(f"fade quad, {screen}", want, got, want is not None and want == got)
def check_plate_period(h):
"""`+0x08` is the loop length: 120, and the port must not run the glow at 105."""
m = re.search(r"the plate's pulse period is (\d+), not (\d+)", h)
want = int(m.group(1)) if m else None
e = el("press_start", "ptbtn00")
got = (e.get("focus") or {}).get("loop_length_units") if e else None
report("plate glow cycle", want, got, want is not None and want == got)
a = jload("authored/timing.json") or {}
auth = a.get("looping_focus_records", {}).get("press_start/ptbtn00", {}).get("period_units")
report(" ... authored 2nd witness", want, auth, want is not None and want == auth)
def check_bgm_window(h):
"""The menu loop, as an ffmpeg window the contract states literally."""
m = re.search(r"the window is \*\*`-ss ([\d.]+) -t ([\d.]+)`\*\*", h)
want = (float(m.group(1)), float(m.group(2))) if m else None
a = ((jload("authored/audio.json") or {}).get("bgm") or {}).get("main_menu", {})
got = (a.get("loop_start_s"), a.get("loop_end_s"))
report("menu BGM loop window", want, got, want is not None and want == got)
def check_black_hold(h):
"""The gap between screens is not a load: the contract says keep it at 0."""
m = re.search(r"Keep `black_hold_units` at (\d+)", h)
want = int(m.group(1)) if m else None
got = (jload("authored/timing.json") or {}).get("black_hold_units")
report("black hold between screens", want, got, want is not None and want == got)
def check_menu_bank(h):
"""Which bank the menu plays -- the row the port once got wrong by authoring."""
m = re.search(r"`(BGM_\d+)` confirmed from the RUNTIME", h)
want = m.group(1) if m else None
got = (((jload("authored/audio.json") or {}).get("bgm") or {})
.get("main_menu", {}).get("bank", ""))
report("menu BGM bank", want, got, want is not None and got.startswith(want))
def check_fade_out(h):
"""The fade-OUT lengths, derived from the same poses the fade-in check reads.
Stated as prose rather than in the fence, so this parses the sentence. Split
from the fade-in deliberately: they came from the same broken helper, and a
single check covering both would let one wrong half hide behind a right one.
"""
m = re.search(r"Fade-out = (\d+) units, (\d+) units, and \*\*(\d+)\*\* on the title", h)
want = [int(m.group(i)) for i in (1, 2, 3)] if m else None
got = []
for screen in ("main_menu", "extras", "title"):
e = el(screen, "pteff00")
ks = [k["t"] for k in e["keyframes"]] if e else []
got.append(ks[-1] - ks[-2] if len(ks) >= 2 else None)
report("fade-out ramps", want, got, want is not None and want == got)
def check_splash_dwell(h):
"""The two boot splashes' dwell -- the retraction the port's recomputation caused.
The contract gives 190 and 145 as the widest gap in each entry's own times.
The port plays the declared timeline, so the same gap must come out of the
export. This is the retracted claim re-derived from a third reading.
"""
m = re.search(r"the splashes are (\d+) and (\d+)", h)
want = [int(m.group(1)), int(m.group(2))] if m else None
got = []
for screen in ("publisher_logo", "developer_logos"):
d = jload(f"export/screens/title/{screen}.json")
ts = sorted({k["t"] for e in d["elements"] for k in e["keyframes"]}) if d else []
got.append(max((b - a for a, b in zip(ts, ts[1:])), default=None))
report("boot splash dwells", want, got, want is not None and want == got)
def check_splash_times(h):
"""The splash's ABSOLUTE keyframe times, not just the gap between two of them.
🔴 Added 2026-08-30 because the dwell check above is a DIFFERENCE, and a
difference is blind to the origin: a reader whose times were all shifted by a
constant would produce the same 190 and pass. That is not hypothetical -- the
Decoder's own control asserted "two DOWNs move two items", which a constant
offset preserves exactly, and it passed for a whole session on a reader that
was two items wrong. Ground truth caught it; the control could not.
The contract prints entry 10's times in full, so the origin is checkable.
"""
m = re.search(r"entry 10's times are\s*`\[([0-9, ]+)\]`", h)
want = [int(x) for x in m.group(1).split(",")] if m else None
d = jload("export/screens/title/publisher_logo.json")
got = sorted({k["t"] for e in d["elements"] for k in e["keyframes"]}) if d else None
report("splash absolute times", want, got, want is not None and want == got)
def check_initial_focus(h):
"""What the menu opens on FROM A FRESH BOOT -- measured, and it was authored.
Anchored on the measurement rather than on the value, so that if the reading
is corrected again this fails instead of silently agreeing.
"""
want = "NEW GAME" if re.search(
r"\*\*Initial focus on a fresh boot is `NEW GAME`\*\*", h) else None
scr = ((jload("authored/flow.json") or {}).get("screens") or {}).get("main_menu", {})
bid = scr.get("initial_focus")
got = (scr.get("buttons") or {}).get(bid, {}).get("label")
kind = scr.get("initial_focus_kind")
report("menu opens on (fresh boot)", want, f"{got} [{kind}]",
want is not None and got == want and kind == "measured")
def fn_nav_perturbed(fn, old, new):
"""Run a walk-anchored check against a perturbed copy of the walk.
`nav()` reads from git, so the perturbation is injected by swapping the
function out rather than by editing a file -- nothing on disk is touched.
"""
global nav
real = nav
nav = lambda: (real()[0].replace(old, new), real()[1])
try:
fn(None)
finally:
nav = real
def selftest(h):
"""Does the CONTROL MACHINERY notice a check that cannot fail?
🔴 THE GAP THIS CLOSES, named by me and prioritised by the Decoder: every
`--control` run asserts that each check FAILS on a perturbed contract. None
of them asserted that a **broken control reports broken**. That is the same
shape as printing a verdict without asserting it, one level up — and a
control harness that silently approves a dead check is exactly as useless as
a check that silently approves a dead value.
So a stub check that can never fail is fed to the machinery, and the
machinery must flag it. If the stub comes back "✅ fails as it must", the
harness is broken and says so with its own exit code.
Exit codes follow the Decoder's convention, which distinguishes the two
failures that matter: **0** all good, **1** a real check failed, **2** the
HARNESS is broken and nothing it reported can be trusted.
"""
import io, contextlib
def always_ok(_h):
# Prints a verdict and asserts nothing -- the exact defect shipped in
# `verify-transcode-fidelity`'s unconditional `return 0`.
print(" stub: everything is fine")
# 🔴 RUN THE REAL MACHINERY OVER THE STUB. A first version of this checked
# that the stub left FAIL at zero and then ARGUED that `control` would
# therefore flag it. That is reasoning where a measurement was available --
# the error this whole thread has been about -- so the stub goes through the
# same `control()` loop the real checks do, and its verdict is read.
with contextlib.redirect_stdout(io.StringIO()) as buf:
verdict = control(h, extra=[(always_ok, "120", "121")])
out = buf.getvalue()
stub_line = [l for l in out.splitlines() if "always_ok" in l]
if verdict is not False or not stub_line:
print(" 🔴 HARNESS BROKEN: the control machinery did not flag a check that")
print(" cannot fail. Nothing any `--control` run has reported is trustworthy.")
print(f" stub verdict: {verdict!r}; line: {stub_line}")
return 2
if "PASSES A WRONG CONTRACT" not in stub_line[0]:
print(f" 🔴 HARNESS BROKEN: stub flagged, but not as a dead check: {stub_line[0].strip()}")
return 2
print(" harness self-test: a check that cannot fail is flagged by the machinery ✅")
print(f" {stub_line[0].strip()}")
print(" Exit codes: 0 all good, 1 a real check failed, 2 the HARNESS is broken.")
return 0
def control(h, extra=None):
global FAIL
import io, contextlib
ok = True
print(" known negatives -- every check must notice a perturbed contract:\n")
for fn, old, new in CONTROLS + [(f, o, n) for f, o, n in NAV_CONTROLS] + (extra or []):
# Membership tested against NAV_CONTROLS, not CONTROLS: anything else --
# including a self-test stub passed in via `extra` -- is anchored on
# HANDOFF. Written the other way round, the stub was routed at the walk
# and flagged "the control's own anchor is gone", a real failure for a
# fabricated reason.
src = nav()[0] if (fn, old, new) in NAV_CONTROLS else h
if old not in src:
print(f" {fn.__name__:<22} 🔴 the control's own anchor is gone")
ok = False
continue
before, FAIL = FAIL, 0
with contextlib.redirect_stdout(io.StringIO()):
if src is h:
# 🔴 EVERY occurrence, not the first. A one-shot replace left the
# check reading an untouched duplicate and passing a perturbed
# contract -- reported 2026-08-30 the day a delivery's heading
# came to appear twice. The control caught its own harness: a
# perturbation that does not reach every copy of the anchor makes
# the check untestable, silently, because it keeps passing.
fn(h.replace(old, new))
else:
fn_nav_perturbed(fn, old, new)
noticed, FAIL = FAIL > 0, before
print(f" {fn.__name__:<22} {'✅ fails as it must' if noticed else '🔴 PASSES A WRONG CONTRACT -- it checks nothing'}")
ok = ok and noticed
return ok
def nav():
"""The player's-eye walk, from the newest ref that carries it.
A second unreachable document: `docs/game/navigation.md` was filled in from
the committed oracle frames and, like HANDOFF, is not on `main`. The port's
`authored/flow.json` is the executable form of that walk, so the two must not
drift -- and the drift would be invisible, because nothing in the port fails
when a label is wrong.
"""
sha = git("log", "--all", "--format=%h", "--", "docs/game/navigation.md").split()[0]
return git("show", f"{sha}:docs/game/navigation.md"), sha
def flow_buttons(screen):
d = jload("authored/flow.json") or {}
b = ((d.get("screens") or {}).get(screen) or {}).get("buttons") or {}
return [v.get("label") for _, v in sorted(b.items())]
def check_focus_persists(h):
"""The menu remembers its cursor -- MEASURED, on the main menu, one screen.
🔴 This checked a PAIR until 2026-08-30: on for `main_menu`, off everywhere
else. The second half asserted that `extras` does NOT persist, and **nothing
measured that**. What the corpus has is EXTRAS' initial focus from a single
entry and Ⓑ restoring the PARENT's focus 4/4 — neither says what a submenu's
own cursor does on re-entry. So one measured behaviour and one absence of a
measurement were being reported identically, and if the game does persist
EXTRAS the check would have held the port to the wrong behaviour AND PASSED.
The mirror of the trap it was written to avoid: refusing to let a derived
rule overwrite a measured value, then letting "not measured here" become a
positive assertion of the negative. Now only the measured half is asserted
against the contract; the scope is a guard, below.
"""
heading = bool(re.search(r"the main menu remembers its cursor; re-entry is not a reset", h))
# 🔴 SECOND NARROW ANCHOR, added 2026-08-30 on the Decoder's advice, and it
# repairs a weakness I had already identified and not acted on. The heading
# anchor is on the CONCLUSION; when they corrected the run's item names --
# `TUTORIAL → EXTRAS → EXTRAS` was actually `NEW GAME → TUTORIAL → TUTORIAL`
# -- this check sailed past it, because the conclusion was above the part
# that was wrong. It survived by luck, not by design.
#
# So the check now also rests on the EVIDENCE: the ring at y 384.0 before the
# round trip and 385.5 after. That pair is the geometry-free equality the
# conclusion actually stands on, and it is what a future correction to the
# measurement would have to touch.
#
# Two narrow anchors, NOT one loosened one. Their words: after a specific
# instrument fails the general one feels safer, and its failure mode is only
# one you have not met yet.
evidence = bool(re.search(r"ring sits at y 384\.0 before the round trip and 385\.5 after", h))
want = heading and evidence
got = (((jload("authored/flow.json") or {}).get("screens") or {})
.get("main_menu", {}).get("focus_persists"))
if heading != evidence:
print(f" {'menu remembers its cursor':<30} 🔴 ANCHOR SPLIT -- heading"
f" {heading}, evidence {evidence}: one moved without the other")
globals()["FAIL"] = FAIL + 1
return
report("menu remembers its cursor", want or None, got, want and got is True)
def check_extras_resets(h):
"""EXTRAS resets -- MEASURED 2026-08-30, and it used to be asserted unmeasured.
For one iteration the port asserted this with nothing behind it, which the
Decoder flagged; it then measured it and the assertion was right. That does
not make the assertion evidence, so the check is rewritten to rest on the
measurement rather than being left to look vindicated.
"""
want = False if re.search(r"EXTRAS resets, the main menu persists", h) else None
ex = ((jload("authored/flow.json") or {}).get("screens") or {}).get("extras", {})
got = ex.get("focus_persists")
report("extras resets its cursor", want, f"{got} [{ex.get('focus_persists_kind')}]",
want is not None and got is False and ex.get("focus_persists_kind") == "measured")
def guard_focus_scope(_h):
"""NOT a contract check. A guard over the screens NOBODY HAS LOOKED AT.
Two screens are now measured and disagree -- `main_menu` persists, `extras`
resets -- so there is no menu-wide rule to state. What this guards is the
rest: `OPTIONS`, `LOAD GAME` and `TUTORIAL` are untouched, and their absent
`focus_persists` is the port defaulting, not a finding.
📌 The absent key and a measured `false` behave identically and mean opposite
things. That is why `extras` now spends a key on saying `false` out loud.
"""
global FAIL
scr = ((jload("authored/flow.json") or {}).get("screens") or {})
stated = {n: v.get("focus_persists") for n, v in scr.items()
if isinstance(v, dict) and "focus_persists" in v}
silent = sorted(n for n, v in scr.items()
if isinstance(v, dict) and "focus_persists" not in v)
ok = stated == {"main_menu": True, "extras": False}
if ok:
# ✅ 2026-08-31: all FOUR submenus are now measured to reset -- EXTRAS,
# LOAD GAME, TUTORIAL and OPTIONS -- and the main menu remains the only
# screen that remembers. Three of those four are not in this export, so
# no authored value changes.
#
# 🔴 NOT PROMOTED TO A RULE, deliberately. "Submenus reset" at 4/4 is
# better evidence than the 2/2 that made `wrap` a rule -- and adopting it
# would change nothing today, because the only submenu this port ships is
# already measured. What it WOULD do is pre-decide the next screen from a
# generalisation instead of a measurement, which is the trap that nearly
# let a derived rule overwrite EXTRAS' measured opening item.
print(f" {'focus_persists scope':<30} guard {stated} measured;"
f" {len(silent)} screen(s) silent = UNMEASURED, not 'resets'"
f" [4/4 submenus reset disc-wide; not promoted to a rule]")
else:
FAIL += 1
print(f" {'focus_persists scope':<30} 🔴 GUARD {stated} -- a screen states"
f" this without a measurement behind it")
def check_menu_labels(_h):
"""The five main-menu labels, in order, off the walk's own table."""
n, sha = nav()
rows = re.findall(r"^\| [1-5] \| \*\*([A-Z ]+)\*\* \|", n, re.M)
want = rows or None
report(f"main menu labels ({sha})", want, flow_buttons("main_menu"),
want is not None and want == flow_buttons("main_menu"))
def check_extras_labels(_h):
"""EXTRAS' three items, written as prose rather than a table."""
n, _ = nav()
m = re.search(r"Three items: `([A-Z ]+)` · `([A-Z ]+)` · `([A-Z ]+)`", n)
want = [m.group(i) for i in (1, 2, 3)] if m else None
report("extras labels", want, flow_buttons("extras"),
want is not None and want == flow_buttons("extras"))
def check_wrap(_h):
"""The cursor wraps, and it is a MENU rule -- the walk says so in two places."""
n, _ = nav()
want = True if re.search(r"one item, and it \*\*wraps\*\* at both ends", n) else None
got = ((jload("authored/flow.json") or {}).get("navigation") or {}).get("wrap")
report("cursor wraps", want, got, want is not None and want == got)
# Each check paired with a one-token edit to the CONTRACT that must break it.
# A check that has never been observed to fail is not evidence -- it may be
# reading nothing, comparing a value to itself, or anchored on a pattern that
# matches anything. `--control` perturbs the contract and requires every check to
# notice. This is the same discipline the checks themselves enforce: an
# instrument goes through a known negative before its clean run is believed.
CONTROLS = [
(check_fade_quads, "pteff00.prm t= 0 α=255 t= 12", "pteff00.prm t= 0 α=255 t= 13"),
(check_fade_out, "Fade-out = 10 units, 10 units", "Fade-out = 11 units, 10 units"),
(check_plate_period, "pulse period is 120, not 105", "pulse period is 121, not 105"),
(check_bgm_window, "`-ss 9.44 -t 61.87`", "`-ss 9.45 -t 61.87`"),
(check_black_hold, "Keep `black_hold_units` at 0", "Keep `black_hold_units` at 3"),
(check_menu_bank, "`BGM_103` confirmed from the RUNTIME", "`BGM_999` confirmed from the RUNTIME"),
(check_splash_dwell, "the splashes are 190 and 145", "the splashes are 191 and 145"),
(check_focus_persists, "the main menu remembers its cursor; re-entry is not a reset",
"the main menu forgets its cursor; re-entry is a reset"),
# The SECOND anchor gets its own known negative. Perturbing only the evidence
# must trip ANCHOR SPLIT -- otherwise the second anchor is decorative and the
# check is still resting on the conclusion alone.
(check_focus_persists, "ring sits at y 384.0 before the round trip and 385.5 after",
"ring sits at y 384.0 before the round trip and 999.9 after"),
# The list sits on the line AFTER "times are", so the perturbation has to
# carry the newline the check's `\s*` spans. A control whose own anchor is
# written from memory of the prose rather than from the prose is the same
# class of error the checks exist to catch.
(check_splash_times, "times are\n`[0,15,30,45,235,239,251,255]`",
"times are\n`[1,16,31,46,236,240,252,256]`"),
(check_extras_resets, "EXTRAS resets, the main menu persists",
"EXTRAS persists, the main menu persists"),
(check_initial_focus, "**Initial focus on a fresh boot is `NEW GAME`**",
"**Initial focus on a fresh boot is `TUTORIAL`**"),
]
# The walk's controls perturb `navigation.md` instead of HANDOFF, so they are
# applied to a different document and kept separate rather than folded in.
NAV_CONTROLS = [
(check_menu_labels, "| 1 | **NEW GAME**", "| 1 | **NEW GAMES**"),
(check_extras_labels, "`MISSION SELECT` · `MOVIE THEATER`", "`MISSION SELECTS` · `MOVIE THEATER`"),
(check_wrap, "one item, and it **wraps** at both ends", "one item, and it stops at both ends"),
]
def main():
if not os.path.exists("export/manifest.json"):
sys.exit("no export/ -- run the exporter first; this check reads what is shipped")
h = contract()
print()
if "--selftest" in sys.argv:
return selftest(h)
if "--control" in sys.argv:
return 0 if control(h) else 1
for fn in (check_fade_quads, check_fade_out, check_plate_period,
check_bgm_window, check_black_hold, check_menu_bank,
check_splash_dwell, check_menu_labels, check_extras_labels,
check_wrap, check_focus_persists, guard_focus_scope,
check_splash_times, check_initial_focus, check_extras_resets):
fn(h)
print()
print(" A passing run means the port agrees with the contract ON THESE VALUES.")
print(" It is not a statement about the 70 sections nobody has reduced to a")
print(" check -- those are still read by hand, or not read at all.")
if FAIL:
print(f"\n🔴 {FAIL} disagreement(s) or lost anchor(s) with the contract")
else:
print("\nthe port agrees with the contract on every value checked")
return 1 if FAIL else 0
sys.exit(main())