port: land the play-tested work, and only that

Takes the port branch up to 77320d5e -- the state the human play-tested on
2026-09-02 -- for SOURCE paths only. Not a branch merge: `auto/port-p6-audio`
is 366 commits and 938 files, and most of that must not land.

WHAT COMES IN (76 files, all human-confirmed working):
  * the logo splash animation. 08ed3dd1 found it: `pose_at` ASSIGNED the settle
    instant instead of clamping to it, so the splash never animated at all --
    and the same bug manufactured a passing harness result, because the harness
    photographed t past the settle. Confirmed by play-test: "cannot notice any
    obvious difference from the actual game."
  * gamepad input -- (A)/(B) bound additively (`ui_accept` ships with NO joypad
    binding), stick latched with hysteresis at the game's own 61% digitise
    threshold. This is what made (A), video-skip and Extras work at all.
  * menu navigation and flow, menu audio, the exporter, the authored
    declarations, and 23 verification tools under tools/port/.

WHAT IS DELIBERATELY LEFT ON THE BRANCH:
  * everything after c0ae460a -- the F5/F6 title-timing investigation, whose own
    tip commit calls itself a "hand-off for one-minute human checks". Unchecked
    by definition; it goes through the new review gate like anything else.
  * the OPTIONS menu work of 2026-09-03. Real, probably good, NOT play-tested.
  * the F1 repeat mechanism, which its own commit calls "deliberately inert".

WHAT MUST NOT LAND, AND WHY THE .gitignore CHANGED:
  545 MB of extracted game content was committed on that branch -- 850 sprite,
  audio and transcoded video files under `export-probe/` and `export-probe2/`,
  plus 246 MB of loose .wav and .tsv at the repo root. This repository's own
  rule, in this file, is "never game content".

  The rule was not missing. It was written, and it was tightened on that very
  branch, with a careful comment explaining why BOTH `export/` and `data/base/`
  had to be listed -- while the exporter was writing to a third name that
  nobody had thought to list. Enumerating names is the thing that failed. So
  the ignore rules now describe the SHAPE: any top-level `export*/`, game media
  by extension, and loose capture output at the root. Verified both ways -- it
  catches all four offenders and ignores nothing currently tracked.

Verified: `cargo check --workspace` clean; all nine GDScript files parse in
project context, with a positive control (an injected syntax error is detected,
3 lines) so the clean result means something. `tools/port/check-all` was NOT
run -- it needs the container, the export tree and a display.
This commit is contained in:
MechaCat02
2026-09-04 16:17:14 +02:00
parent ad96fe97b8
commit a23c321831
76 changed files with 32972 additions and 346 deletions

384
authored/audio.json Normal file
View File

@@ -0,0 +1,384 @@
{
"format": "sylpheed.audio/1",
"_": [
"Menu audio. EVERY VALUE IN THIS FILE IS MEASURED OR CHOSEN -- none of it is",
"in a data file the exporter can read, which is why it is here and not in the",
"exporter. `measured` and `chosen` are NOT the same thing and this file keeps",
"them apart: a measurement is deleted when the disc states it, a choice is",
"deleted when somebody measures it.",
"",
"Two different kinds of not-on-the-disc live in this file and they are not",
"interchangeable:",
"",
" * `se` -- MEASURED. `Static.slb` is a delimiter-less run of whole 2048-byte",
" XMA1 packets: no RIFF, no seek chunk, no XACT container. A wave is defined",
" ONLY by (offset, packet_count), and both numbers come from the running",
" game, not from the file. HANDOFF Q8. Delete a row the day a table on the",
" disc states the same thing.",
"",
" * `bgm` -- MEASURED, and only the LOOP POLICY beside it is chosen. HANDOFF",
" Q10's negative is about the TABLES: `SOUNDS`, `FILES` and the bank headers",
" name no screen. The executable does -- cue 1103 = `BGM_103`, corroborated",
" by a byte-for-byte match against what the XMA probe saw at the main menu.",
" An earlier draft read the negative as unbounded, picked a track at random",
" and called it authored. See the `bgm._` block for what that cost.",
"",
"The exporter reads this file and emits `export/audio/**` from it. It holds no",
"cue table of its own: a measured offset compiled into a Rust `const` is a",
"measurement wearing the costume of a decoded field, and MISSION section 3 is",
"explicit that measured values live here."
],
"se": {
"_": [
"MEASURED, HANDOFF Q8, and the RE agent retracted an earlier 'cannot be",
"extracted' to publish these. The waves were located BY PLAYING THEM: Canary",
"with `--xma_param_probe=true` prints a stream's packet count and first 32",
"bytes when it is played, and searching those bytes in the bank gives the",
"offset.",
"",
"WARNING, from the same finding: the file order is NOT cue-id order. These",
"cannot be counted out, and an index here would be a fabrication.",
"",
"`name_match` is the authors' own identifier GUESSED BY NAME. It is carried",
"so the guess is not lost and is never presented as the measurement. Where",
"the RE agent did not separate two candidates, there is no name at all --",
"an absent `name_match` means nobody has claimed one, never that the",
"BINDING is unknown. The binding is the measured part.",
"",
"All three are mono 48 kHz; that is the RE agent's statement in",
"`sylpheed_formats::media::se_wave_riff`, not something re-derived here."
],
"move": {
"bank": "Static.slb",
"offset": "0x1ec0",
"packets": 4,
"channels": 1,
"rate": 48000,
"name_match": "SE_UI_CURSOR",
"why": "HANDOFF Q8, measured: the d-pad move cue, 8 192 B / 0.533 s, reproduced across two boots. Left/right play nothing at all, which is a measurement too and is why there is no `left`/`right` row here rather than a silent file.",
"kind": "measured"
},
"confirm": {
"bank": "Static.slb",
"offset": "0x5d6c0",
"packets": 6,
"channels": 1,
"rate": 48000,
"why": "HANDOFF Q8, measured: the (A) confirm cue, 12 288 B / 1.016 s. NO `name_match`: Q8 is explicit that (A)'s wave was not separated between `SE_UI_DECIDE` and `SE_UI_SUB_WIN_OPN`, so naming it would invent the one thing the measurement did not settle.",
"kind": "measured"
},
"back": {
"bank": "Static.slb",
"offset": "0x0ec0",
"packets": 2,
"channels": 1,
"rate": 48000,
"why": "HANDOFF Q8, measured: the (B) back cue, 4 096 B / 0.344 s, reproduced across two boots. No `name_match` for the same reason as `confirm` -- Q8 names no identifier for it.",
"kind": "measured"
}
},
"bgm": {
"_": [
"MEASURED, NOT CHOSEN -- and the port got this wrong for one iteration.",
"",
"`docs/port/BLOCKED.md` carried a row reading 'not on the disc ... the port",
"is choosing a track, and that choice is authored', and the first draft of",
"this file duly picked BGM_001 and labelled it arbitrary. That row was not",
"stale: `BGM_103` is in HANDOFF at `9ca1eb5`, which is the exact commit the",
"row says it was reconciled against. It was WRONG WHEN WRITTEN.",
"",
"What HANDOFF actually says is a negative with a stated reach, and the reach",
"is what the port dropped: the *tables* cannot say which BGM a screen plays",
"-- `SOUNDS`, `FILES` and the bank headers name no screen. The EXECUTABLE",
"can. `GamePart_Title`'s phase handler `sub_821C5580` carries `li r5, 1103`",
"into a sound call, cue 1103 is `BGM_103`, and `BGM_103.slb`'s two declared",
"waves (3 876 864 / 3 930 112 B) are byte-for-byte the two streams the XMA",
"probe saw decoding at the main menu. Static code, disc census and runtime",
"agree. HANDOFF's own words: 'The port does not have to choose a track.'",
"",
"So this section is a CITATION, not a decision. It lives in `authored/`",
"only because the binding is in the .xex and the exporter reads data files,",
"not code -- and it must be deleted the day something the exporter can read",
"states it. The loop policy below IS still a decision."
],
"main_menu": {
"bank": "BGM_103.slb",
"loop": "restart",
"kind": "measured",
"why": "MEASURED, HANDOFF Q10 -- NOT a port choice. `GamePart_Title`'s phase handler `sub_821C5580` plays cue 1103 = `BGM_103`, and `BGM_103.slb`'s two declared waves (3 876 864 / 3 930 112 B) are byte-for-byte the two streams the XMA probe saw decoding at the main menu. Static code, disc census and runtime all agree; see docs/re/menu-audio-cues.md and docs/re/structures/bgm-two-stems.md. The name carries its `.slb` extension because that is what `sound.pak` hashes -- `BGM_103` alone resolves to nothing, which is how the first draft of this file failed. ✅ AUDITED 2026-08-31 -- the THREE legs are three, and that is now measured rather than asserted. Prompted by the Decoder's point that a decorative second support is worse than none, since a conclusion with two supports reads as better evidenced than one and apparent redundancy is itself the misinformation. Read literally, 'disc census' and 'runtime' could be ONE comparison -- declared wave sizes matched byte-for-byte against the probe -- which would make three legs two. It is a real third leg only if the census EXCLUDES alternatives: if another bank carried the same two sizes, the byte match would not distinguish BGM_103. Measured with this port's own reader (`crates/sylpheed-export/examples/bgm_size_census.rs`): of 32 readable BGM_* banks on the disc, EXACTLY ONE carries waves of that size. The census therefore excludes, the static-code leg names the cue independently, and the three legs stand. ✅ AND THE EXCLUSION IS TIGHTER THAN I STATED. The Decoder attempted to refute it from their own census tool rather than this port's reader: of 32 census rows, exactly one bank carries EITHER of those wave sizes -- not merely both together, which is what I measured. A collision would therefore need to reproduce a single size, not a pair, and none does.",
"loop_why": "MEASURED, and this field's own history is why it says so first. The bed loops; the loop is a RUNTIME field -- `loop_start`/`loop_end` in the XMA decoder context, set by `XMASetLoopData` and logged by Xenia -- and the cycle was watched directly: three wraps, both contexts wrapping at the same instant every time, mean 61.81 s against the 61.93 s authored in `loop_end_s`, 0.2 % apart from instruments sharing nothing. The export is TRIMMED to that window, because Godot loops a whole file and a loop region therefore has to BE the file. ⚠️ The window's START is not measured and is authored as 0, which is known to be wrong -- see `loop_start_why`. 🔴 EVERY SENTENCE THAT PRECEDED THIS ONE WAS REFUTED, and the previous text survived in the manifest for two days after the corrections were written. It said the loop would be `AUDIBLY WRONG AT THE SEAM [refuted]`, that `no loop-point field has been identified [refuted] anywhere`, and that trimming `would INVENT a loop point`. All three are false: the field exists, the 3.4 s of near-silence was the PORT'S loop and not the game's, and the trim is now what the measurement says. The corrections went into `loop_end_why` and `loop_start_why`; this field is the one the exporter concatenates into `manifest.json`, so the export went on telling readers the refuted story. A correction that does not reach the artifact a consumer reads has not been made. 📌 CITATIONS ADDED 2026-09-01, and their absence was found by `audit-kinds` the moment this field got a `kind` -- it had 1 400 characters of prose and nothing openable, which is exactly the state the audit exists to catch and could not see while the field was unlabelled. The wrap measurement is docs/re/data/menu-bgm-loop-measured.txt and the start is docs/re/data/menu-bgm-loop-start.txt; the bank's two-stem structure is docs/re/structures/bgm-two-stems.md.",
"loop_kind": "measured",
"stems": "sum",
"stems_why": "MEASURED, HANDOFF Q10: a bank is exactly TWO waves of identical duration (32/32 banks on the disc), sample-synchronous -- transient correlation peaks at lag 0.00 s over +/-5 s and both stop at the same millisecond. Concatenating them plays the piece twice, the second time as a bass-less stem; that was the previous reading and it is refuted. Emitting two files would be wrong for a second reason: MODDING rule 1 is one logical asset, one file, and handing a modder two stems to line up by hand is the reassembly the exporter exists to have already done. WHAT IS SUMMED IS SETTLED; WHAT WAVE 1 IS, IS NOT -- HANDOFF calls it quieter, far more L/R-decorrelated and almost bass-free, so it reads as a surround-rear pair OR a second intensity layer, and `ChannelMask` is 0x0002 on both so the file will not say. A unity sum is right under either reading; a weighting would only be justified once that is settled.",
"stems_kind": "measured",
"loop_start_s": 9.44,
"loop_start_why": [
"MEASURED 2026-08-30 -- 9.44 s. The loop region is [9.44 s, 71.31 s] of an",
"87.744 s wave: the first 9.44 s is an intro played ONCE, and the last 16.4 s",
"is a fade-out never played at all.",
"",
"Two derivations, both stems, and NEITHER converts bits to seconds -- the",
"conversion that refuted itself earlier by giving two sample-synchronous stems",
"62.34 and 63.29 s. (a) time to `read_offset` crossing `loop_start`, plus a",
"1.33 s head correction at a LOCALLY measured rate; (b) first pass minus cycle.",
"9.44 s on both stems either way.",
"",
"⚠️ ONE BOOT, ONE BANK. The decoder reads ahead of playback, but both endpoints",
"are `read_offset` events so the lead cancels in the difference.",
"",
"🔴 THIS FIELD WAS 0.0 AND FLAGGED WRONG FOR ONE ITERATION, deliberately. The",
"value was not guessable -- linear back-extrapolation said 9-13 s and linearity",
"is refuted by a 4.4 % rate variation within one stream. What made the wait",
"cheap was that the field EXISTED and the `-ss`/`-t` ordering had been proved",
"with a stand-in value, so arriving at 9.44 was a one-value edit.",
"",
"📌 CITATION ADDED 2026-09-01 -- found the moment this field got a `kind`. It",
"carried 1 041 characters describing two derivations and cited no file. The",
"numbers are in docs/re/data/menu-bgm-loop-start.txt, and the loop region's",
"wrap timing is in docs/re/data/menu-bgm-loop-measured.txt.",
"",
"⚠️ Second uncited MEASURED field in this one entry, after `loop_why`. Both",
"described their evidence carefully in prose and pointed at nothing. A why that",
"recounts a measurement reads as well-sourced precisely because it is detailed,",
"which is why neither looked wrong.",
"",
"✅ AUDITED 2026-09-01 with the exclusion test: could either derivation have come",
"out differently given the other? YES, and they discriminate different errors --",
"(a) depends on a locally measured RATE and (b) on the CYCLE, so a wrong rate",
"breaks (a) and leaves (b) standing, and a wrong cycle does the reverse. Two legs",
"that fail independently, which is what 'two derivations' was claiming.",
"",
"⚠️ BOUND: they share one trace. A systematic error in the read_offset stream",
"moves both, and the ONE BOOT, ONE BANK caveat above is that limit stated. What",
"they exclude is arithmetic error, not trace error."
],
"loop_start_kind": "measured",
"loop_end_s": 61.87,
"loop_end_why": [
"MEASURED off the running game 2026-08-30, 240 s parked on the menu",
"(docs/re/structures/menu-bgm-loop-measured.md). The bed loops at 61.93 s, NOT",
"at the summed wave's 87.744 s length, and the last ~25.8 s is never played --",
"exactly the fade-out and trailing silence bgm-two-stems.md found. The game",
"loops BEFORE the fade.",
"",
"🔴 THIS CORRECTS AN AUTHORED VALUE THAT WAS WRONG IN BOTH DIRECTIONS. `restart`",
"at the wave's end produced a seam of about 3.4 SECONDS of near-silence, and",
"this port measured that seam off its own Master bus and recorded it as the",
"cost of a missing loop point. It was not the game's seam; it was OURS. Zero",
"runs of >=0.3 s below median-18 dB appear in 232 s of the real menu.",
"",
"Two instruments agree: correlation gives a top lag of 61.909 s and r = -0.009",
"at 87.750 s, and locating 30 s slices inside the decoded waves shows playback",
"advancing exactly +5.00 s per 5 s and wrapping at 61.93 s, three times, with a",
"control that finds slices cut at 10/45/70 s at 10.00/45.00/70.00.",
"",
"⚠️ The loop START is inferred, not measured: [0.0, 61.93) and [0.25, 62.18) are",
"not separated at their resolution. The port takes 0 because a bank's own start",
"is where its data begins, and records that the choice was not measured.",
"",
"⚠️ Godot loops a WHOLE FILE, so the export is TRIMMED to 61.93 s rather than",
"carrying a loop point the runtime could not honour. The trimmed tail is",
"content the game never reaches, so nothing playable is lost -- but a modder",
"replacing this file is replacing the loop region, not the whole bank.",
"",
"🔴 CONFLICT, OPEN AS OF 2026-08-30. The loop IS a runtime field: `loop_start`",
"and `loop_end` live in the XMA decoder context, set by `XMASetLoopData`, and",
"the RE agent read 8734 records off the menu. Converted, they imply a cycle of",
"roughly [10 s, 72 s] against the [0.25, 57.18] their audio tracking reported.",
"BOTH CANNOT BE RIGHT and neither has been withdrawn.",
"",
"They judge the weak link probably theirs: the locator's control matched slices",
"cut from the wave ITSELF -- exact copies -- which is an easier problem than",
"matching a capture that differs by decoder, gain and mix. A control easier than",
"the measurement does not bound the measurement's error, and music with repeated",
"sections is where a locator aliases.",
"",
"⚠️ THE VALUE IS KEPT ON THEIR INSTRUCTION, and because the LENGTH survives",
"better than the PLACEMENT: 61.93 has an autocorrelation behind it that used no",
"wave at all, and the trimmed loop has no seam in this port's own output.",
"",
"This port added one check neither of their instruments ran: whether the trim",
"JOINS SMOOTHLY. Over 126.5 s the wrap at 61.93 s and again at 123.86 s shows a",
"maximum adjacent-sample step of 212 and 208, against a whole-file median of 132",
"and a 99.9th percentile of 3737. So the join is not a click and nothing is",
"audibly broken.",
"",
"⚠️ THAT DOES NOT DISCRIMINATE THE TWO READINGS. A smooth join says the waveform",
"does not jump; it does not say the loop is at the musically right point, and a",
"cut landing near a zero crossing is smooth wherever it falls.",
"",
"🔴 What the conflict would COST if their runtime fields win: under [10 s, 72 s]",
"this export is about 10 SECONDS SHORT -- the content in [61.93, 72] is played",
"by the game and absent here. That is the number to weigh when it resolves, and",
"it is why this entry is not being treated as settled.",
"",
"✅ CONFIRMED 2026-08-30 BY A SECOND INSTRUMENT SHARING NOTHING WITH THE FIRST.",
"The RE agent stopped converting the runtime fields and TIMED them instead --",
"a probe tailing the Apu debug log and stamping `read_offset` on arrival --",
"and watched THREE wraps, each from its own `loop_end` to its own `loop_start`,",
"with both contexts wrapping at the SAME INSTANT every time. Cycle 61.56 and",
"62.06 s, mean 61.81 s: 0.2 % from the 61.93 authored here, measured by wall",
"clock between decoder events against an autocorrelation that never touched",
"the wave. Both contexts wrapping together is the sample-synchrony the linear",
"bit conversion could not produce.",
"",
"So the LENGTH is settled and the WINDOW is not. See `loop_start_why`.",
"",
"✅ 61.87 ADOPTED 2026-08-30, replacing 61.93. Their wrap timing gives 61.87 --",
"wraps at 96.46 / 158.33 / 220.21 s, gaps 61.87 and 61.87 -- against the 61.93",
"this port's autocorrelation gave. 0.1 % apart. The measured value is taken",
"because it is the one with the loop's own endpoints under it; the",
"autocorrelation never touched the wave and agreed to a tenth of a percent,",
"which is what makes both worth having."
],
"loop_end_kind": "measured"
}
},
"voice": {
"_": [
"🔴 KNOWN WRONG, HELD DELIBERATELY. Which of a voice region's streams to",
"export. The premise this entry was built on has been REFUTED BY THE RUNNING",
"GAME and the entry is kept, escalated, rather than swapped for another guess.",
"",
"The premise was: a region carries THREE PRESENTATIONS OF ONE TAKE, so the",
"exporter picks one. The Decoder booted with `--xma_param_probe=true` -- the",
"cvar that reports which sub-wave the game decodes -- and the game decodes",
"ALL THREE, CONCURRENTLY, in three separate XMA contexts, with byte sizes",
"matching the three disc payloads exactly (1294336 / 1118208 / 1171456",
"against RIFF size - 60 of 1294396 / 1118268 / 1171516).",
"",
"SO THERE IS NO 'WHICH ONE' TO ANSWER. `presentation` below discards two of",
"three streams the game plays. It is not a preference between rules any more;",
"it is a known-incomplete export.",
"",
"WHY IT IS NOT CHANGED TODAY. Reverting to the 1/n sum is not obviously less",
"wrong: an equal-gain sum of channel pairs is not a downmix -- MISSION",
"section 6 makes exactly that point when it pins an explicit matrix for the",
"movies' 5.1 fold rather than letting ffmpeg default -- and the 6.02 dB the",
"sum cost S00A was a real defect. Swapping one guess for another on a message",
"is what produced this entry twice already.",
"",
"🟡 HYPOTHESIS, NOT A RESULT, and it is the Decoder's: three concurrent stereo",
"streams is six channels, and N stereo streams is how XMA carries",
"multichannel on the 360, so 5.1 would explain the differing byte rates, the",
"near-silent stream and why cues are 1-stream or 3-stream and never 2. AGAINST",
"IT: all three declare ChannelMask = 0x0002 identically, which is odd for",
"distinct channel roles. Do not build on it.",
"",
"WHAT SETTLES IT: a recording of the game's own output over the intro,",
"through the PulseAudio null sink (AUDIO-VERIFICATION section 3). Candidate",
"combinations of the three decoded streams can then be correlated against",
"what the game actually played. Asked 2026-08-29.",
"",
"🔴 REFUTED FROM THE OUTPUT SIDE, 2026-08-30, not merely suspected.",
"",
"The RE agent recorded 148 s of the game's own output over the boot intro",
"(ALSA tee, --gpu=null, 0.15 % silence -- cleaner than the recipe page's own",
"reference run), with provenance from the XMA probe rather than a screenshot:",
"`ADV`'s three contexts appear byte-exact, then the `BGM_102` pair.",
"",
"FIVE OF SIX CHANNELS CARRY DISTINCT CONTENT. No channel is a copy of another;",
"the largest pairwise correlation is 0.70, between FL and FR, which is what a",
"stereo pair looks like. BR is 82 % silent and 11 dB down.",
"",
"So `presentation: \"loudest\"` -- keeping ONE stream -- cannot be right. That",
"was already labelled known-wrong here on the strength of the game decoding",
"all three concurrently; it is now refuted by what the game PLAYS.",
"",
"⚠️ AND IT IS STILL NOT FIXED, DELIBERATELY, on the RE agent's own instruction.",
"Three limits they state:",
" * it does not make summing right -- the output is multichannel, which says",
" nothing about which stream lands where;",
" * '6 channels' is NOT evidence the game is 5.1 -- that count is Xenia's",
" hardcoded kFrameChannelsDefault. The evidence is that five of them DIFFER,",
" which a stereo guest cannot produce;",
" * 🔴 the stream-to-channel mapping is NOT RUN. Cross-correlating each",
" captured channel against each decoded `ADV` stream is the step that",
" answers this, and it is their next iteration.",
"",
"Changing the mapping now would swap one authored guess for another, which is",
"a worse position than a guess that is labelled. The value stays; the label is",
"upgraded from suspicion to refutation."
],
"presentation": "all",
"presentation_why": [
"`loudest` = the full-length stream whose peak is nearest full scale.",
"",
"🔴 READ THE BLOCK ABOVE FIRST. This selects one of three streams the game",
"decodes concurrently, so whatever it selects, two are missing. The",
"paragraphs below are the history of how the value was arrived at, kept",
"because the reasoning is what makes the error checkable -- NOT because the",
"choice is defensible on its own terms any more.",
"",
"It was `highest_rate`, on a recommendation withdrawn as self-contradictory:",
"'the highest-rate, highest-gain one is chunk 1' selects different streams --",
"ADV stream 2 is 1118268 B at 0.0 dBFS, stream 3 is 1171516 B at -8.3.",
"",
"A structural argument for `loudest` was offered and withdrawn too: ADV",
"stream 2 is mono-in-stereo and stream 3 is dual-mono, so the extra bytes",
"looked like a duplicated channel rather than fidelity. The CHANNEL",
"MEASUREMENT stands and now reads differently -- these are channel pairs, and",
"0.60x with the residual 26.8 dB down is what a correlated pair at a lower",
"level looks like. The GENERALISATION was refuted by census: the stream-3 /",
"stream-2 size ratio over the 28 three-stream cues runs 0.0778 to 2.9163.",
"",
"⚠️ THE FAILURE MODE HERE IS THAT IT SOUNDS FINE. A single stream decodes to",
"clean audible dialogue, so nothing in the output reveals that two streams",
"are missing. That is why the manifest says it in words on every voice entry",
"rather than leaving it to this file.",
"",
"📌 WHERE THE OPEN QUESTION LIVES, added 2026-09-01 under this port's own rule:",
"an `authored` kind must cite the question it stands in for, or an invented",
"value and a placeholder for a measurement read identically. This one stands in",
"for the three-concurrent-streams problem, recorded in docs/port/BLOCKED.md and",
"delivered in docs/port/HANDOFF.md -- the game decodes all three at once, so",
"ANY single selection is missing two, and the export states that per movie",
"rather than choosing quietly.",
"",
"⚠️ 1 402 characters of careful reasoning and nothing openable until now. It is",
"the third uncited field in this file, and all three were detailed rather than",
"sloppy -- the detail is what made them look sourced."
],
"presentation_kind": "authored",
"stream_weights": {
"_": [
"Declared XMA `byte_size` -> the coefficient that stream's position takes in a",
"stereo downmix. MEASURED by the RE agent 2026-08-30",
"(docs/re/structures/intro-audio-decomposed.md): decomposing the game's own",
"6-channel output as capture = 0.600 x movie + residual puts ctx0 at FL/FR,",
"ctx1 at FC with LFE silent, and ctx2 at BL/BR.",
"",
"🔴 KEYED BY BYTE SIZE ON PURPOSE. The assignment is indexed by the decoder's",
"own declared size, so the exporter can CHECK that the stream in front of it is",
"the one the measurement describes rather than assume it. A region whose chunks",
"do not match falls back to the count divisor and says so. That is not defensive",
"programming: on 2026-08-30 this table's sizes did NOT fit the region the",
"resolver returned, which is what exposed `resolve_movie_voice_region` starting",
"238 packets late. Had the weights been applied positionally they would have",
"been applied to the wrong streams silently.",
"",
"⚠️ ONE BOOT, ONE MOVIE. Only `ADV`'s three streams were measured. `S00A`'s",
"sizes match nothing here and it keeps the divisor -- extending this by",
"POSITION would be assuming the ordering generalises, which is exactly the",
"inference the byte-size key exists to avoid.",
"",
"⚠️ The weights are a stereo downmix's, folded to mono. They sum to 1.0, so the",
"total is the movie's own; what they distribute is the balance between three",
"positions. Whether the game's 0.600 mixer gain is a constant or a volume",
"setting is unknown and the port applies no gain of its own."
],
"1294336": {
"position": "FL/FR",
"weight": 0.4142
},
"1118208": {
"position": "FC (LFE silent)",
"weight": 0.2929
},
"1171456": {
"position": "BL/BR",
"weight": 0.2929
}
}
}
}

