port: check the walk as well as the contract, and a defect I nearly filed off a debug pin
docs/game/navigation.md is a second document unreachable from main, and
authored/flow.json is its executable form -- nothing in the port fails when a
label drifts from it. Three more checks in contract-check, anchored on the walk's
own text: the five main-menu labels in order, EXTRAS' three items, the cursor
wrap. Ten checks now, ten known negatives, all passing.
The manual audit behind them found nothing else: initial focus is already
kind:authored citing Q5's instability, left_right is an explicit no-op,
auto_repeat is measured, unexported destinations are marked blocked with reasons.
Refutation target: the walk's claim that the ring is the ONLY thing moving on the
settled menu. Cannot be tested against the game from here, but can be tested
against my renderer, which is the direction that matters. Five renders across a
full ring cycle: 1428 of 921600 pixels vary, 0.155 %, one 46x44 cluster beside
the focused item. The port animates one ring, not five -- worth checking, since
all five ptbtn01f..05f declare the same 120-unit cycle and a renderer running all
of them would look identical until you diffed frames.
Then I nearly filed a serious P5 defect against myself: sweeping --leaf-time with
the ring pinned moves 10.4 % of the frame, full-screen. It is not a defect. That
pin addresses the build-in -- ptloop01 runs t=0..600, ptloop02 t=0..720 -- and at
settle both park off-screen at x=1521 and x=-839, with loop_leaf_on_screens
scoped to the title alone. The general form: a pin that can address states the
screen never occupies will manufacture defects on demand, which inverts what the
three pins are for.
The +0x08 ask came back answered and is not consumable. ui_layout::loop_length_units
is public at b5df02a and byte-for-byte what screen.rs holds, so the deletion is
one line -- but Cargo.toml pins a tag, no tag carries that commit, and swapping a
deliberate pin for a bare rev on an unmerged branch is not a move to make alone.
Asked for a tag; keeping the guarded local read.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01N7FiFFFwbvG2uxdcEh8HyF
This commit is contained in:
@@ -175,25 +175,99 @@ CONTROLS = [
|
||||
]
|
||||
|
||||
|
||||
|
||||
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, 1), real()[1])
|
||||
try:
|
||||
fn(None)
|
||||
finally:
|
||||
nav = real
|
||||
|
||||
|
||||
def control(h):
|
||||
global FAIL
|
||||
import io, contextlib
|
||||
ok = True
|
||||
print(" known negatives -- every check must notice a perturbed contract:\n")
|
||||
for fn, old, new in CONTROLS:
|
||||
if old not in h:
|
||||
for fn, old, new in CONTROLS + [(f, o, n) for f, o, n in NAV_CONTROLS]:
|
||||
src = h if (fn, old, new) in CONTROLS else nav()[0]
|
||||
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()):
|
||||
fn(h.replace(old, new, 1))
|
||||
if src is h:
|
||||
fn(h.replace(old, new, 1))
|
||||
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_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)
|
||||
|
||||
|
||||
# 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")
|
||||
@@ -203,7 +277,8 @@ def main():
|
||||
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_splash_dwell, check_menu_labels, check_extras_labels,
|
||||
check_wrap):
|
||||
fn(h)
|
||||
print()
|
||||
print(" A passing run means the port agrees with the contract ON THESE VALUES.")
|
||||
|
||||
Reference in New Issue
Block a user