P5's gate is "a human clicks through it". The artifact is a scripted walk that
proves the wiring rather than the intent -- up (wraps 01->05), five down, (A)
into EXTRAS, down, (B) back, landing on the main menu with focus RESTORED to
EXTRAS, ten PNGs one per settled step:
xvfb-run -a godot --path port -- --menu \
--script=up,down,down,down,down,down,accept,down,cancel --shots=/tmp/p5
--script posts InputEventAction through Input.parse_input_event so the presses
arrive at _unhandled_input exactly as a d-pad's would. Calling MenuFlow directly
would have been shorter and would have proved nothing: the wiring between a
press and the cursor is the part most likely to be broken, and a direct call is
exactly the part that skips it.
Derived vs authored, which P5 is the easiest place to blur:
* DERIVED -- the ORDER of the items, from each screen file's `buttons`, which
the exporter already fills from button-role elements sorted by resting Y.
* AUTHORED -- destinations, initial focus, what (B) does, and left/right being
a no-op. All measured off the running game (HANDOFF Q4/Q5) or chosen, none
on the disc, all in authored/flow.json with a why.
Four of five main-menu destinations are `goto: null` with a `blocked` note. That
is a MILESTONE BOUNDARY, not an unknown -- DIFFICULTY, the save list, the lesson
list and OPTIONS were all measured and live in archives this export does not
carry. `blocked` and `none` are kept apart so nobody later "discovers" the gap.
--headless CANNOT DRAW, and the port hung instead of saying so.
Measured, not assumed: under --headless Godot's dummy renderer never emits
RenderingServer.frame_post_draw, so every capture path awaited it forever --
--capture since P1, --film since P3, --shots as of now. With stdout block-
buffered the observable behaviour was SILENCE, FOREVER, which in a loop reads as
a job still working. Isolated by `--quit` (prints, exits 0) vs `--capture` (zero
bytes, killed at 40 s). Now those three flags refuse at STARTUP naming the
xvfb-run line that works, and --script no longer waits for a frame it is not
going to photograph -- so headless walks the menus in 4.5 s as a cheap
regression check needing no X server.
REFUTATION ATTEMPT, against the Decoder's 7eeae30 point 2 ("the oracle confirms
the game renders the ring's rotation"). Aimed there because PROTOCOL says to aim
at a claim the port is about to build on that rests on an estimator whose own
control the Decoder reported as +/-19.8 deg. IT SURVIVES, more strongly than
claimed.
Both captures draw the SAME sprite (ptbtneff01) 240 px apart, so "is it drawn
rotated" becomes "are these two crops one image at a different angle" -- no crop
offset needed and no reference to our own renderer. 360-bin angular luminance
profile over the annulus, circularly cross-correlated. Two controls first: known
rotations 0/30/90/150/210/270/330 recovered with 0 deg error, and a ring-free
patch of the same capture peaks at 0.369, so the estimator does not manufacture
matches. Then: A vs B 134 deg (corr 0.968), sprite vs A 76 deg, sprite vs B
210 deg -- and 210-76 = 134, which nothing in the method forced.
So 0 deg is NOT A POSE THE GAME SHOWS, and screen_view.gd draws the ring at
0 deg. That is now stated in the code as known-wrong rather than suspected. The
port did NOT start spinning it: the period has two unknowns and both are the
Decoder's -- the second keyframe is untimed, and "groups hold" predicts a stop
at 360 = 0 which contradicts both captures. Two frames of one focused button a
known time apart settle it. Filed in BLOCKED.md and asked over the channel.
BLOCKED.md's staleness check was half a check. It tested whether that page is
stale relative to HANDOFF; it cannot see the other direction, and the other
direction is what happened -- 7eeae30 lands 27 minutes AFTER HANDOFF was last
written and answers a question HANDOFF still lists as open. Added the missing
half: `git log --oneline 9ca1eb5..HEAD -- docs/re/`.
Also recorded, since the two were nearly confused: the ring's annulus centroid
lands within ~0.4 px of its design position under a ZERO crop offset, which
corroborates ORACLE-CAPTURES' "1279x675, top-left aligned" on a feature nobody
chose for the purpose. The earlier "text bands at design y + 23" is an offset
WITHIN the button sprite, not a crop offset.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01CtmUw5N5LJaMW1Njb8Ziey
169 lines
9.6 KiB
JSON
169 lines
9.6 KiB
JSON
{
|
|
"format": "sylpheed.flow/1",
|
|
"_": [
|
|
"The boot sequence. AUTHORED, and it has to be: HANDOFF Q6 closed this with a",
|
|
"negative -- the order is in none of the four places it could have been. It is",
|
|
"not in config.ini's empty [SYSTEM], not in the movie manifest (which carries",
|
|
"assets, not transitions), not in a persistent GamePart field (the requested id",
|
|
"lives only as a stack argument in flight), and `GP_ADVERTISE_DEMO` has zero",
|
|
"xrefs of any kind. A transition is a call with a name argument, chosen by code.",
|
|
"",
|
|
"So this file REPRODUCES AN OBSERVATION. The sequence below is what the RE",
|
|
"agent watched the game do, not what any file on the disc says it does. Nothing",
|
|
"here may be presented as decoded."
|
|
],
|
|
"boot": [
|
|
{
|
|
"screen": "publisher_logo",
|
|
"why": "The SQUARE ENIX wordmark is the first thing the boot shows -- RE agent, 2026-08-29. Entry 10 of the pair; 13 is its region twin and the port shows one, not both."
|
|
},
|
|
{
|
|
"screen": "developer_logos",
|
|
"why": "GAME ARTS / SETA / studio anima, after the publisher wordmark. HANDOFF Q2."
|
|
},
|
|
{
|
|
"video": "ADV",
|
|
"why": "HANDOFF Q9, DECODED from the movie manifest: ADVERTISE_MOVIE -> ADV.wmv, and the boot intro and the attract movie are the SAME asset -- there is no separate boot slot. Its POSITION here (after the developer logos, before the title) is measured, not decoded: it is the order the RE agent watched the game boot in.",
|
|
"skippable": true,
|
|
"skippable_why": "HANDOFF Q9: one (A) press skips a movie -- measured, title reached at 57 s against a 193 s baseline."
|
|
},
|
|
{
|
|
"screen": "title",
|
|
"why": "HANDOFF Q2/Q6: the boot reaches the title after the intro movie. The port holds here -- nothing takes the title's place until P5 gives it somewhere to go."
|
|
}
|
|
],
|
|
"dwell": {
|
|
"_": [
|
|
"DELIBERATELY EMPTY. Each screen's dwell is its own keyframe group -- the",
|
|
"publisher wordmark reaches its hold at t=235 (3.92 s) and the developer",
|
|
"logos at t=190 (3.17 s), both read from the disc. Holding beyond that would",
|
|
"be a number nobody has measured, so the sequencer holds for zero extra time",
|
|
"and the pacing is the disc's own.",
|
|
"",
|
|
"When a capture times the real boot, the extra hold per screen goes here."
|
|
]
|
|
},
|
|
"navigation": {
|
|
"_": [
|
|
"MEASURED off the running game, HANDOFF Q5 -- none of it is on the disc.",
|
|
"It lives here rather than in GDScript so that a reader can see it is a",
|
|
"measurement and delete it the day a field on the disc states it."
|
|
],
|
|
"wrap": true,
|
|
"wrap_why": "HANDOFF Q5: up/down move one item and WRAP at both ends. Measured on the 5-item main menu AND the 3-item EXTRAS, so it is a menu rule and not a per-screen one (docs/game/navigation.md, branch auto/no-disc-and-menu-captures 3a87a26).",
|
|
"left_right": "nothing",
|
|
"left_right_why": "HANDOFF Q5: left/right do nothing. Measured. Implemented as an explicit no-op rather than by omission, so that 'we never wired it' and 'the game ignores it' are distinguishable in the code.",
|
|
"input_during_transition": "ignored",
|
|
"input_during_transition_why": "AUTHORED, and NOT measured -- nobody has watched what the game does with a button pressed mid-fade. Ignoring is the choice that invents the least: it cannot queue a press the game might have dropped. Ask the RE agent before relying on it."
|
|
},
|
|
"screens": {
|
|
"_": [
|
|
"What each button does. The NAVIGATION ORDER is not here -- it is derived,",
|
|
"in each screen file's `buttons` (button-role elements sorted by resting Y).",
|
|
"Only the destinations, the initial focus and the cancel target are",
|
|
"authored, because only those are measurements or decisions.",
|
|
"",
|
|
"`goto` is an EXPORTED SCREEN NAME or null. `goto_name` is the game's own",
|
|
"screen vocabulary from the decoded transition lookup -- carried so the",
|
|
"binding is not lost, and marked below as the NAME MATCH it is, never as a",
|
|
"measurement (HANDOFF: the strings are what the call sites reference, not",
|
|
"proven arguments, and the same list mixes in TEXT_FONT and GAMMA_RGB).",
|
|
"",
|
|
"`goto: null` with a `blocked` note means the destination screen is real and",
|
|
"measured but is NOT IN THIS EXPORT -- it lives in another archive. That is a",
|
|
"milestone boundary, not an unknown."
|
|
],
|
|
"title": {
|
|
"on_accept": {
|
|
"goto": "main_menu",
|
|
"goto_name": "TITLE_MENU",
|
|
"goto_name_kind": "name match, not measured",
|
|
"why": "MEASURED, HANDOFF: (A) on the title opens the main menu, with (A) on the boot title as the control in the same run."
|
|
},
|
|
"on_cancel": null,
|
|
"on_cancel_why": "MEASURED, HANDOFF Q5: (B) on the title does nothing."
|
|
},
|
|
"main_menu": {
|
|
"initial_focus": "ptbtn01",
|
|
"initial_focus_kind": "authored",
|
|
"initial_focus_why": "AUTHORED, standing in for HANDOFF Q5, which measured that initial focus is NOT STABLE: four boots of the same harness opened on TUTORIAL, TUTORIAL, NEW GAME, NEW GAME. A port has to open on something. ptbtn01 (NEW GAME) is picked because it is one of the two states actually observed and it is the top item, so a reader can predict it. It is a CHOICE. Delete this the day the RE agent finds what selects it.",
|
|
"on_cancel": {
|
|
"goto": "title",
|
|
"goto_name": "TITLE_SCREEN",
|
|
"goto_name_kind": "name match, not measured",
|
|
"kind": "authored -- likely but UNPROVEN",
|
|
"why": "HANDOFF Q5 states (B) on the main menu returns to the title. That is the ONE navigation rule on this screen with no capture behind it: it was seen once, without a capture, and the title also returns on its own after ~8-10 s idle, so an observer could not have told the two apart (docs/re/menu-navigation-semantics.md). Independently, the main menu is the ONLY screen whose footer does not advertise (B) -- confirmed here from the disc art, see docs/port/DECISIONS.md. The port implements it because a menu with no way out is worse than a menu with a plausible one, and records that it is authored."
|
|
},
|
|
"buttons": {
|
|
"ptbtn01": {
|
|
"label": "NEW GAME",
|
|
"goto": null,
|
|
"goto_name": "DIFFICULTY",
|
|
"goto_name_kind": "name match, not measured",
|
|
"blocked": "DIFFICULTY is not in this export. MEASURED destination (EASY/NORMAL/HARD/BACK, opening on NORMAL, then SELECT DATA) but it is not a GP_TITLE build, so there is no screen file to go to yet."
|
|
},
|
|
"ptbtn02": {
|
|
"label": "LOAD GAME",
|
|
"goto": null,
|
|
"goto_name": null,
|
|
"blocked": "The save-slot list is GP_SAVE_LOAD, not in this export. Destination MEASURED."
|
|
},
|
|
"ptbtn03": {
|
|
"label": "TUTORIAL",
|
|
"goto": null,
|
|
"goto_name": "TUTORIAL_MENU",
|
|
"goto_name_kind": "name match, not measured",
|
|
"blocked": "The lesson list is not a GP_TITLE build. Destination MEASURED."
|
|
},
|
|
"ptbtn04": {
|
|
"label": "OPTIONS",
|
|
"goto": null,
|
|
"goto_name": null,
|
|
"blocked": "The settings menu is GP_OPTIONS, not in this export. Destination MEASURED."
|
|
},
|
|
"ptbtn05": {
|
|
"label": "EXTRAS",
|
|
"goto": "extras",
|
|
"goto_name": "EXTRA_MENU",
|
|
"goto_name_kind": "name match, not measured",
|
|
"why": "MEASURED, HANDOFF Q4: EXTRAS opens GP_TITLE build 6. It is the ONLY main-menu destination inside this archive, and therefore the only (A)-into-a-submenu the P5 gate can actually walk."
|
|
}
|
|
},
|
|
"labels_why": "The five labels are read off live-main-menu.png, a capture of the running game (docs/game/navigation.md, branch auto/no-disc-and-menu-captures 3a87a26). They are carried for logs and for a human reading this file; nothing draws them -- the button sprite already has its own text."
|
|
},
|
|
"extras": {
|
|
"initial_focus": "ptbtn11",
|
|
"initial_focus_kind": "measured",
|
|
"initial_focus_why": "MEASURED, unlike the main menu's: EXTRAS opens focused on MISSION SELECT (live-extras.png). It is authored here only because there is nowhere else to put a measurement -- it is not a choice.",
|
|
"on_cancel": {
|
|
"goto": "main_menu",
|
|
"goto_name": "TITLE_MENU",
|
|
"goto_name_kind": "name match, not measured",
|
|
"why": "MEASURED, HANDOFF Q5: (B) goes up one level and RESTORES FOCUS to the item you came from. EXTRAS advertises (B) in its own footer -- the red glyph is in ptmsg2.png and absent from the main menu's ptmsg.png."
|
|
},
|
|
"buttons": {
|
|
"ptbtn11": {
|
|
"label": "MISSION SELECT",
|
|
"goto": null,
|
|
"goto_name": null,
|
|
"blocked": "The stage list is GP_MISSION_SELECT, not in this export. Destination MEASURED."
|
|
},
|
|
"ptbtn12": {
|
|
"label": "MOVIE THEATER",
|
|
"goto": null,
|
|
"goto_name": null,
|
|
"blocked": "NEVER OPENED. docs/game/navigation.md marks this one unknown -- not merely unexported. Do not assume it opens GP_MOVIE_THEATER; that would be a name match dressed as a destination."
|
|
},
|
|
"ptbtn13": {
|
|
"label": "BACK",
|
|
"goto": "main_menu",
|
|
"goto_name": "TITLE_MENU",
|
|
"goto_name_kind": "name match, not measured",
|
|
"same_as_cancel": true,
|
|
"why": "MEASURED: EXTRAS' third item is BACK (live-extras.png). Treated as (B): it pops the stack, so focus is restored on the main menu exactly as (B) does. Whether the game distinguishes them is untested and there is no reason here to invent a difference."
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|