View File

@@ -1,55 +1,669 @@
{
"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."
]
"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. 📌 SOURCE, added 2026-09-01: the boot's screen order and dwells are derived from GP_TITLE's own entries -- see docs/port/FORMAT.md for the export shape and docs/re/ui-title-build-map.md for which entry is which screen. The order here is not authored; it is what the archive declares."
},
"screens": {
"_": [
"What each button does. NOT FILLED IN -- that is P5. HANDOFF Q4 measured the",
"destination screens and the RE agent later decoded that a transition is a",
"lookup by NAME, giving a candidate vocabulary (TITLE_SCREEN, TITLE_MENU,",
"LOADING, DIFFICULTY, EXTRA_MENU, TUTORIAL_MENU). Those are the right `goto`",
"targets when this is written, marked as the name match they are."
]
{
"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.",
"skippable_kind": "measured"
},
{
"screen": "title",
"overlay": {
"screen": "press_start",
"clock": "shared",
"why": "MEASURED, 2026-08-29, docs/re/title-plate-delay-measured.md on branch auto/no-disc-and-menu-captures at 5b0a6e6 (NOT on main when this was written). The boot title shows build 4 ALONE and the `PRESS (A) BUTTON` plate -- build 2 -- arrives later. This is the ONE case in the port where two builds are drawn at once.",
"no_constant_why": "THERE IS NO AUTHORED DELAY HERE, AND THERE WAS ONE FOR ONE ITERATION. The first version of this block carried `after_settle_seconds: 2.13`, taken from the RE agent's instruction. The port refuted that instruction with arithmetic off the disc -- build 2 has a group of its own, and starting it at settle put the plate 3.97 s late -- and the corrected answer needs no constant at all: BOTH BUILDS RUN ON ONE CLOCK, STARTED TOGETHER, and the plate arrives at its own declared t=236 (CORRECTED 2026-09-01 from t=238, which is the last opaque frame rather than the arrival). `clock: \"shared\"` is that, spelled out rather than implied by the absence of a delay field. 📌 SOURCES, added 2026-09-01 in the uncited-why backfill: the plate's arrival is docs/re/title-plate-delay-measured.md and its pulse is docs/re/structures/plate-pulse-measured.md. 🔴 AND `clock: \"shared\"` IS AUTHORED FROM OUR OWN ARITHMETIC, NOT MEASURED. Nobody has watched whether build 2's group starts with build 4's; it is the reading that reconciles the oracle's 2.13 s IF the settle anchor is t=118. See docs/port/plate-arrival-halves.md and BLOCKED.md H3.",
"arithmetic_why": "Why one clock reproduces the measurement, checked against this export rather than taken on trust: build 4's effect quads `pteff01`, `pteff02` and `ptlogoall_eff` end their ramps together at t=118; `ptbtn00` reaches alpha 255 at t=236; the difference is 118 units = 1.967 s at 60 units/s. The oracle measured 2.138 s and 2.132 s. The gap is presentation rate: the emulator presents at 28.1 fps against a nominal 30, and the corpus had independently measured the idle title at 28.5 fps before these runs. 🔴 CORRECTED 2026-09-01: this said `ptbtn00` reaches 255 at t=238 and that the difference is 120 units = 2.000 s. It reaches 255 at t=236 and HOLDS to 238, so 238 is the last opaque frame, not the arrival; 236 - 118 = 118. The port printed the contradiction in one sentence on every boot. The correction moves the reconciliation by 0.033 s and overturns nothing -- see docs/port/plate-arrival-halves.md. 🔴 AND THE ANCHOR IS NOW OPEN. The oracle defines \"title settled\" operationally, as its glyph counter first reading the no-plate value 154. This export offers TWO anchors 42 units apart: t=118 (the effect quads) and t=160 (`ptcopyright` at full alpha -- the LAST element to finish building in, and the only one made of glyphs). This line picked 118, while `ScreenView.settle_time()` returns 160 and the boot prints `settles at t=160`, so one binary holds both. Asked in BLOCKED.md H3; not guessed here. 📌 SOURCE: the pulse period and its phase behaviour are in docs/re/structures/plate-pulse-measured.md and docs/re/structures/plate-pulse-phase-lock.md, with the raw series in docs/re/data/plate-pulse-timeseries.txt. ✅ AUDITED 2026-09-01: the corpus's 28.5 fps is a genuinely independent leg -- a different quantity (idle-title presentation rate), measured BEFORE these runs, so it could have come out disagreeing. It agrees to 1.4 %.",
"the_premise_that_failed_why": "The port's own, and it is worth keeping because it will bite again: `rest.t` IS NOT WHEN A SCREEN SETTLES. It is the last hold keyframe before the exit. Reading it as the settle put build 4's arrival at 4.35 s instead of 1.97 s, and every reconciliation computed from it came out wrong by exactly that error. `ScreenView.settle_time()` still uses rest.t -- see docs/port/BLOCKED.md. 🔴 THE EXAMPLE THIS CITED IS GONE, THOUGH THE CONCLUSION IS NOT. It read \"`ptlogo1` has rest.t=251 and stops MOVING at t=42\". In the CURRENT export `ptlogo1.rest.t` is 42 -- equal to when it stops moving. The record-layout fix repaired precisely that element, and the entry was never re-derived under it (REFUTED.md now carries this at 🟡 ⟨our-reader⟩). rest.t is still wrong for transients -- `ptlogo_back2eff1` is a two-frame flash whose rest.t=54 is the flash PEAK -- and for `pteff00`, whose rest.t=16 sits at the end of the fade-FROM-black while a fade-TO-black runs 261..269. Re-derived 2026-09-01: docs/port/plate-arrival-halves.md. 🔴 AND IT IS NOT THIS DEFECT'S CAUSE. The plate's ARRIVAL is a declared keyframe (transparent to t=214, opaque at t=236), not a rest pose; rest.t=236 only chooses where `holding` parks it, and 236 is that ramp's own peak. Confirmed on a filmed boot with rest.t untouched: the onset is bracketed within one frame of 214.",
"scope_why": "Attached to the BOOT STEP, not to the `title` screen, and that is deliberate. What was measured is the boot title. Whether the title shows the plate when it is REACHED AGAIN -- by (B) from the main menu, or after the attract movie -- is not measured, and putting the overlay on the screen would quietly claim it is. 📌 SOURCE, added 2026-09-01: the plate belongs to the boot's overlay step rather than to the title screen because its arrival is measured against the boot clock -- docs/re/title-plate-delay-measured.md. 🔴 STALE CLAUSE, CORRECTED 2026-09-01: this said \"Whether the title shows the plate when it is REACHED AGAIN -- by (B) from the main menu, or after the attract movie -- is not measured\". It IS measured now, and has been since 2026-08-30: after (B) from the menu the plate is re-drawn, pressed at 351.2 s with its pulse back at 358.5 s (the Decoder, nav-autorepeat-and-settled-b data). The port re-arms the overlay on arrival at the title by any path, and that is correct. What stayed true is the structural half -- the declaration lives on the boot STEP and is looked up from there, so a screen that gains an overlay gets it on both paths at once. ⚠️ What is STILL not measured is whether the returned plate FADES or appears at once; the 7.3 s between press and pulse is consistent with a transition plus the declared 214->236 fade, but that is consistency, not a measurement of the ramp on this path.",
"no_pulse_why": "The port draws the plate arriving and then holding. It does not pulse it. The RE agent identifies the pulse as the plate's FOCUS RECORD `ptbtn00f` -- a glow ramping 0x00 to 0x50 and back, t=6..105 -- not as a loop of `ptbtn00`'s own group, which was the port's earlier reading and was wrong. Looping that record is a candidate the port has NOT taken: its group is 105 timed units plus an AUTHORED 24-unit exit ramp, and hitting the measured 2.24 s mean requires composing that authored constant with a loop assumption, which is tuning rather than measuring. Filed in BLOCKED.md. 📌 SOURCE, added 2026-09-01: docs/re/structures/plate-pulse-measured.md, and the phase-lock caveat that bounds what a gated capture can show is docs/re/structures/plate-pulse-phase-lock.md."
},
"why": "HANDOFF Q2/Q6: the boot reaches the title after the intro movie. This is the LAST step, and a last step is where the sequence stops rather than fading out -- a boot that ends by fading to black looks like a boot that crashed. P5 gave the title somewhere to go, but that is a HANDOVER and not another boot step: `--boot` still stops here, and `--boot --play` hands the same held title to the menu flow, where (A) opens TITLE_MENU. Kept as a stop rather than folded into `screens` because what the boot does is authored from a measured sequence, and what (A) does is a separate measurement."
}
],
"dwell": {
"_": [
"NOT SET -- because the dwell is DECLARED, and the port already plays it.",
"",
"This key has now been wrong in two opposite directions, and the second was",
"mine, so both are recorded.",
"",
"It first said 'a screen's dwell is its OWN keyframe group'. Then GP_TITLE",
"build 4 was measured dwelling ~1100 presented frames against a declared ~120,",
"and I generalised that into 'the boot is KNOWN TOO FAST [refuted] on both splashes'.",
"🔴 THAT WAS AN OVER-CORRECTION and it is withdrawn. Build 4 is the title: its",
"exit is caused by something outside its timeline, so it holds. A splash's exit",
"is caused by nothing, so it plays its declared timeline and leaves. The title",
"is the exception, not the rule, and one screen was never enough to overturn",
"the other two.",
"",
"MEASURED 2026-08-29 by the Decoder over 3 cold boots",
"(docs/re/structures/boot-splash-dwells-are-declared.md):",
"",
" publisher declared t=0..255 = 4.250 s corpus 4.30 / 4.60 / 4.37",
" developer declared t=0..210 = 3.500 s corpus 3.51 / 3.50 / 3.37",
"",
"The developer agrees to 1.1 %, two of its three runs to 0.3 %. The port emits",
"4.400 s and 3.650 s -- each declared value plus the 9-unit black hold, exactly.",
"So the pacing was right all along and nothing changes in the code.",
"",
"🔴 AND THE UNIT STAYS UNITS, NOT SECONDS. The same two dwells timed in the",
"Decoder's own container came out 15-20 % LONGER than both the declared values",
"and the corpus -- same disc, same timeline -- and three independent readings",
"of that container's rate disagree with each other. A seconds figure records",
"one emulator's pacing on one run. The units are on the disc. If anything ever",
"goes in `dwell` it is an extra hold in UNITS, and only for a screen that is",
"measured to wait beyond its group."
]
},
"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).",
"wrap_kind": "measured",
"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.",
"left_right_kind": "measured",
"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. 📌 WHERE THE ASK LIVES, added 2026-09-01: docs/port/BLOCKED.md carries it, and until now this why said \"ask the RE agent\" without naming where the question is recorded -- a pointer with no destination. An `authored` kind still needs a citation, because the thing to cite is the OPEN QUESTION the choice stands in for; without it, an invented value and a placeholder for a measurement read the same.",
"input_during_transition_kind": "authored",
"auto_repeat": false,
"auto_repeat_why": "MEASURED 2026-08-30, Decoder daf8f47: a 2.0 s held (down) moves the cursor EXACTLY ONCE. Their counter passes its own control first -- a single 0.12 s tap gives exactly 1 spike, the hold gives 1, move spike 0.0202-0.0220 against a 0.0003-0.0038 floor. The port's edge-triggered _input already behaved this way; what changed is that it is now a MEASUREMENT rather than an unexamined consequence of how the handler was written. HANDOFF Q5's 'up / down' row is split at the source: one-item-per-press (evidenced by the 4-press wrap count) from no-auto-repeat (which had nothing until this run).",
"auto_repeat_kind": "measured"
},
"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",
"goto_name_why": [
"NOT MEASURED, and the label says so. HANDOFF Q4 states it exactly: \"the",
"screens are measured; the ids are a name match onto the executable's class",
"names.\" So `TITLE_MENU` is a string that exists in the executable and plausibly",
"denotes this screen -- nothing observed binds it to this transition.",
"",
"It is carried so a reader can search for it and so the port never has to",
"invent one. THE PORT NEVER BRANCHES ON IT: navigation uses `goto`, which is",
"a screen file, and this field is documentation.",
"",
"🔴 THIS `why` DID NOT EXIST UNTIL 2026-08-30. All seven `goto_name_kind`",
"labels rested on a sibling `why` that argues the DESTINATION -- a different",
"claim from where the NAME came from. `tools/port/audit-kinds` reports that",
"as BORROWED rather than ok, because a label resting on a neighbour's",
"argument reads as evidenced and is not."
],
"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 2026-08-30, Decoder daf8f47, docs/re/data/nav-autorepeat-and-settled-b.txt: twenty seconds after a delivery-confirmed B the screen is still the title with PRESS (A) BUTTON up. The run waited for the PLATE PULSE -- the title's own settled signature -- before pressing, which is exactly what the earlier confounded attempt did not. This cell briefly said 'MEASURED, HANDOFF Q5' on no evidence, then said AUTHORED once that was caught; it is now measured for real. Value unchanged throughout: null.",
"on_cancel_kind": "measured"
},
"main_menu": {
"initial_focus": "ptbtn01",
"initial_focus_kind": "measured",
"focus_persists": true,
"focus_persists_kind": "measured",
"focus_persists_why": [
"MEASURED 2026-08-30, Decoder: the main menu REMEMBERS ITS CURSOR across a",
"round trip through the title. (B) out and (A) back returns to the item you",
"left, not to a default. Their control passed first -- two delivery-confirmed",
"DOWNs moved the cursor exactly two items before the round trip, so the",
"cursor demonstrably was not where it started.",
"",
"The port reset to `initial_focus` on every entry, so this was a real defect",
"and not a refinement: a player who moved to EXTRAS, pressed (B), then (A),",
"landed back on NEW GAME.",
"",
"🔴 SCOPED TO THIS SCREEN ON PURPOSE, and the scope is the authored part.",
"The measurement is of the MAIN MENU. Making it a menu-wide rule would be",
"n=1 wearing a rule's clothes -- and here it would actively contradict a",
"measurement, because `extras` opens on MISSION SELECT as a MEASURED initial",
"focus, and a remembered cursor would override it on re-entry. `wrap` is a",
"menu rule because it was measured on two screens; this was measured on one.",
"",
"⚠️ WHAT IS NOT KNOWN: whether the memory survives a return to the BOOT",
"(as opposed to the title), and whether any other screen has it. Ask before",
"widening this.",
"",
"🔴 CORRECTED 2026-08-30, SAME DAY, by the Decoder: the paragraph above argued",
"the scope from `extras` having a MEASURED initial focus that a remembered",
"cursor would override. That is a good reason to be CAUTIOUS and NOT a finding",
"that `extras` resets. Nothing has measured what a submenu's own cursor does on",
"re-entry: the corpus has EXTRAS' opening item from ONE entry, and (B) restoring",
"the PARENT's focus 4/4, and neither answers it.",
"",
"So `focus_persists: false` everywhere else is THE PORT'S DEFAULT, not the",
"game's behaviour. It invents the least and it preserves the one measurement",
"there is. `tools/port/contract-check` asserts only the main-menu half against",
"the contract and reports the scope as a GUARD, because for one iteration it",
"asserted non-persistence as though it had been measured -- which would have",
"held the port to the wrong behaviour and passed while doing it.",
"",
"❔ The Decoder is measuring EXTRAS re-entry now. Do not build on the",
"non-persistence half until it returns.",
"",
"📌 SOURCE, added 2026-09-01 in the uncited-why backfill: docs/re/data/focus-persists-across-title.txt carries the round trip, and docs/re/data/extras-focus-resets.txt carries the contrasting submenu result that keeps this scoped to one screen."
],
"initial_focus_why": [
"MEASURED 2026-08-30 (later) -- `NEW GAME` on a fresh boot, 2/2 fresh boots,",
"both the FIRST menu entry. Decoder, HANDOFF `bf9e07f`, section \"correcting",
"today's focus delivery\"; ring row y=225.5 against a measured 79.25 px step,",
"data in docs/re/data/menu-focus-reader-offset.txt.",
"",
"🔴 THIS FIELD WAS `authored` UNTIL NOW AND THE UPGRADE IS NOT BECAUSE IT",
"AGREES WITH ME. The value did not change; its standing did. The confirmation",
"is a direct reading of a fresh boot's first menu entry, independent of the",
"reasoning that chose NEW GAME here -- and the Decoder had said explicitly that",
"my agreeing with their records was no evidence, which was correct at the time.",
"",
"✅ AND IT SURVIVES A REBOOT -- MEASURED 2026-08-31. Six fresh boots all",
"opened on NEW GAME, and THREE of them followed a session that ended with the",
"cursor on EXTRAS or OPTIONS. That is what makes it a test of persistence",
"rather than six repetitions of the same start.",
"",
"⚠️ REACH, and it is the Decoder's own caveat rather than mine: every one of",
"those sessions ended with the emulator KILLED, not shut down cleanly. A game",
"that writes menu state on a clean exit never gets the chance, so this",
"measures 'does not survive a KILLED session'. If a real console remembers a",
"cursor across a power cycle, that does not contradict this.",
"",
"⚠️ WHY 'FIRST ENTRY' IS LOAD-BEARING: the menu REMEMBERS ITS CURSOR (see",
"`focus_persists`), so any reading not taken on a fresh boot's first entry is",
"measuring HISTORY, not what the screen opens on. That objection is what",
"invalidated the earlier TUTORIAL/NEW GAME disagreement, and this measurement",
"is the one that is immune to it.",
"",
"The superseded reasoning is kept below, because it is what made the wait cheap:",
"the field existed and was labelled honestly, so arriving at a measurement was a",
"label change and not an archaeology problem.",
"",
" (was) 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. CORROBORATED 2026-08-29, and still not decoded: the committed capture live-main-menu.png has NEW GAME focused. Identified by rendering all five focus states and taking the minimum difference -- 531 differing pixels against 6080-7094 for the others, an 11.5x margin -- with the method controlled on live-main-menu-options-focused.png, whose answer is in its filename and which it picks by 4.7x. That means the port's choice matches the state of one committed frame. It does NOT make focus stable: Q5's four boots gave TUTORIAL, TUTORIAL, NEW GAME, NEW GAME, and this identifies one frame rather than a rule. Delete this entry the day something says what SELECTS it. TIGHTENED 2026-08-29: Q5 now has SIX boots, and the shape is sharper than 'unstable' -- TUTORIAL x3, NEW GAME x3, and NO OTHER ITEM EVER OBSERVED. So it is not uniform over five buttons; whatever selects it has to explain a two-way split. That does not change this choice (NEW GAME remains one of exactly two observed states, and it is the state of the committed capture) but it does change what would REFUTE it: a boot opening on LOAD GAME, OPTIONS or EXTRAS would break the two-way shape, and a rule that predicts the split would delete this entry outright.",
" (was) ",
" (was) ✅ CONSISTENT WITH THE ONE CAPTURE, measured 2026-08-30. Rendering each of the",
" (was) five buttons focused against `live-main-menu.png` gives 0.0705 % for ptbtn01",
" (was) and 0.72-0.84 % for the other four -- a 10x discrimination. So that capture",
" (was) shows NEW GAME focused, and the authored choice matches it.",
" (was) ",
" (was) ⚠️ THIS DOES NOT OVERTURN Q5. Q5 measured initial focus as UNSTABLE across",
" (was) four boots; one capture showing ptbtn01 is consistent with that and does not",
" (was) contradict it. What the measurement establishes is narrower and still worth",
" (was) having: the port's focus rendering is distinctive enough that a capture",
" (was) identifies which button is focused, and this authored value is not at odds",
" (was) with the only frame we can check it against. It stays AUTHORED."
],
"on_cancel": {
"goto": "title",
"goto_name": "TITLE_SCREEN",
"goto_name_kind": "name match, not measured",
"goto_name_why": [
"NOT MEASURED, and the label says so. HANDOFF Q4 states it exactly: \"the",
"screens are measured; the ids are a name match onto the executable's class",
"names.\" So `TITLE_SCREEN` is a string that exists in the executable and plausibly",
"denotes this screen -- nothing observed binds it to this transition.",
"",
"It is carried so a reader can search for it and so the port never has to",
"invent one. THE PORT NEVER BRANCHES ON IT: navigation uses `goto`, which is",
"a screen file, and this field is documentation.",
"",
"🔴 THIS `why` DID NOT EXIST UNTIL 2026-08-30. All seven `goto_name_kind`",
"labels rested on a sibling `why` that argues the DESTINATION -- a different",
"claim from where the NAME came from. `tools/port/audit-kinds` reports that",
"as BORROWED rather than ok, because a label resting on a neighbour's",
"argument reads as evidenced and is not."
],
"kind": "measured",
"why": "MEASURED 2026-08-30, delivery-confirmed (B = 0x5801), 73.5 % of pixels changed, and both captures name themselves. Latency <= 0.4 s and NO loading screen in between, which matters because the disc carries four pgloading_* screens. This entry previously read 'likely but UNPROVEN': it had been seen once without a capture, and the title ALSO returns on its own after ~8-10 s idle, so an observer could not tell a response from a timeout. The <= 0.4 s latency is what kills that confound -- it is twenty times faster than the idle return. Decoder 86a8ce7, menu-navigation-semantics.md row 'B on the main menu', docs/re/data/b-on-main-menu.txt."
},
"buttons": {
"ptbtn01": {
"label": "NEW GAME",
"goto": null,
"goto_name": "DLG_SELECT_DIFFICULTY",
"goto_name_kind": "name match, not measured",
"goto_name_why": [
"✅ CORRECTED 2026-08-31: this read `DIFFICULTY`, and the destination is a",
"DIALOG rather than a GamePart -- `DLG_SELECT_DIFFICULTY`, `GP_DIALOG.pak`",
"entries 2/3 [see the withdrawal below]. Decoder, TWO arguments [corrected below]; the geometry one is",
"re-derived here with this port's own reader: entries 2 and 3 are the ONLY",
"builds in that archive carrying `pcbtn00`-`pcbtn03`, at design rows",
"259/329/399/469, spacing exactly 70. See",
"`crates/sylpheed-export/examples/dialog_rows.rs`.",
"",
"🔴 SO THE FOUR EXTERNAL DESTINATIONS ARE NOT UNIFORM: three open GameParts",
"and this one opens a dialog. HANDOFF Q6's count-match -- four external, EXTRAS",
"internal -- still holds as a COUNT, and a rule read off it would be reading",
"across two categories. The Decoder sent that count with disc support",
"yesterday and weakened it themselves today; recorded at the weaker strength.",
"",
"✅ THE REACH IS NOW BOUNDED -- 2026-08-31, and both agents scanned for it.",
"",
"It read: \"another four-button dialog with the same rows would be",
"indistinguishable by this evidence\". The Decoder searched every build in",
"every pak for four buttons within 6 px of those rows and found ZERO rivals.",
"Re-run here with this port's reader and a BROADER filter -- any element",
"whose name contains `btn`, not only `pcbtn`, so a rival under a different",
"naming convention would still be caught: 2 859 builds across 33 paks,",
"EXACTLY 2 matches, entries 2 and 3. The run carries its own known positive:",
"fewer than 2 would mean the reader cannot see the incumbents and its zero",
"would mean nothing.",
"",
"✅ And the name is now backed by a TABLE ENTRY rather than an inference",
"from a string list: every `DLG_` name in the image sits in a 12-byte record",
"(id, name pointer, handler [corrected]) spanning 0x820A0A2C-0x820A0D68 -- 70 names,",
"70 records, none unmatched. `DLG_SELECT_DIFFICULTY` is **id 2000**.",
"",
"🔴 \"THREE INDEPENDENT ROUTES\" CORRECTED TO TWO -- 2026-08-31, by the Decoder,",
"and I had relayed the count unchecked for the second time from one delivery.",
"",
"The image leg says DIFFICULTY is a dialog and names no entry, so alone it",
"identifies nothing. The disc and oracle legs are ONE COMPOUND ARGUMENT: the",
"capture is compared against the disc's rows. What makes that discriminating is",
"the EXCLUSION SCAN -- zero rivals within 6 px anywhere on the disc -- and that",
"is what the word \"three\" was taking credit for. The conclusion is unchanged;",
"the evidence is two arguments, one of them compound, and was never three.",
"",
"📌 The test that falls out of it, theirs: ask of an n-routes claim not whether",
"the routes are correct but whether ANY COULD HAVE COME OUT DIFFERENTLY GIVEN",
"THE OTHERS. That is an exclusion argument, and it is usually absent.",
"",
"🔴 WITHDRAWN 2026-08-31 -- \"AN EN/JP PAIR\", AND I RELAYED IT.",
"",
"The Decoder stated entries 2/3 as a language pair in the same HANDOFF row that",
"identifies DIFFICULTY, as a fact, and has withdrawn it: nothing established the",
"pairing. I copied it into this `why` -- twice -- in the SAME SENTENCE where I",
"was careful to say my re-derivation confirms the geometry and does not name the",
"screen. The unchecked half rode along inside the clause I had checked.",
"",
"What the scan actually shows is that adjacent GP_DIALOG entries are UNRELATED",
"DIALOGS: 26 of 65 adjacent pairs differ in BUTTON COUNT, which no language pair",
"can. Identical element sets is the language signature in GP_TITLE; here it is",
"equally consistent with a duplicate. So `2/3` are two builds with the same four",
"buttons at the same rows, and calling them EN and JP is an assumption.",
"",
"⚠️ THE IDENTIFICATION DOES NOT REST ON IT -- unique four-button geometry with",
"zero rivals disc-wide, plus the oracle capture. The pairing was decoration on a",
"conclusion that stands without it, which is exactly why it travelled unchecked.",
"",
"✅ RESTORED 2026-08-31, ON A MEASUREMENT RATHER THAN A RELAY. The Decoder took",
"the `ja` capture of DIFFICULTY that was missing and 2/3 ARE English/Japanese:",
"EN vs JP differ in 1.82 % of pixels in FOUR BANDS AND NOWHERE ELSE -- the",
"heading (DIFFICULTY -> the JP heading), the ring by 2 px, the BACK label, and",
"the footer. EASY/NORMAL/HARD are NOT in the differing set: the Japanese release",
"leaves the three difficulty names in Latin script, which is why the disc figure",
"is only 2.77 % of bytes against 1.82 % of pixels.",
"",
"📌 MY OBJECTION WAS NOT WRONG AND IS NOT WITHDRAWN. It was that IDENTICAL",
"ELEMENT SETS DO NOT IMPLY A LANGUAGE PAIR -- 26 of 65 adjacent pairs differ in",
"button count, so adjacency proves nothing. That argument still holds; what has",
"changed is that the conclusion now rests on a direct locale capture instead of",
"on that inference. A bad argument for a true claim is still a bad argument, and",
"the claim was correctly out of this file until somebody went and looked.",
"",
"⚠️ REACH, THEIRS: one JP boot, one screen, does not generalise. GP_TITLE 4/7 is",
"known to differ by MORE than text -- entry 7 carries nine sprites entry 4 lacks.",
"Nothing in the port keys off locale today; this is recorded, not consumed.",
"",
"🔴 RECORD LAYOUT CORRECTED 2026-09-01, and I had copied the wrong one. I wrote",
"\"(handler, id, name pointer)\"; it is {id, name_ptr, handler} -- the same three",
"fields shifted one word, so every record was being credited with the PREVIOUS",
"record's handler. The Decoder caught it with a control dump: under the old",
"alignment record 0 had a handler of 0x10000000, which is not a code address.",
"ids and names are unaffected and DLG_SELECT_DIFFICULTY is still 2000, so",
"nothing here moves except the sentence.",
"",
"📌 FOURTH aside of theirs relayed into this file. The first three were an EN/JP",
"pairing, a leg count and an independence claim -- all decorative. This one is a",
"STRUCTURE, which is worse: a wrong field order is the kind of thing a later",
"reader builds on, and it carried no weight here only by luck.",
"",
"❔ AND THE JOIN IS NOT REACHABLE BY THAT ROUTE -- their negative, with their",
"reach. All three handlers load the same global at 0x828E2B14 and take addresses",
"at 0x828E45E0/4640/467C, every one inside a 364 601-byte contiguous zero run:",
"BSS, populated only at runtime. Controlled, because an all-zero read is also",
"what a wrong address gives, and the dialog table itself reads non-zero through",
"the same arithmetic.",
"",
"⚠️ That closes the DIALOG HANDLERS, not the image. The archive loader and any",
"id-keyed table elsewhere are unexamined, so \"not in the image\" is NOT",
"established. Recorded as a route rather than an answer, which is how they sent",
"it.",
"",
"❔ STILL UNBOUND, and it is what would make this airtight: nothing connects",
"id 2000 to a pak entry. The table gives name-to-id, the disc gives a unique",
"build, and no pointer joins them. The tie is UNIQUENESS PLUS THE ORACLE",
"CAPTURE, not a binding -- so if a rival build ever appeared, this",
"identification would go with it.",
"",
"button count and geometry, NOT by a binding from the `DLG_` name to a pak",
"entry. No such binding was found. Another four-button dialog with the same",
"rows would be indistinguishable by this evidence -- my re-derivation",
"confirms the geometry and does not name the screen.",
"",
" (was) NOT MEASURED, and the label says so. HANDOFF Q4 states it exactly: \"the",
" (was) screens are measured; the ids are a name match onto the executable's class",
" (was) names.\" So `DIFFICULTY` is a string that exists in the executable and plausibly",
" (was) denotes this screen -- nothing observed binds it to this transition.",
" (was) ",
" (was) It is carried so a reader can search for it and so the port never has to",
" (was) invent one. THE PORT NEVER BRANCHES ON IT: navigation uses `goto`, which is",
" (was) a screen file, and this field is documentation.",
" (was) ",
" (was) 🔴 THIS `why` DID NOT EXIST UNTIL 2026-08-30. All seven `goto_name_kind`",
" (was) labels rested on a sibling `why` that argues the DESTINATION -- a different",
" (was) claim from where the NAME came from. `tools/port/audit-kinds` reports that",
" (was) as BORROWED rather than ok, because a label resting on a neighbour's",
" (was) argument reads as evidenced and is not."
],
"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.",
"skipped_chain": [
"DIFFICULTY",
"SELECT DATA"
],
"skipped_chain_why": "THE PORT SKIPS TWO MEASURED SCREENS HERE, AND IT SAYS SO OUT LOUD RATHER THAN PRETENDING. The real chain is NEW GAME -> DIFFICULTY -> SELECT DATA -> (A) on a save slot -> ~4.5 s -> S00A. DIFFICULTY and SELECT DATA are MEASURED destinations (HANDOFF Q4) but neither is a GP_TITLE build, so there is no screen file to go to. The port jumps from NEW GAME to the one thing in that chain it has, and the runtime prints what it skipped on every run. This is a GAP, not a sequence: nobody may read the port's behaviour here as what the game does.",
"skipped_chain_kind": "measured",
"then_video": "S00A",
"then_video_why": "P7. HANDOFF Q9, DECODED from the movie manifest: MS00A -> S00A.wmv is the new-game intro, 93.9 s. Its POSITION is measured as well -- the movie starts ~4.5 s after (A) on the save slot, matched off the running game at 0.96-1.000 with a strictly monotone playhead over 25 consecutive 0.5 s samples.",
"then_video_kind": "decoded",
"unobserved_why": "WHAT FILLS THE ~4.5 s between the save slot and the movie is NOT KNOWN. The oracle run that would have shown it hit the already-documented sub_823070B0 cache crash after SELECT DATA. GP_TITLE does carry a LOADING screen -- entries 0/1 and 12/15, whose elements are every one of them named pgloading_* -- and LOADING is in the game's own screen vocabulary, but nobody has watched it appear here and the port does NOT put it in the chain on that basis. 📌 WHERE THE OPEN QUESTION LIVES, added 2026-09-01: docs/port/BLOCKED.md carries the row -- 'what fills the 4.5 s before S00A'. An explicit unknown still needs a citation, or it cannot be distinguished from an unexamined one.",
"skippable": true,
"skippable_why": "HANDOFF Q9, MEASURED: one (A) press skips a movie -- the title was reached at 57 s against a 193 s baseline. Same rule the boot intro already uses.",
"skippable_kind": "measured",
"after_video": {
"goto": "title",
"kind": "authored",
"why": "AUTHORED, and it has to be: the game goes into MISSION 1, and gameplay is out of scope (PORT-MISSION section 7). P7's gate asks for 'plays, then returns to a defined state' -- this is that state. The title is chosen over the main menu because the boot's own end state is the title, so a run that finishes the new-game intro lands somewhere a player can start again from. Nothing measured says the game does this."
}
},
"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",
"goto_name_why": [
"NOT MEASURED, and the label says so. HANDOFF Q4 states it exactly: \"the",
"screens are measured; the ids are a name match onto the executable's class",
"names.\" So `TUTORIAL_MENU` is a string that exists in the executable and plausibly",
"denotes this screen -- nothing observed binds it to this transition.",
"",
"It is carried so a reader can search for it and so the port never has to",
"invent one. THE PORT NEVER BRANCHES ON IT: navigation uses `goto`, which is",
"a screen file, and this field is documentation.",
"",
"🔴 THIS `why` DID NOT EXIST UNTIL 2026-08-30. All seven `goto_name_kind`",
"labels rested on a sibling `why` that argues the DESTINATION -- a different",
"claim from where the NAME came from. `tools/port/audit-kinds` reports that",
"as BORROWED rather than ok, because a label resting on a neighbour's",
"argument reads as evidenced and is not."
],
"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",
"goto_name_why": [
"NOT MEASURED, and the label says so. HANDOFF Q4 states it exactly: \"the",
"screens are measured; the ids are a name match onto the executable's class",
"names.\" So `EXTRA_MENU` is a string that exists in the executable and plausibly",
"denotes this screen -- nothing observed binds it to this transition.",
"",
"It is carried so a reader can search for it and so the port never has to",
"invent one. THE PORT NEVER BRANCHES ON IT: navigation uses `goto`, which is",
"a screen file, and this field is documentation.",
"",
"🔴 THIS `why` DID NOT EXIST UNTIL 2026-08-30. All seven `goto_name_kind`",
"labels rested on a sibling `why` that argues the DESTINATION -- a different",
"claim from where the NAME came from. `tools/port/audit-kinds` reports that",
"as BORROWED rather than ok, because a label resting on a neighbour's",
"argument reads as evidenced and is not."
],
"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",
"focus_persists": false,
"focus_persists_kind": "measured",
"focus_persists_why": [
"MEASURED 2026-08-30 -- EXTRAS RESETS. HANDOFF `4ed75e6`: ring back to",
"y=347.5 on re-entry after a confirmed DOWN, frame 0.0 % different from the",
"first entry, and the screen confirmed by eye as EXTRAS because an earlier",
"run was fooled about which screen it was on.",
"",
"📌 WRITTEN EXPLICITLY, THOUGH THE PORT'S DEFAULT IS ALREADY false. The",
"absent key and the measured false behave identically and mean completely",
"different things: one is 'nobody looked', the other is 'the game was",
"watched doing it'. `tools/port/audit-kinds` can see the second and not the",
"first, which is the whole reason for spending a key on it.",
"",
"🔴 AND THIS IS NOT A VINDICATION OF HOW IT GOT HERE. For one iteration the",
"port ASSERTED non-persistence for EXTRAS in `contract-check` while nothing",
"had measured it; the Decoder flagged that, and it turned out right. Being",
"right by luck does not retroactively make it evidence -- declining to",
"generalise the memory was the correct move, and encoding 'not measured",
"here' as a positive claim was a different and wrong one that happened to",
"land. The measurement is what makes it true; the assertion never did.",
"",
"⚠️ Do NOT generalise in either direction: main_menu persists, EXTRAS resets,",
"and OPTIONS / LOAD GAME / TUTORIAL are untouched."
],
"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.",
"",
"",
"✅ CAVEAT LIFTED 2026-08-30 -- MEASURED, not a single-entry reading any more.",
"HANDOFF `4ed75e6`, docs/re/data/extras-focus-resets.txt: EXTRAS opens at ring",
"y=347.5 on MISSION SELECT, moves to 427.5 after one delivery-confirmed DOWN,",
"and returns to 347.5 on re-entry with the frame 0.0 % different from the first",
"entry. Because this screen RESETS, a single-entry reading of it is not",
"measuring history -- which is precisely what made the caveat necessary while",
"persistence here was unknown.",
"",
"✅ THE AMBIGUITY IS RESOLVED -- MEASURED 2026-08-31, and it went the way",
"that makes `ptbtn11` right for a REASON rather than by coincidence.",
"",
"A submenu resets to ITS OWN OPENING ITEM, and that item is a per-screen",
"default which need NOT be the first. Decoder, docs/re/data/",
"difficulty-resets-to-named-item.txt: DIFFICULTY opens on NORMAL (second of",
"four); after one confirmed DOWN to HARD, (B) out and (A) back returns to",
"NORMAL -- in-cursor 1.0 from where it opened against 93.9 from where it was",
"left. Reproduced on a FRESH BOOT and confirmed by eye, not read off the",
"2026-08-29 capture.",
"",
"So the port's `initial_focus` is the reset target, and `buttons[0]` in",
"`MenuFlow.initial_focus` is a REPAIR rather than a default -- which is how",
"it was already documented, and is now measured rather than principled.",
"",
"❔ STILL OPEN, and not leaned on: whether the reset target MOVES once a",
"difficulty has actually been confirmed. A game that remembered your last",
"choice would behave differently, and the probe never confirms one -- the",
"same SELECT DATA crash that constrains the run prevents testing it.",
"",
"",
"🔴 CORRECTED 2026-08-31. This read \"it matters IF another screen is ever",
"authored\" whose opening item is not its first. Such a screen exists and is",
"recorded IN THIS FILE: DIFFICULTY, under `main_menu/buttons/ptbtn01`, is",
"EASY/NORMAL/HARD/BACK and opens on NORMAL -- the SECOND of four. Measured:",
"driven with no d-pad, unchanged for 90 s, matching the committed capture at",
"r=+0.999 (Decoder, docs/re/captures/newgame-path/newgame-difficulty.png).",
"",
"So \"a screen opens on its first item\" is REFUTED as a general description of",
"this game. On EXTRAS, TUTORIAL and OPTIONS the named item and the top item",
"coincide BY ACCIDENT. A top-item rule would be wrong on DIFFICULTY.",
"",
"nobody can separate \"resets to MISSION SELECT\" from \"resets to the TOP ITEM\".",
"They coincide here -- ptbtn11 is both. The port's value is correct under either",
"reading, and the REASON is not established.",
"",
"The superseded caveat is kept below.",
" (was) ⚠️ WEAKENED 2026-08-30 -- the OBSERVATION stands, its reading as an INITIAL",
" (was) focus does not. It was taken on a single entry. Now that the main menu is known",
" (was) to remember its cursor across a round trip, a one-entry reading of any screen",
" (was) may be measuring HISTORY rather than what the screen opens on -- the same",
" (was) objection that reframed the main menu's TUTORIAL/NEW GAME disagreement.",
" (was) ",
" (was) Kept as `measured` because the frame really does show MISSION SELECT focused,",
" (was) and kept as the port's opening item because it is the only reading there is.",
" (was) 🔴 If EXTRAS turns out to persist, this becomes history and the kind must",
" (was) change with it.",
"",
"🔴 CHECKED AGAINST THE BYTES 2026-08-31 by both agents -- and NOT independently.",
"Settled by fact, not by my inference: the Decoder's 282/362/442 came from",
"`crates/sylpheed-formats/examples/extras_button_order.rs`, which calls",
"`ui_layout::parse_build` -- THE SAME CRATE this port's export uses. The",
"Python RATC parsers in their tree exist and did not produce that number.",
"So the two legs are ONE READER USED TWICE, and the agreement carries no",
"information about the reader being right; it carries information only about",
"two callers of it agreeing, which they could not fail to do.",
"",
"⚠️ The VALUE is unaffected -- `ptbtn11` is decided by the DIFFICULTY",
"measurement and by the reset finding. What died is a word I used about the",
"evidence, which is the third such word in three iterations.",
"",
"is WEAKENED, by my own audit rather than by theirs.",
"",
"Applying their test to my own sentence: could my reading have come out",
"differently given theirs? Only if the implementations differ. Mine is",
"`sylpheed_formats::ui_layout::parse_build` via this port's export. Their tree",
"does carry separate Python RATC parsers (`kf_record_census.py` and others),",
"so a second implementation EXISTS -- but which reader produced their",
"282/362/442 is not established by me, and if they used the same crate the",
"two legs are one reader used twice.",
"",
"So: the values agreeing is still evidence, and calling it INDEPENDENT was a",
"claim about their tooling that I did not check. Recorded at the strength I",
"can support. ⚠️ Nothing rests on it -- the row order is also decided by the",
"DIFFICULTY measurement -- which is exactly why it went unexamined.",
"",
"Decoder attempted to refute this value and it survives: `ptbtn11` is the TOP",
"button on this screen -- y 282 against 362 and 442 -- so the port is right",
"whichever reading of the reset target applies. Confirmed from THIS port's own",
"export, a different reader of the same disc: extras 282/362/442, and the main",
"menu as a control at 162/242/322/401/482.",
"",
"🔴 WHICH ALSO MEANS EXTRAS CANNOT SEPARATE the two readings -- named item and",
"top item coincide here. It was DIFFICULTY, opening on its second of four, that",
"settled it."
],
"on_cancel": {
"goto": "main_menu",
"goto_name": "TITLE_MENU",
"goto_name_kind": "name match, not measured",
"goto_name_why": [
"NOT MEASURED, and the label says so. HANDOFF Q4 states it exactly: \"the",
"screens are measured; the ids are a name match onto the executable's class",
"names.\" So `TITLE_MENU` is a string that exists in the executable and plausibly",
"denotes this screen -- nothing observed binds it to this transition.",
"",
"It is carried so a reader can search for it and so the port never has to",
"invent one. THE PORT NEVER BRANCHES ON IT: navigation uses `goto`, which is",
"a screen file, and this field is documentation.",
"",
"🔴 THIS `why` DID NOT EXIST UNTIL 2026-08-30. All seven `goto_name_kind`",
"labels rested on a sibling `why` that argues the DESTINATION -- a different",
"claim from where the NAME came from. `tools/port/audit-kinds` reports that",
"as BORROWED rather than ok, because a label resting on a neighbour's",
"argument reads as evidenced and is not."
],
"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",
"goto_name_why": [
"NOT MEASURED, and the label says so. HANDOFF Q4 states it exactly: \"the",
"screens are measured; the ids are a name match onto the executable's class",
"names.\" So `TITLE_MENU` is a string that exists in the executable and plausibly",
"denotes this screen -- nothing observed binds it to this transition.",
"",
"It is carried so a reader can search for it and so the port never has to",
"invent one. THE PORT NEVER BRANCHES ON IT: navigation uses `goto`, which is",
"a screen file, and this field is documentation.",
"",
"🔴 THIS `why` DID NOT EXIST UNTIL 2026-08-30. All seven `goto_name_kind`",
"labels rested on a sibling `why` that argues the DESTINATION -- a different",
"claim from where the NAME came from. `tools/port/audit-kinds` reports that",
"as BORROWED rather than ok, because a label resting on a neighbour's",
"argument reads as evidenced and is not."
],
"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."
}
}
}
}
}

172
authored/rendering.json Normal file
View File

@@ -0,0 +1,172 @@
{
"format": "sylpheed.rendering/1",
"_": [
"WHICH decoded rules the runtime applies where. AUTHORED because it is a",
"choice about the REACH of somebody else's decode, not about the disc.",
"Delete an entry the day the decode covers the case outright.",
"",
"The exporter flags `leaf_carries_geometry` on 15 elements -- those whose",
"nested `.rat` leaf declares a scale or rotation the parent does not. That",
"flag is a CENSUS FACT and it is emitted for all 15. What is DECODED is",
"narrower: the Decoder fitted the game's own composed alpha (per-draw vertex",
"colours C3FFFFFF / B6FFFFFF = 195 and 182) against the ptloop leaves and got",
"one consistent time, then PREDICTED the quad centres to ~11 px. That covers",
"`ptloop01` and `ptloop02` and nothing else."
],
"draw_leaf_for": [
"ptloop01",
"ptloop02"
],
"draw_leaf_why": [
"The two the decode covers. `docs/re/structures/ui-leaf-vs-parent-alpha.md`.",
"",
"NOT DRAWN, though the exporter flags them and ships their data:",
"",
" `title_jp/ptlogo_eff2` -- OUT OF SCOPE, which is a better reason than",
" the caution this entry first gave. MISSION section 7 scopes out",
" 'localisation beyond English', and this element exists only on the",
" Japanese title. So it is not a thing the menu port has to answer, and the",
" parked Japanese-locale capture does not need reviving on its account --",
" that is the human's call and not something either agent widens quietly.",
"",
" It is ALSO undecidable here even if it were in scope. Its 125% is a POP,",
" not a steady scale: scale-0 -> 125% -> scale-0 between t=50 and t=107,",
" about 0.95 s. The leaf draws at 100%, as two superimposed copies at alpha",
" 160 and 80, each rotating 360 degrees over 960 units -- 16 s a turn. If",
" parent scale gates the leaf it is a 0.95 s flash; if the leaf runs free it",
" spins for 16 s. Nothing on the disc chooses and title_jp has no oracle",
" capture.",
" `build_12,15/pgloading_loop5` -- STILL NOT DRAWN, but the reason given here",
" was WRONG and is replaced. It read \"leaf scale (0,0). A zero scale is one of",
" the three historical failures this corpus names\" -- which describes t=0 and",
" t=30 and nothing after them.",
"",
" What the leaf actually holds, read out of the export: ONE element,",
" `pgloading_ring`, with a sprite, whose scale ramps 0 -> 250 -> 800 -> 1000",
" while its alpha rises to full at t=55 and falls to nothing by t=130. An",
" expanding, fading ring -- a loading pulse, not a degenerate record.",
"",
" 🔴 And it is VISIBLE at the instant this port poses. `build_12`'s settle",
" window is [40, 48], so the pose lands near t=44, where the ring interpolates",
" to scale 140 at alpha 143. So withholding it is not declining to draw",
" nothing; it is declining to draw something, and the old reason hid that.",
"",
" It stays withheld on the reason below, which is the one that always applied:",
" there is no way to adjudicate it here. The loading screens have no oracle",
" capture -- the RE agent records them as not reachable from the title path --",
" and `verify-screen` compares against a renderer that draws no leaves at all.",
" Drawing it would put unadjudicable content on a screen, which is the same",
" test `ptlogo_eff2` fails.",
"",
"AND THERE IS NO WAY TO ADJUDICATE EITHER HERE. `title_jp` has no oracle",
"capture, and `verify-screen` compares against `sylpheed-cli`, which does not",
"draw leaves at all -- so ANY leaf drawing increases that divergence whether",
"it is right or wrong. Its max went 155 -> 232 when they were drawn, and that",
"number is not evidence in either direction.",
"",
"What deletes this list: a decode covering those cases, or an oracle capture",
"of title_jp."
],
"draw_leaf_kind": "decoded",
"loop_leaf_on_screens": [
"title"
],
"loop_leaf_why": [
"WHICH screens replay a leaf's group instead of letting it run once and park.",
"MEASURED on the title, UNRESOLVED on the menus, so it is scoped to the title.",
"",
"The disc gives one pass: ptloop01's leaf runs t=0..600 and ptloop02's t=0..720,",
"each ending parked off-screen at x=1521 / -839. The port ran them once.",
"",
"THE ORACLE SAYS THEY LOOP ON THE TITLE. Across two title dwells the sweep quad",
"oscillates over its whole x range and resets hard to the same start value --",
"one reset inside the first dwell, two inside the second. A run-once-and-park",
"shows one traverse and then a constant x.",
"",
"🔴 THE LOOP-LENGTH FIELD CANNOT SETTLE THIS, and I had hoped it would.",
"`ptloop01` declares 600 with keyframes to exactly 600; `ptloop02` declares 720",
"to 720. SLACK ZERO -- and 'loops at 600' and 'runs once for 600 and stops'",
"write the identical header. 92.3% of records on the disc are in that state, so",
"the field discriminates loop length only where there IS slack, as the plate's",
"105-in-120 had.",
"",
"⚠️ THE MENUS ARE NOT COVERED, on purpose. Both declare the same 600/720, so",
"nothing on the disc distinguishes them -- but the oracle measurement is of the",
"title, and my own weak evidence points the other way for the menu: sweeping the",
"phase against live-main-menu.png, the port matches best with the sweeps",
"OFF-SCREEN (0.061%) and three times worse mid-screen (0.183%). If they looped",
"with a 600-unit period the sweep is on screen for roughly 73% of the cycle, so",
"a capture showing none is not nothing -- but it is one capture, and 'best",
"match' is a weak instrument for an absence. Two weak signals in opposite",
"directions is a reason to scope, not to pick.",
"",
"What settles the menu: a direct capture of it, which the Decoder has offered.",
"",
"🔴 RE-MEASURED 2026-08-31, BECAUSE THE EVIDENCE ABOVE WAS TAKEN WITH THE WRONG",
"BLEND. The phase sweep that produced '0.061 % off-screen, 0.183 % mid-screen'",
"drew the sweeps ALPHA-OVER. They are additive -- measured off the running game",
"the same day (`additive_elements`) -- so an on-screen sweep composited the wrong",
"way was being scored against the capture, and 'mid-screen is worse' could have",
"been an artefact of my own compositing rather than of the sweeps being absent.",
"",
"Re-run with additive sweeps and looping switched on for the menu, against",
"`live-main-menu.png`:",
"",
" phase 0 0.0208 % sweeps paint 0 px -- off screen",
" phase 150 0.0851 % sweeps paint 58 027 px, bbox 884x720",
" phase 300 0.0205 % sweeps paint 0 px -- off screen",
" phase 75 / 225 / 375 / 450 / 525: 0.086..0.122 %",
" run-once-and-park, which is what the port ships: 0.0208 %",
"",
"✅ THE CONCLUSION HELD AND GOT STRONGER. The ratio was 3x with the wrong blend",
"and is 4-6x with the right one, and the absolute numbers improved everywhere.",
"The capture still matches best with the sweeps NOT VISIBLE. So this entry stays",
"scoped to the title, and the correction is recorded rather than the scoping",
"changed.",
"",
"⚠️ It is still one capture and 'best match' is still a weak instrument for an",
"absence -- that caveat is not repaired by fixing the blend, only cleared of one",
"confound.",
"",
"📌 AND THE NEW DRAW LOG DOES NOT SETTLE IT EITHER, though it looks like it",
"should. `docs/re/captures/ui-draws/blend-main-menu-2026-08-31.log` shows both",
"sweep strips SUBMITTED on the main menu, in every frame group. That is not",
"evidence they animate there: a quad parked off-screen at x=1521 is still a draw",
"call. A DRAW IS NOT A VISIBLE ELEMENT, and reading that log as 'the sweeps run",
"on the menu' would have contradicted the pixels for no reason."
],
"loop_leaf_kind": "measured",
"additive_elements_deleted_why": [
"✅ DELETED 2026-09-01, and the deletion is the point.",
"",
"This held `additive_elements`, a per-screen list of element ids transcribed",
"from the Decoder's per-draw RB_BLENDCONTROL0 log. PORT-MISSION section 3: 'When",
"the RE agent later decodes something you had authored, delete the authored",
"entry and let the exporter emit it. That deletion is the measure of progress.'",
"",
"The blend is now DECODED -- `T8aD +0x04` bit 0x02, docs/re/structures/",
"ui-blend-mode-decoded.md -- and reachable since formats-pin-2026-09-01 exposed",
"`ui_layout::sprite_blend_additive` and `blend_additive_by_name`. The exporter",
"emits `blend_additive` per element and per nested focus/leaf element, and",
"ScreenView reads it there.",
"",
"🔴 CHECKED BEFORE THE SWAP, and the map turned out to be a SUBSET rather than",
"the answer. Over main_menu, extras, press_start and title:",
"",
" 15 the map called additive AND the disc agrees",
" 0 the map called additive and the disc does not <- no contradictions",
" 17 the disc calls additive and the map did not",
"",
"So nothing transcribed was wrong; it was incomplete, and was being read as",
"complete. The 17 include `pteff03`/`pteff03a` -- the sweep LEAVES, which are",
"what `draw_leaf_for` actually puts on screen while the map listed their parents",
"`ptloop01`/`ptloop02` -- and TWELVE on `title`, where this map was deliberately",
"empty and the port therefore drew every title effect alpha-over.",
"",
"A name-keyed map can only answer for a screen somebody drove the game to. That",
"is what made the Japanese menus an open question (BLOCKED.md H6): the port drew",
"main_menu additive and main_menu_jp alpha-over, asserting by omission that the",
"JP build blends differently. The bit is on the disc for every screen at once, so",
"that asymmetry is now answered statically and H6 needs no capture."
]
}

View File

@@ -1,94 +1,94 @@
{
"format": "sylpheed.screen_names/1",
"_": [
"Which GP_TITLE pak entry is which screen. AUTHORED: the disc does not name its",
"builds, so every name here is a decision. The identifications come from",
"HANDOFF Q2 (ui-title-build-map.md), which measured them against framebuffer",
"captures of the running game; the exporter stamps the name into the screen",
"file with name_source: \"authored\" so a reader can tell a recovered name from",
"an invented one.",
"",
"KEYED BY PAK ENTRY INDEX, not by the enumeration ordinal. It used to be the",
"ordinal; widening the enumeration to reach the splash renumbers ordinals, and",
"a name that moves when the enumeration rule changes is not a name. The entry",
"was always described here as the stronger locator -- now it is the only",
"stable one.",
"",
"Delete an entry here the day the RE agent decodes a name field."
],
"archives": {
"dat/GP_TITLE.pak": {
"2": {
"name": "press_start",
"why": "HANDOFF Q2: builds 2/3 are the PRESS (A) BUTTON plate -- a build of its own, composited over the title and faded in a beat later. English of the EN/JP pair. Measured against a live capture."
},
"3": {
"name": "press_start_jp",
"why": "HANDOFF Q2: the Japanese twin of build 2. Out of scope for this milestone; named so it is not mistaken for a screen we need."
},
"4": {
"name": "title",
"why": "HANDOFF Q2: build 4 is the English title art. Measured against a live capture."
},
"5": {
"name": "main_menu",
"why": "HANDOFF Q2: builds 5/8 are the five-button main menu; 5 is English. Measured against a live capture. (An earlier reading called 8 a submenu and was withdrawn -- 8 is the Japanese main menu.)"
},
"6": {
"name": "extras",
"why": "HANDOFF Q2: builds 6/9 are the EXTRAS submenu, the only submenu inside this archive. Measured against a fresh EXTRAS capture."
},
"7": {
"name": "title_jp",
"why": "HANDOFF Q2: the Japanese twin of build 4."
},
"8": {
"name": "main_menu_jp",
"why": "HANDOFF Q2: the Japanese twin of build 5."
},
"9": {
"name": "extras_jp",
"why": "HANDOFF Q2: the Japanese twin of build 6."
},
"10": {
"name": "publisher_logo",
"why": "The SQUARE ENIX PUBLISHER wordmark -- the FIRST thing the boot sequence shows, before the developer logos. Measured by the RE agent 2026-08-29, render grid at docs/re/captures/title-builds/splash-both-halves-rendered.png. Entries 10/13 are region twins distinguished by the trademark glyph; 10 carries the (TM)."
},
"13": {
"name": "publisher_logo_r",
"why": "The region twin of entry 10, carrying (R) where 10 carries (TM). Named so it is not mistaken for a second screen the boot path needs."
},
"11": {
"name": "developer_logos",
"why": "The GAME ARTS / SETA / studio anima logos -- the developer splash, shown after the publisher wordmark. HANDOFF Q2 and the RE agent's 2026-08-29 render grid; draws 7/7 elements."
},
"14": {
"name": "developer_logos_r",
"why": "The region twin of entry 11, as 13 is to 10."
}
}
},
"unnamed": {
"dat/GP_TITLE.pak": "Entries 0/1 and 12/15 are plates never seen running -- not in the boot path, not on any title-side screen, not in the attract loop (HANDOFF Q2). They export under their entry index rather than a name we would be inventing."
},
"also_export": {
"dat/GP_TITLE.pak": {
"10": {
"name": "publisher_logo",
"why": "LOCATED BY ENTRY INDEX, not by a rule. These four bundles declare their sprites directly and have no .rat layout child, so `is_build` cannot see them -- and the RE agent established that NO content rule can: design size fails (every extra composable bundle sampled is 1280x720, the same as every screen) and element count fails (fragments run 2..15 elements in GP_OPTIONS/GP_SAVE_LOAD while these are 3 and 7 -- the ranges overlap). Safe here and not in general: in GP_TITLE the widened set adds exactly these four and all four are real screens, zero fragments."
},
"11": {
"name": "developer_logos",
"why": "As entry 10: located by index because no content rule distinguishes a splash from a fragment. 7 elements, all drawn."
},
"13": {
"name": "publisher_logo_r",
"why": "As entry 10, region twin."
},
"14": {
"name": "developer_logos_r",
"why": "As entry 11, region twin."
}
}
"format": "sylpheed.screen_names/1",
"_": [
"Which GP_TITLE pak entry is which screen. AUTHORED: the disc does not name its",
"builds, so every name here is a decision. The identifications come from",
"HANDOFF Q2 (ui-title-build-map.md), which measured them against framebuffer",
"captures of the running game; the exporter stamps the name into the screen",
"file with name_source: \"authored\" so a reader can tell a recovered name from",
"an invented one.",
"",
"KEYED BY PAK ENTRY INDEX, not by the enumeration ordinal. It used to be the",
"ordinal; widening the enumeration to reach the splash renumbers ordinals, and",
"a name that moves when the enumeration rule changes is not a name. The entry",
"was always described here as the stronger locator -- now it is the only",
"stable one.",
"",
"Delete an entry here the day the RE agent decodes a name field."
],
"archives": {
"dat/GP_TITLE.pak": {
"2": {
"name": "press_start",
"why": "HANDOFF Q2: builds 2/3 are the PRESS (A) BUTTON plate -- a build of its own, composited over the title and faded in a beat later. English of the EN/JP pair. Measured against a live capture. 📌 SOURCE, added 2026-09-01 in the uncited-why backfill: the four bundles are identified in docs/re/ui-title-build-map.md, and the ordinal-versus-entry distinction this entry depends on is docs/re/structures/build-ordinal-vs-entry.md. ⚠️ The sibling references below (\"as entry 10, region twin\") are a citation form too -- they point at another entry in this file rather than at a document, and forcing a path onto them would be mislabelling to satisfy a counter."
},
"3": {
"name": "press_start_jp",
"why": "HANDOFF Q2: the Japanese twin of build 2. Out of scope for this milestone; named so it is not mistaken for a screen we need. 📌 SOURCE, added 2026-09-01 in the uncited-why backfill: the four bundles are identified in docs/re/ui-title-build-map.md, and the ordinal-versus-entry distinction this entry depends on is docs/re/structures/build-ordinal-vs-entry.md. ⚠️ The sibling references below (\"as entry 10, region twin\") are a citation form too -- they point at another entry in this file rather than at a document, and forcing a path onto them would be mislabelling to satisfy a counter."
},
"4": {
"name": "title",
"why": "HANDOFF Q2: build 4 is the English title art. Measured against a live capture. 📌 SOURCE, added 2026-09-01 in the uncited-why backfill: the four bundles are identified in docs/re/ui-title-build-map.md, and the ordinal-versus-entry distinction this entry depends on is docs/re/structures/build-ordinal-vs-entry.md. ⚠️ The sibling references below (\"as entry 10, region twin\") are a citation form too -- they point at another entry in this file rather than at a document, and forcing a path onto them would be mislabelling to satisfy a counter."
},
"5": {
"name": "main_menu",
"why": "HANDOFF Q2: builds 5/8 are the five-button main menu; 5 is English. Measured against a live capture. (An earlier reading called 8 a submenu and was withdrawn -- 8 is the Japanese main menu.) 📌 SOURCE, added 2026-09-01 in the uncited-why backfill: the four bundles are identified in docs/re/ui-title-build-map.md, and the ordinal-versus-entry distinction this entry depends on is docs/re/structures/build-ordinal-vs-entry.md. ⚠️ The sibling references below (\"as entry 10, region twin\") are a citation form too -- they point at another entry in this file rather than at a document, and forcing a path onto them would be mislabelling to satisfy a counter."
},
"6": {
"name": "extras",
"why": "HANDOFF Q2: builds 6/9 are the EXTRAS submenu, the only submenu inside this archive. Measured against a fresh EXTRAS capture. 📌 SOURCE, added 2026-09-01 in the uncited-why backfill: the four bundles are identified in docs/re/ui-title-build-map.md, and the ordinal-versus-entry distinction this entry depends on is docs/re/structures/build-ordinal-vs-entry.md. ⚠️ The sibling references below (\"as entry 10, region twin\") are a citation form too -- they point at another entry in this file rather than at a document, and forcing a path onto them would be mislabelling to satisfy a counter."
},
"7": {
"name": "title_jp",
"why": "HANDOFF Q2: the Japanese twin of build 4. 📌 SOURCE, added 2026-09-01 in the uncited-why backfill: the four bundles are identified in docs/re/ui-title-build-map.md, and the ordinal-versus-entry distinction this entry depends on is docs/re/structures/build-ordinal-vs-entry.md. ⚠️ The sibling references below (\"as entry 10, region twin\") are a citation form too -- they point at another entry in this file rather than at a document, and forcing a path onto them would be mislabelling to satisfy a counter."
},
"8": {
"name": "main_menu_jp",
"why": "HANDOFF Q2: the Japanese twin of build 5. 📌 SOURCE, added 2026-09-01 in the uncited-why backfill: the four bundles are identified in docs/re/ui-title-build-map.md, and the ordinal-versus-entry distinction this entry depends on is docs/re/structures/build-ordinal-vs-entry.md. ⚠️ The sibling references below (\"as entry 10, region twin\") are a citation form too -- they point at another entry in this file rather than at a document, and forcing a path onto them would be mislabelling to satisfy a counter."
},
"9": {
"name": "extras_jp",
"why": "HANDOFF Q2: the Japanese twin of build 6. 📌 SOURCE, added 2026-09-01 in the uncited-why backfill: the four bundles are identified in docs/re/ui-title-build-map.md, and the ordinal-versus-entry distinction this entry depends on is docs/re/structures/build-ordinal-vs-entry.md. ⚠️ The sibling references below (\"as entry 10, region twin\") are a citation form too -- they point at another entry in this file rather than at a document, and forcing a path onto them would be mislabelling to satisfy a counter."
},
"10": {
"name": "publisher_logo",
"why": "The SQUARE ENIX PUBLISHER wordmark -- the FIRST thing the boot sequence shows, before the developer logos. Measured by the RE agent 2026-08-29, render grid at docs/re/captures/title-builds/splash-both-halves-rendered.png. Entries 10/13 are region twins distinguished by the trademark glyph; 10 carries the (TM). 📌 SOURCE, added 2026-09-01 in the uncited-why backfill: the four bundles are identified in docs/re/ui-title-build-map.md, and the ordinal-versus-entry distinction this entry depends on is docs/re/structures/build-ordinal-vs-entry.md. ⚠️ The sibling references below (\"as entry 10, region twin\") are a citation form too -- they point at another entry in this file rather than at a document, and forcing a path onto them would be mislabelling to satisfy a counter."
},
"13": {
"name": "publisher_logo_r",
"why": "The region twin of entry 10, carrying (R) where 10 carries (TM). Named so it is not mistaken for a second screen the boot path needs. 📌 SOURCE, added 2026-09-01 in the uncited-why backfill: the four bundles are identified in docs/re/ui-title-build-map.md, and the ordinal-versus-entry distinction this entry depends on is docs/re/structures/build-ordinal-vs-entry.md. ⚠️ The sibling references below (\"as entry 10, region twin\") are a citation form too -- they point at another entry in this file rather than at a document, and forcing a path onto them would be mislabelling to satisfy a counter."
},
"11": {
"name": "developer_logos",
"why": "The GAME ARTS / SETA / studio anima logos -- the developer splash, shown after the publisher wordmark. HANDOFF Q2 and the RE agent's 2026-08-29 render grid; draws 7/7 elements. 📌 SOURCE, added 2026-09-01 in the uncited-why backfill: the four bundles are identified in docs/re/ui-title-build-map.md, and the ordinal-versus-entry distinction this entry depends on is docs/re/structures/build-ordinal-vs-entry.md. ⚠️ The sibling references below (\"as entry 10, region twin\") are a citation form too -- they point at another entry in this file rather than at a document, and forcing a path onto them would be mislabelling to satisfy a counter."
},
"14": {
"name": "developer_logos_r",
"why": "The region twin of entry 11, as 13 is to 10. 📌 SOURCE, added 2026-09-01 in the uncited-why backfill: the four bundles are identified in docs/re/ui-title-build-map.md, and the ordinal-versus-entry distinction this entry depends on is docs/re/structures/build-ordinal-vs-entry.md. ⚠️ The sibling references below (\"as entry 10, region twin\") are a citation form too -- they point at another entry in this file rather than at a document, and forcing a path onto them would be mislabelling to satisfy a counter."
}
}
},
"unnamed": {
"dat/GP_TITLE.pak": "Entries 0/1 and 12/15 are plates never seen running -- not in the boot path, not on any title-side screen, not in the attract loop (HANDOFF Q2). They export under their entry index rather than a name we would be inventing."
},
"also_export": {
"dat/GP_TITLE.pak": {
"10": {
"name": "publisher_logo",
"why": "LOCATED BY ENTRY INDEX, not by a rule. These four bundles declare their sprites directly and have no .rat layout child, so `is_build` cannot see them -- and the RE agent established that NO content rule can: design size fails (every extra composable bundle sampled is 1280x720, the same as every screen) and element count fails (fragments run 2..15 elements in GP_OPTIONS/GP_SAVE_LOAD while these are 3 and 7 -- the ranges overlap). Safe here and not in general: in GP_TITLE the widened set adds exactly these four and all four are real screens, zero fragments. 📌 SOURCE, added 2026-09-01 in the uncited-why backfill: the four bundles are identified in docs/re/ui-title-build-map.md, and the ordinal-versus-entry distinction this entry depends on is docs/re/structures/build-ordinal-vs-entry.md. ⚠️ The sibling references below (\"as entry 10, region twin\") are a citation form too -- they point at another entry in this file rather than at a document, and forcing a path onto them would be mislabelling to satisfy a counter."
},
"11": {
"name": "developer_logos",
"why": "As entry 10: located by index because no content rule distinguishes a splash from a fragment. 7 elements, all drawn. 📌 SOURCE, added 2026-09-01 in the uncited-why backfill: the four bundles are identified in docs/re/ui-title-build-map.md, and the ordinal-versus-entry distinction this entry depends on is docs/re/structures/build-ordinal-vs-entry.md. ⚠️ The sibling references below (\"as entry 10, region twin\") are a citation form too -- they point at another entry in this file rather than at a document, and forcing a path onto them would be mislabelling to satisfy a counter."
},
"13": {
"name": "publisher_logo_r",
"why": "As entry 10, region twin. 📌 SOURCE, added 2026-09-01 in the uncited-why backfill: the four bundles are identified in docs/re/ui-title-build-map.md, and the ordinal-versus-entry distinction this entry depends on is docs/re/structures/build-ordinal-vs-entry.md. ⚠️ The sibling references below (\"as entry 10, region twin\") are a citation form too -- they point at another entry in this file rather than at a document, and forcing a path onto them would be mislabelling to satisfy a counter."
},
"14": {
"name": "developer_logos_r",
"why": "As entry 11, region twin. 📌 SOURCE, added 2026-09-01 in the uncited-why backfill: the four bundles are identified in docs/re/ui-title-build-map.md, and the ordinal-versus-entry distinction this entry depends on is docs/re/structures/build-ordinal-vs-entry.md. ⚠️ The sibling references below (\"as entry 10, region twin\") are a citation form too -- they point at another entry in this file rather than at a document, and forcing a path onto them would be mislabelling to satisfy a counter."
}
}
}
}

View File

@@ -1,59 +1,604 @@
{
"format": "sylpheed.timing/1",
"keyframe_units_per_second": 60,
"why": [
"HANDOFF Q1. The disc says a keyframe is at `t=30`; it does not say what a",
"`t` is. The unit was MEASURED off the running game, not decoded: a declared",
"15-unit fade lands on round(255*k/15) for all seven of its samples with k",
"stepping 2,4,6,8,10,12,14 on seven consecutive submitted frames -- so 2",
"units per rendered frame -- and the idle title presents at 28.3-28.8 fps,",
"a 30 Hz game, giving 60 units per second. A second line agrees: the",
"transition quad is declared black for 12 units, and a capture measured the",
"pure-black plateau at 0.17-0.23 s, where 12/60 = 0.20 s.",
"",
"Expressed as units-per-second rather than seconds-per-unit so the value is",
"exact rather than a repeating decimal a reader has to recognise.",
"",
"DELETE THIS FILE when a field on the disc is found that states the unit.",
"Nothing here is on the disc."
"format": "sylpheed.timing/1",
"keyframe_units_per_second": 60,
"why": [
"HANDOFF Q1. The disc says a keyframe is at `t=30`; it does not say what a",
"`t` is. The unit was MEASURED off the running game, not decoded: a declared",
"15-unit fade lands on round(255*k/15) for all seven of its samples with k",
"stepping 2,4,6,8,10,12,14 on seven consecutive submitted frames -- so 2",
"units per rendered frame -- and the idle title presents at 28.3-28.8 fps,",
"a 30 Hz game, giving 60 units per second. A second line agrees: the",
"transition quad is declared black for 12 units, and a capture measured the",
"pure-black plateau at 0.17-0.23 s, where 12/60 = 0.20 s.",
"",
"Expressed as units-per-second rather than seconds-per-unit so the value is",
"exact rather than a repeating decimal a reader has to recognise.",
"",
"DELETE THIS FILE when a field on the disc is found that states the unit.",
"Nothing here is on the disc.",
"",
"🔴 DO NOT 'CORRECT' THIS AGAINST AN EMULATOR FRAME RATE. A draw-stream",
"measurement on 2026-08-29 found the presented units-per-frame rising 33 % over",
"a single boot (1.765 early, 2.357 late) and three independent readings of one",
"container's rate disagreeing with each other. That is the EMULATOR's",
"presentation pacing drifting, and no single units-per-frame figure describes a",
"run there.",
"",
"60 is a different quantity: the GAME's logical unit rate, measured off the",
"running game as HANDOFF Q1 (a declared t=30 landing on the linear value at",
"every one of seven sampled frames). The port renders at its own frame rate and",
"converts through this constant, so guest pacing cannot reach it. The two",
"numbers are not comparable and one is not evidence about the other.",
"",
"🔴 2026-09-01 — THE FIRST LEG ABOVE IS RETIRED. THE VALUE IS NOT.",
"",
"'2 units per rendered frame ... a 30 Hz game, giving 60 units per second' is a",
"FRAME-COUNT derivation, and the Decoder retired that mechanism the same day",
"(docs/re/units-per-second-measured.md): the same animation takes 21 frame",
"labels in one capture and 33 in another, and one splash logo steps +136,+34 in",
"one run and +17,+51,+34,+34,+17,+17 in the other. A fixed per-frame increment",
"cannot do that. The clock is TIME-INTEGRATED, not frame-counted, so `units =",
"2 x frames` computes an emulator artefact. The 2 was that run's frame pacing.",
"",
"✅ The port's RUNTIME was already right: `boot.gd` advances",
"`time_units += delta * units_per_second`, off delta time. Nothing in this port",
"derives a unit from a frame count. Audited 2026-09-01, and it is why the",
"retirement cost a justification and not a behaviour.",
"",
"✅ AND THE SECOND LEG NEVER TOUCHED A FRAME COUNT, which is why 60 survives:",
"the transition quad is declared black for 12 units and the capture bracketed",
"the pure-black plateau at 0.14-0.30 s (title-plate-delay-measured.md, at a",
"0.125 s sampling resolution). 12 units in 0.14-0.30 s is 40-86 units/s. That",
"is a declared unit count against a wall-clock duration, with no frames in the",
"chain -- and it EXCLUDES 120 units/s, which would need 0.10 s.",
"",
"✅ MEASURED DIRECTLY 2026-09-01: 56.8 units per guest second, control passing",
"at 1.15 %, from two elements agreeing at one clock (`ptbtn00` 657.9 alpha/s,",
"`ptcopyright` 650.4 alpha/s, which puts ptcopyright's segment at T = 22.25 --",
"a rate agreement AND a round declared length). 30 and 120 are both excluded.",
"",
"60 IS KEPT. 56.8 is 5.6 % away against a ~5 % quantisation resolution, so it",
"does not refute 60, and the Decoder explicitly did not ask for a change. The",
"reach is the TITLE: the splashes are a different GamePart and nothing yet shows",
"they tick at the same rate.",
"",
"⚠️ If anyone re-fits this from alpha: DROP THE LAST STEP of a ramp. It clamps",
"at 255 and reports more elapsed time than it consumed -- worth 4 % on the plate.",
"",
"🔴 2026-09-01 (later) — A PER-SCREEN RATE WAS PROPOSED AND NOT ADOPTED.",
"",
"docs/re/splash-declared-vs-captured.md proposes ~57 units/s for the title and",
"~35-40 for the splashes, i.e. that one constant cannot be right and that a",
"splash at 60 runs 1.5-1.7x too fast. THE PORT DID NOT MOVE, and the reason is",
"arithmetic on a measurement already cited in this file:",
"",
" the 160-unit hold is the DEVELOPER splash's a=255 plateau, t=30..190, and it",
" is measured at 4.514 s. The 210-unit group CONTAINING it is measured at",
" 3.37/3.50/3.51 s over three cold boots (the dwell_why block below). A",
" sub-interval cannot outlast the interval containing it.",
"",
"The same three boots put the splashes at 57.7 and 60.7 units/s -- corroborating",
"60 on exactly the two screens the new figure puts at 35-39. At 35.4 the declared",
"groups would run 5.93 s and 7.20 s against corpus dwells of 3.37-3.51 and",
"4.30-4.60, i.e. each splash ~70 % longer than measured.",
"",
"⚠️ DO NOT ADOPT EITHER NUMBER UNTIL THAT IS RESOLVED, and do not split the",
"difference -- averaging two measurements that cannot both be true is not a",
"third measurement. docs/port/splash-rate-contradiction.md, asked as BLOCKED H7.",
"",
"⚠️ AND THE STRUCTURAL CLAIM MAY STILL BE RIGHT. 'One rate cannot cover every",
"screen' is a claim about the format, and the title's 56.8 does sit ~5 % off the",
"splashes' 58-61. If a per-screen rate is real this file should carry a MECHANISM",
"-- a field or a GamePart constant -- not two authored numbers. The Decoder has",
"'where the per-GamePart rate comes from' as its next item.",
"",
"🔴 2026-09-01 (later still) — RECLASSIFIED measured -> authored. THE VALUE DOES",
"NOT MOVE; THE LABEL WAS FALSE.",
"",
"The Decoder withdrew their guest-frame-rate finding the same day they published",
"it. ⚠️ THAT DOCUMENT IS NOT IN THIS CHECKOUT -- it is `guest-frame-rate-WITHDRAWN.md`",
"on their branch, named here in prose deliberately rather than in `source`:",
"`audit-kinds` flagged the first version of this entry DANGLING because I cited",
"a file I cannot read, which is exactly the check doing its job. The reading",
"below is from their message and is labelled as such.",
"It read the guest's presentation as 30 fps from a movie-frame ruler and",
"concluded 2 x 30 = 60. This file carried `kind: measured` on that strength.",
"`kind: measured` on the strength of it. It cannot any more.",
"",
"Three routes now disagree and at most one can be right:",
"",
" withdrawn movie cadence 60 units/s",
" vblank cadence (Xenia, 60 Hz) ~120",
" title-plate-delay, 120 units ~56 -- two runs agreeing to 6 ms",
"",
"⚠️ 60 IS KEPT ANYWAY, and it is not a coin toss between the three. The one leg",
"of this file's own reasoning that never touched a frame count still stands and",
"still brackets it: the transition quad is declared black for 12 units and the",
"capture measured the plateau at 0.14-0.30 s, i.e. 40-86 units/s. 60 sits inside",
"that; 120 does not. And ~56 is 7 % from 60, inside the same bracket.",
"",
"So the honest statement is: 60 is AUTHORED, bracketed by one surviving",
"frame-free measurement, and consistent with the nearest of the three live",
"routes. It is no longer 'measured', and anything that cited it as measured is",
"citing a withdrawal.",
"",
"📌 THE METHOD NOTE IS WORTH MORE THAN THE NUMBER, and it is the Decoder's: their",
"pre-registration named three ways the ruler could lie and guarded two. The third",
"occurred, and a PERFECT 1.0000 is exactly what it produces -- a triple buffer",
"rotating once per present gives run-length 1 at any frame rate. Both guards",
"tested how the buffer was READ, neither tested whether a change meant a decode.",
"",
" A clean result on an instrument whose key assumption is unguarded is not",
" confirmation. The cleanness may be the failure mode's own signature.",
"",
"Same family as this port's non-inverting latch check, which passed for the wrong",
"reason until its control failed.",
"",
"🔴 2026-09-01 — THE 12-UNIT BRACKET ABOVE IS WITHDRAWN. IT EXCLUDES NOTHING.",
"",
"I kept 60 on the ground that '12 declared units measured at 0.14-0.30 s gives",
"40-86 units/s, so 120 is excluded'. The Decoder refuted it and the refutation",
"holds on arithmetic I checked myself:",
"",
" the source doc says of that number, in its own words, 'at a sampling",
" resolution (0.125 s) that cannot do better'. 120 units/s predicts 12 units in",
" 0.100 s -- BELOW one sample interval. A 0.125 s sampler cannot resolve it and",
" reports about one sample, ~0.125-0.14 s. The 0.14 s low end is the",
" INSTRUMENT'S FLOOR, and 12/0.14 = 85.7 is an upper bound produced by dividing",
" by a floored duration. It is the value 120 predicts once the sampler is",
" accounted for.",
"",
"🔴 AND THE DEEPER ERROR IS MINE, NOT THE ARITHMETIC. I argued the leg survived",
"because it 'never touched a frame count'. True, and INSUFFICIENT: every",
"wall-clock duration off Canary is true/speed_factor, so apparent units/s =",
"true x speed -- and the speed factor is precisely what makes the three routes",
"disagree. I checked the leg for the WRONG CONTAMINANT. Frame-free is not",
"clock-free, and on this emulator clock-free is the property that matters.",
"",
"What actually survives from that leg, and it is the half I did not lead with:",
"the declared 12 units are independently confirmed as SIX FRAMES by",
"screen-transitions.md's 255/6-per-frame ramp. No wall clock in it at all. That",
"is evidence about units per FRAME -- which was never in dispute -- and silent",
"about units per second.",
"",
"SO 60 HAS NO SURVIVING BRACKET. It stays because nothing supports 120 either and",
"moving a shipped timeline on no evidence is worse than leaving it. That is a",
"default, not a derivation, and this entry now says so. `kind` is already",
"`authored`, which is the honest label for a default.",
"",
"🟡 2026-09-01 — 120 units/s IS NOW MEASURED, AND THIS PORT HAS NOT MOVED.",
"",
"The Decoder's content-hash experiment gives 120 (2 units/present x 60",
"presents/s), with the controls the withdrawn version lacked -- a static texture",
"hashing constant, 1 change in 403 samples, and movie luma not constant, 102",
"distinct hashes. Pre-registered bands, and the observed 0.5739 falls inside",
"them. It is a better experiment than either of the two it replaces.",
"",
"IT IS ALSO 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. 60 stays for now.",
"",
"⚠️ 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.",
"",
"✅ AUDITED, SO THE SWITCH IS CHEAP WHEN IT COMES: no seconds are baked into the",
"timeline anywhere. Every second this port prints or acts on is computed as",
"units / keyframe_units_per_second at the point of use. audio.json's loop_start_s",
"and loop_end_s ARE seconds and correctly do NOT follow this constant -- they are",
"positions in an audio file with no keyframe unit in them.",
"",
"🔴 One exception found and fixed: tools/port/verify-dwell read black_hold_units",
"from this file 'so it cannot drift again' and then divided by a literal 60.0.",
"The value could not drift; the conversion could.",
"",
"📌 THE FALSIFIER IS PRE-REGISTERED in docs/port/units-per-second-switch-readiness.md:",
"at 120 the publisher splash runs 2.13 s and the developer 1.75 s, against three",
"cold boots measuring 4.30/4.60/4.37 and 3.51/3.50/3.37. 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.",
"",
"✅ 2026-09-01 (final position of the day) — 120 IS WITHDRAWN BY ITS AUTHOR AND 60",
"IS POSITIVELY SUPPORTED. The port never moved, so nothing has to be undone.",
"",
"The mechanism is worth more than the number: `units per present` HALVED when the",
"present rate doubled (Δα +34 at 27.2 presents/s, +17 at 51.4) while units per",
"second did not move (54.4 vs 51.4). The UI clock advances by elapsed TIME, not",
"by frame count -- so '2 units per frame' was never a property of the game, only",
"of a capture that happened to run at 27 fps. The 120 was 2 units/present x 60",
"presents/s, and the first factor is not a constant, so the product was not a",
"rate.",
"",
"Their write-up is `units-per-frame-is-not-a-constant.md`, under docs/re/ on",
"their branch. 🔴 NOT IN THIS CHECKOUT, so it is named WITHOUT a resolvable",
"path -- `tools/port/check-citations` flagged the first version of this very",
"paragraph as DANGLING, in the entry where I was recording the lesson about",
"dangling citations. The check does not care about a disclaimer, which is",
"correct: a path that does not resolve does not resolve.",
"",
"✅ 2026-09-01 (settled) — THE GAME'S CLOCK IS FRAME-BASED, 1 UNIT PER PRESENT.",
"Measured by the Decoder with a DESIGNED experiment rather than an inference:",
"`--framerate_limit=30` halved units/second to 30.2, doubled the publisher dwell",
"to 8.450 s, and left the modal alpha step at 17 where a time-based clock",
"predicts 34. Both controls passed first -- the limiter demonstrably took effect,",
"and all 8 splash quad rects were identical, so nothing but the frame rate",
"differed. `255 x 1 / 15 = 17` at 28.4, 51.4 and 54.8 presents/s alike.",
"",
"⚠️ THIS CHANGES WHAT 60 MEANS HERE, AND MAKES IT MORE FALSIFIABLE. If the game",
"advances 1 unit per present, its units/second IS its present rate. So",
"`keyframe_units_per_second = 60` is now equivalent to the claim:",
"",
" the game presented these screens at 60 Hz on the console.",
"",
"That is a sharper statement than 'the unit is 1/60 s' and it is checkable.",
"",
"✅ AND IT IS SUPPORTED, which the constant has not been until now. Canary",
"unlimited presents at 51-55 Hz and the splash dwell is 4.30/4.60/4.37 s over",
"three cold boots. A natively 30 Hz game would present at ~30 in Canary too --",
"which the framerate_limit run confirms, since forcing 30 made the same splash",
"take 8.45 s. It does not take 8.45 s unforced. So the game asks for ~60, not 30.",
"",
"🔴 AND THAT CLOSES THE CONSTANT AS A CAUSE OF 'THE PLATE IS LATE', for a NEW",
"reason and in the direction that matters. Under the frame-based model the only",
"alternative console rate is 30 Hz, which puts the plate at 236/30 = 7.87 s --",
"LATER than the 3.93 s the port ships, not earlier. There is no console present",
"rate that makes the plate arrive sooner than it already does here.",
"",
"⚠️ KEPT AS `authored`, NOT PROMOTED TO `measured`. The chain is inference over",
"three measurements (frame-based clock; Canary's unlimited present rate; the",
"dwell corpus) rather than a measurement of units per second. It becomes",
"`measured` the day someone reads the console's present rate for these screens",
"directly.",
"",
"📌 AND THE PORT'S OWN DESIGN IS DELIBERATELY NOT THE GAME'S, which is worth",
"stating so nobody 'fixes' it. The game is frame-based; this port is time-based",
"(`time_units += delta * units_per_second`). They agree at 60 fps, which is the",
"only rate the console ever asked the game to be right at. A time-based port",
"reproduces a 60 Hz console on hardware that is not 60 Hz; a frame-based port",
"would drift on every machine that is not -- and this port has measured itself at",
"9.7 to 69.4 fps depending on the renderer. DO NOT make the port frame-based to",
"match the game.",
"",
"✅ 2026-09-02 — 60 NOW STANDS ON A THIRD INDEPENDENT ROUTE, and the REASON",
"changed again while the value did not.",
"",
"The Decoder reconciled three of their own pages that held incompatible",
"positions -- 2 units per guest frame, time-integrated at 56.8, and 1 unit per",
"present -- with one mechanism: THE CLOCK ADVANCES ONE UNIT PER VBLANK, and",
"presents may be dropped without the clock caring. That explains steps that are",
"always multiples of 17 (1, 2 or 3 vblanks between two logged presents), and the",
"same animation spanning 21 labels in one capture and 33 in another, which a",
"strict per-present clock cannot produce.",
"",
"Their rate result is a MANIPULATION rather than an observation: 255 declared",
"units take 4.263/4.162 s at a 60 Hz vblank and 8.450 s at --framerate_limit=30",
"-- 59.8/61.3 against 30.2 units/s. So the vblank rate sets the unit rate, and a",
"console vblanks at 60.",
"",
"So the justification for 60 has now been: '2 units per rendered frame' (retired),",
"'the game presents at 60 Hz' (superseded), and now 'one unit per 60 Hz vblank'.",
"THE NUMBER HAS NEVER MOVED. That is worth noticing rather than celebrating -- a",
"value whose reason changes three times while it survives is either robust or",
"under-constrained, and the honest label is still `authored`.",
"",
"📌 THIS PORT INSTANTIATES THEIR NULL MODEL, which is the one thing this side can",
"contribute to that argument. Their reasoning turns on 'a time-integrated clock",
"predicts 4.25 s in BOTH conditions'. This port IS a working time-integrated",
"clock at 60 units/s, and its splash dwell across a 4.0x change in its own",
"rendering rate is 4.28 / 4.26 / 4.27 / 4.26 s -- flat to 0.5 %. So their",
"counterfactual is demonstrated rather than assumed. ⚠️ It is evidence about the",
"NULL, not about the game; it says what a time-integrated clock does, not what",
"the game's clock is.",
"",
"🟡 PER-VBLANK VS PER-PRESENT IS STILL OPEN, and they name the discriminating",
"experiment (log Xenia's vblank counter beside each present). ⚠️ IT IS",
"IMMATERIAL TO THIS PORT AND THEY SHOULD NOT RUN IT ON THE PORT'S ACCOUNT. The",
"two models differ only when the console DROPS a present: per-vblank keeps",
"real-time pace through a drop, per-present slows. This port is time-based, so",
"it matches per-vblank exactly and would run marginally ahead of per-present",
"during drops only. On a console presenting every vblank the two coincide, and",
"the screens in question are a handful of quads.",
"",
"🔴 2026-09-02 (later) — 'A THIRD INDEPENDENT ROUTE' IS WITHDRAWN BY ITS AUTHOR.",
"The paragraph above says 60 now stands three ways. It does not, and I recorded",
"the claim before challenging it hard enough.",
"",
"I raised that three routes to one number are weaker than they look if they share",
"an upstream assumption -- vblank rate, present rate and declared dwell are not",
"obviously independent. The Decoder audited it and agreed: route B needs 'the",
"guest presents 60x/s', which comes from the vblank histogram UNDER XENIA'S 60 Hz",
"LIMITER; route C needs 'the vblank is 60 Hz', which is that limiter's cvar; route",
"D is a wall-clock duration that lands on 60 only BECAUSE the vblank is 60 Hz.",
"All three reduce to one upstream fact: the display refreshes 60 times a second",
"on that emulator. One witness in three coats.",
"",
"✅ WHAT SURVIVES IS CONDITIONAL AND BETTER, and it is established by MANIPULATION",
"rather than agreement -- forcing 30 Hz gave 30.2 units/s, 60 Hz gives 59.8/61.3:",
"",
" units per second = THE DISPLAY REFRESH RATE.",
"",
"It becomes '60' only through a fact this corpus has never measured: an Xbox 360",
"outputs 60 Hz. That is a hardware specification. It is solid, and it belongs",
"CITED as a spec rather than folded in as a third measurement.",
"",
"📌 And the conditional form is the one that justifies this port's construction",
"rather than excusing it. 'units/s = refresh rate' says what to do on hardware",
"that is NOT 60 Hz, which is exactly why a time-based clock at a fixed 60 units/s",
"is right and a frame-based one would drift. `kind` stays `authored`: nothing",
"here promotes it, and the reason it is not `measured` is now sharper -- the",
"measurement is of a RELATIONSHIP, and the constant that closes it comes from a",
"datasheet."
],
"kind": "authored",
"source": "docs/re/ui-keyframe-time-unit.md, docs/port/HANDOFF.md",
"ramp": "linear",
"ramp_why": [
"Also HANDOFF Q1, and part of the same measurement: the fade lands on the",
"linear value at every one of the seven sampled frames, so there is no ease."
],
"ramp_kind": "measured",
"dwell_seconds": null,
"dwell_why": [
"NOT SET -- because the dwell is DECLARED, and the port already plays it.",
"",
"This key has now been wrong in two opposite directions, and the second was",
"mine, so both are recorded.",
"",
"It first said 'a screen's dwell is its OWN keyframe group'. Then GP_TITLE",
"build 4 was measured dwelling ~1100 presented frames against a declared ~120,",
"and I generalised that into 'the boot is KNOWN TOO FAST [refuted] on both splashes'.",
"🔴 THAT WAS AN OVER-CORRECTION and it is withdrawn. Build 4 is the title: its",
"exit is caused by something outside its timeline, so it holds. A splash's exit",
"is caused by nothing, so it plays its declared timeline and leaves. The title",
"is the exception, not the rule, and one screen was never enough to overturn",
"the other two.",
"",
"MEASURED 2026-08-29 by the Decoder over 3 cold boots",
"(docs/re/structures/boot-splash-dwells-are-declared.md):",
"",
" publisher declared t=0..255 = 4.250 s corpus 4.30 / 4.60 / 4.37",
" developer declared t=0..210 = 3.500 s corpus 3.51 / 3.50 / 3.37",
"",
"The developer agrees to 1.1 %, two of its three runs to 0.3 %.",
"",
"🔴 CORRECTED 2026-09-01. This said: 'The port emits 4.400 s and 3.650 s -- each",
"declared value plus the 9-unit black hold, exactly. So the pacing was right all",
"along and nothing changes in the code.' THE PORT DOES NOT DO THAT, and this",
"file is what stops it: `black_hold_units` is 0, set deliberately (see",
"black_hold_why -- a uniform value is positively excluded and only an",
"ordered-pair key survives). There is no 9-unit hold to add, so the sentence",
"described a behaviour asserted three keys above it and refused one key below.",
"",
"MEASURED off the shipping boot, three runs, 2026-09-01:",
"",
" publisher declared 255 units = 4.250 s 4.28 / 4.26 / 4.27 mean 4.270 s",
" developer declared 210 units = 3.500 s 3.50 / 3.57 / 3.51 mean 3.527 s",
"",
"Residuals +1.2 and +1.6 units -- frame granularity on the exit check, not a",
"hold. The claimed 4.400 and 3.650 are each ~0.13 s longer than what has been",
"shipping since P3. Against the corpus (4.42 and 3.46 means) neither the claimed",
"nor the measured figure dominates: the port is 3.4 % short on the publisher and",
"2.0 % long on the developer, the claim would be 0.5 % short and 5.5 % long. So",
"this corrects a false statement about our own behaviour; it does not settle",
"whether a hold belongs there. That is still black_hold_why's ordered-pair ask.",
"",
"🔴 AND THE UNIT STAYS UNITS, NOT SECONDS. The same two dwells timed in the",
"Decoder's own container came out 15-20 % LONGER than both the declared values",
"and the corpus -- same disc, same timeline -- and three independent readings",
"of that container's rate disagree with each other. A seconds figure records",
"one emulator's pacing on one run. The units are on the disc. If anything ever",
"goes in `dwell` it is an extra hold in UNITS, and only for a screen that is",
"measured to wait beyond its group.",
"",
"🔴 2026-09-01 (later) — 'So the pacing was right all along and nothing changes in",
"the code' IS CONDITIONAL, AND MAY BE A COINCIDENCE OF TWO CANCELLING ERRORS.",
"",
"That sentence rests on the port's total screen time matching the corpus dwells.",
"It does: 4.270 s against 4.30/4.60/4.37 and 3.527 s against 3.51/3.50/3.37.",
"",
"But a TOTAL cannot see two errors of opposite sign inside it. Measured:",
"",
" the port's screen time IS its animation time. publisher 4.270 s against a",
" 4.250 s animation -- a hold of +0.020 s, i.e. none. The port does not hold",
" after a splash timeline at all.",
"",
" the GAME does: the Decoder counts the publisher on screen for 219 presents and",
" animating for ~128 of them, about 42 % hold.",
"",
"So IF keyframe_units_per_second is 120 rather than 60, this port animates every",
"splash 2x too slow AND omits the hold entirely, and the two sum to almost exactly",
"the right total. The agreement above would then be evidence of nothing.",
"",
"⚠️ THE HOLD AND THE CONSTANT ARE COUPLED. At 60 the port must NOT gain a hold --",
"the animation already fills the screen time and a hold would overshoot by ~40 %.",
"The missing hold is a defect only if 120 is right. They stand or fall together,",
"which is another reason not to move on one capture.",
"",
"📌 And when it does move it is TWO changes, not one: the constant, and a hold",
"measured as (screen presents - animation presents). It must NOT be inferred from",
"the total, because the total is precisely the quantity that cannot distinguish",
"the two errors. docs/port/units-per-second-switch-readiness.md.",
"",
"✅ 2026-09-01 (later still) — THE PARAGRAPH ABOVE IS WITHDRAWN. 'The pacing was",
"right all along' WAS right all along.",
"",
"I claimed the dwell agreement might be a coincidence of two cancelling errors --",
"a 2x-slow animation plus a missing hold. There is no missing hold. I misread a",
"presents split from the Decoder's instrument ('219 on screen, ~128 animating')",
"as a hold OUTSIDE the declared timeline. It is a split WITHIN it: the publisher",
"ramps 0-30, HOLDS 30-235 (205 units, 80.4 % of the screen) and fades 235-255,",
"and this port plays all three.",
"",
"Measured rather than read -- frozen samples of the logo region across the",
"publisher splash: 0.405488 at t=60, 120, 180 and 228 units, identical to six",
"decimals across 168 units, with 0.391 at t=15 (mid-ramp) and 0.038 at t=252",
"(in the exit fade). The hold is there and it is played.",
"",
"⚠️ The failure was not a mis-measurement. I took a two-part split from someone",
"else's instrument and assumed its boundary sat where my own model put it.",
"Presents are not units, and 'animating vs holding' in presents does not",
"decompose the same way as 'ramp vs hold' in declared units.",
"",
"AND THE DWELL FIGURES HERE ARE NOW POSITIVE EVIDENCE, not merely survivors. A",
"time-based clock is immune to dropped frames, so a dwell measured in seconds is",
"stable across runs at different frame rates. This port's own splash dwell across",
"a 4.0x change in its rendering rate: 4.28 s at 17.3 fps, 4.26 at 19.6, 4.27 at",
"25.0, 4.26 at 69.4 -- a 0.5 % spread, putting 255 units at 59.6-59.9 units/s",
"every time. That establishes these dwells are frame-rate-independent",
"MEASUREMENTS rather than artefacts of whatever rate a run hit, which is the",
"property the Decoder's argument needs of them.",
"",
"✅ 2026-09-02 — THE +1.2 / +1.6 UNIT RESIDUAL WAS FRAME GRANULARITY, and that is",
"now measured rather than inferred.",
"",
"The dwells were recorded as 4.270 s and 3.527 s against declared 4.250 and 3.500",
"-- residuals of +1.2 and +1.6 units -- and I attributed them to the granularity",
"of the exit check without testing it. A hardware GPU makes that testable: same",
"boot, same declared groups, three runs at 65-66 fps instead of 17-25.",
"",
"Pre-registered: if the residual is frame granularity it should shrink roughly",
"with the frame rate, so <= 0.5 units at 65 fps. Measured:",
"",
" publisher 4.27 / 4.26 / 4.27 mean 4.253 s residual +0.20 units",
" developer 3.50 / 3.52 / 3.50 mean 3.500 s residual +0.00 units",
"",
"From +1.2 and +1.6 down to +0.20 and +0.00. The prediction held and the",
"attribution is no longer an assumption. ⚠️ It also means the figures quoted",
"elsewhere in this corpus as 4.270 / 3.527 carry a rendering-rate term; the",
"declared values are what the port actually targets and 4.250 / 3.500 is what it",
"hits when the renderer keeps up."
],
"dwell_kind": "measured",
"looping_focus_records": {
"_": [
"WHICH focus records the port draws, unconditionally and on a loop, OVER the",
"element's own sprite rather than instead of it.",
"",
"RESTORED 2026-08-30 on a MEASUREMENT, having been deleted on 2026-08-29 for",
"a real defect that was in the RENDERER, not in this table. The old entry made",
"`_draw` substitute the glow for the plate's own bright sprite, so the plate",
"was invisible at every instant (max 0 against max 252.5). `ScreenView` now",
"draws the base and the record over it, and the entry comes back."
],
"kind": "measured",
"source": "/reborn docs/port/HANDOFF.md Q1, docs/re/ui-keyframe-time-unit.md",
"ramp": "linear",
"ramp_why": [
"Also HANDOFF Q1, and part of the same measurement: the fade lands on the",
"linear value at every one of the seven sampled frames, so there is no ease."
],
"exit_ramp_seconds": 0.4,
"exit_ramp_why": [
"HANDOFF Q7 + the RE agent's 2026-08-29 answer. MEASURED, not on the disc.",
"press_start/ptbtn00": {
"record_element": "ptbtn00f",
"period_units": 120,
"kind": "measured",
"source": "docs/re/structures/plate-pulse-measured.md, RE agent 2026-08-30",
"why": [
"MEASURED off the running game, held at the title with NO INPUT: the plate",
"oscillates continuously -- two windows in one boot of 58 s and 57 s, about",
"23 cycles each, with no decay and no settling.",
"",
"Every element of a screen ends on exactly ONE untimed keyframe, so there is",
"exactly one unknown duration per screen -- the ramp INTO that final keyframe.",
"This is that duration. ~0.4 s, which is 24 units at 60 units/s.",
"🔴 IT NEVER GOES OFF. The plate-absent floor is 159 thresholded green",
"pixels -- the title art's own, measured on live-title-build4-no-plate.png --",
"and the pulse bottoms at 714, four and a half times that. So `ptbtn00`",
"going transparent at t=244 is not the end of the plate; that is its EXIT",
"ramp, which plays when the screen leaves. While the screen is held the base",
"sits at its own hold (alpha 255 at t=238) and `ptbtn00f`'s cycle runs over",
"it. Base-only and base-plus-glow are what the 714 and the 1520 are.",
"",
"The alternative readings were tested and refuted. It is not a black quad laid",
"over a frozen screen: under that model a black rect scales every region by the",
"same 1-alpha, so the button-region / background-region brightness RATIO would",
"be constant through the fade. Measured on the RE agent's filmstrip it falls",
"6.495 -> 5.574 -> 3.105 -> 2.125 -> 1.935, a 3.4x monotonic drop. The screen",
"itself plays out: pteff00.prm ramps to opaque black while the button labels,",
"ptmsg, pteff10 and pteff12 all ramp to transparent, and ptframe1/2 hold.",
"",
"REACH, quoted from the RE agent rather than smoothed over: the filmstrip is",
"downsampled and the button region contains some background, so this pins the",
"DIRECTION, not 0.4 s to +/-0.05 s, and it is one transition pair. Treat the",
"number as approximate and the model as established."
],
"exit_ramp_units": 24,
"dwell_seconds": null,
"dwell_why": [
"NOT SET, and not needed. A 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. Adding a hold on top of that would",
"be inventing a number nobody measured, so the sequencer holds for zero extra",
"time and the pacing you see is the disc's own.",
"",
"If a capture ever times the real boot, this is where that number goes."
]
"⚠️ 120 UNITS, NOT SECONDS, and that is the RE agent's own instruction. Their",
"run measured 2.530 and 2.540 s; an earlier corpus run measured 2.24 s. Same",
"declared number, different emulator pacing -- x1.27 and x1.12 against a",
"nominal 2.000 s, which IS 120 units at 60 units/s. Hardcoding 2.5 s would",
"author one loaded container's clock."
],
"limits": [
"ONE BOOT. Two windows inside it are not two boots.",
"It does NOT distinguish the boot title from an attract-loop title: run 1",
"opens at t~255 s against Q9's ~193 s no-input baseline, so it may already",
"be the attract title. Both are 'the title, held, no input' -- which is what",
"was asked -- but it is not proof about the first appearance.",
"🔴 714/1520 IS NOT AN ALPHA RATIO. The counter is thresholded pixels, so dim",
"pixels drop out first. No duty cycle and no ramp shape may be read off it;",
"the port draws the record's own declared alpha ramp and infers nothing."
]
}
},
"exit_ramp_deleted_why": [
"DELETED 2026-08-29, and the deletion is the point.",
"",
"`exit_ramp_seconds` (~0.4 s) and `exit_ramp_units` (24) were AUTHORED because",
"the disc had no time slot on a group's final keyframe, so the ramp into it was",
"the one unknown duration per screen. Under the corrected record layout",
"(formats-pin-2026-08-29c onward) there IS no untimed keyframe -- a group is an",
"8-byte header then frames x {u32 time; 36-byte pose}, so every pose is timed",
"including the last. The unknown the constant stood in for does not exist.",
"",
"MISSION section 3: 'When the RE agent later decodes something you had",
"authored, delete the authored entry and let the exporter emit it. That",
"deletion is the measure of progress.'",
"",
"VERIFIED DEAD BEFORE DELETING, not assumed: setting it to 9999 (166 seconds)",
"changed the boot's transitions by 0.04 s -- wall-clock jitter, not a 166 s",
"ramp. Both of its uses in ScreenView were gated on `not last_frame.has('t')`,",
"which no longer fires on any of the export's 866 keyframes.",
"",
"The measurement it recorded is not lost: HANDOFF Q7's ~0.4 s fade-out and the",
"0.17-0.23 s black hold are still measured facts, and the hold is still used --",
"`tools/port/verify-dwell` compares a transition INTERVAL against the oracle's",
"visible SPAN plus that hold. What is deleted is the port's need to invent a",
"duration the disc now states."
],
"black_hold_units": 0,
"black_hold_why": [
"0 = NOT MODELLED. The escalation is resolved: a uniform value is positively",
"EXCLUDED, so 0 is no longer one option among several -- it is the only honest",
"uniform choice, because it is the one that does not claim a constant exists.",
"",
"UPDATE: TWO candidate models are now excluded, not one. The Decoder has five",
"replicates with NO variation -- title->menu 3,3,3 and EXTRAS->menu 2,2 -- and",
"every differing value comes from a different ORDERED PAIR. The same origin",
"gives different values to different destinations (menu 0 vs 1, EXTRAS 2 vs 3).",
"So a constant is excluded AND keying on the outgoing screen is excluded; only",
"an ordered-pair key survives, with a measured value needed per pair.",
"",
"I checked independently whether anything DECLARED predicts it, from the",
"quantities in my export. None does: outgoing close (15,10,10,10), incoming",
"clear (12,12,16,12), outgoing span (269,74,80,80) and incoming span",
"(80,80,269,74) each have two rows sharing a value with different gaps.",
"",
"I did NOT search combinations of them. Four intra-archive pairs against many",
"candidate two-screen functions fits by construction -- that is the error this",
"corpus has catalogued five times, and finding a formula here would be",
"indistinguishable from finding one in noise.",
"",
"The Decoder ordered the gaps by the screen being LEFT (frames): menu 0 and 1,",
"EXTRAS 2, title 3. Three hypotheses are positively ruled out, not merely",
"unsupported. DIRECTION: EXTRAS->menu (2) and menu->EXTRAS (1) are the same",
"pair both ways and differ. BUTTON: (B) gives 0 and 2, (A) gives 1 and 3.",
"INCOMING SCREEN: an incoming menu takes 3 from the title and 2 from EXTRAS.",
"",
"So the quantity varies 0-3 frames by outgoing screen, and any uniform non-zero",
"value is wrong as a MODEL rather than merely off in magnitude. 0 models the",
"gap as absent; 6 would model it as constant, which the data excludes.",
"",
"MY OWN RULE IS REFUTED, not just unadopted. It was gap + the incoming",
"screen's opening black-clear = a constant, holding at 16/16/18 on three",
"transitions. Their fourth gives 16, 14, 16, 18 -- and decisively, the two",
"transitions with the SAME incoming screen (main_menu) have different gaps,",
"so the incoming screen cannot determine it. A fourth point did to a",
"three-point fit exactly what it should.",
"",
"DO NOT key this per outgoing screen yet. Three outgoing screens with one",
"value each restates the data rather than predicting it -- the same objection",
"I raised against my own 16/16/18. Key it when a screen has more than one",
"measured value, and key it on the screen being LEFT.",
"",
"📌 CITATION ADDED 2026-09-01, and its absence propagated from the delivery.",
"This why carried over a thousand characters and NOTHING OPENABLE. The Decoder",
"sent the `(B)`-from-EXTRAS leg as an inline frame table with no file cited,",
"while docs/re/data/fade-four-transitions.txt -- which carries that leg and",
"eight others -- had been committed the whole time. They found it in their own",
"audit and cited it; it had already landed here uncited.",
"",
"⚠️ An uncited measurement propagates as an uncited value. The receiving end",
"cannot tell a summarised measurement from a recalled one, and both read as",
"prose.",
"",
"✅ AUDITED 2026-09-01 and this one needed nothing: it was already an EXCLUSION argument rather than a count. It excludes a constant, excludes keying on the outgoing screen, and excludes every declared quantity in the export as a predictor -- four of them named, each shown not to separate the pairs. That is the form the week's other claims were found to be missing."
],
"black_hold_kind": "measured"
}