e5f1b7c2d4a519b2bdb8b8d557177a6eed28f16f
1292 Commits
| Author | SHA1 | Message | Date | |
|---|---|---|---|---|
|
|
d949a2216f |
re: the menu loop WATCHED -- three wraps, 61.81 s, and my placement is refuted
Settles the conflict by timing the loop instead of converting it. A tailing probe stamps read_offset with the wall clock as each log line arrives, so the period needs no bits-to-time step -- the step already shown to be invalid. Three wraps, each exactly loop_end -> loop_start, and BOTH CONTEXTS WRAP AT THE SAME INSTANT all three times. That is the property two stems of one performance must have and the one the linear conversion could not deliver (62.34 vs 63.29 s would drift a second per cycle). Cycle 61.56 and 62.06 s, mean 61.81, against the audio autocorrelation's 61.93 -- 0.2 % apart from instruments sharing nothing. Linearity refuted a second time and internally: the fitted rate over 10..60 s is 341 394 bits/s while the cycle covers 22 034 741 bits in 61.81 s = 356 491 bits/s, 4.4 % apart inside one stream. My own audio locator's PLACEMENT is refuted. loop_start at 3.6 M bits is 11.6 % of the stream by any reading, ~10.1 s at the cycle's own mean rate, against the 0.25 s that page reported -- for the reason already suspected, that its control matched slices cut from the wave itself and never tested the aliasing the real problem has. The length was right and the span was wrong. Still not measured: loop_start in seconds. Offsets below it play exactly once and this trace stamped that whole stretch at t=0.002, swallowing the log backlog in one read, because it started after the music. The fix is to start the trace before tapping into the menu -- one line, not done. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Wuu56cE8vJGTBtn1ppsk8v |
||
|
|
cf6be709ab |
re: the loop IS a runtime XMA field -- and reading it contradicts my audio measurement
No Canary patch was needed: UpdateLoopStatus already logs loop_start/loop_end, they just need the Apu category (--log_mask=13 --log_level=3). Decoded, from the menu, 8734 records all after BGM_103's contexts appear: ctx0 (wave 3876864) loop_start 3605682 loop_end 25640423 loop_count 255 ctx1 (wave 3930112) loop_start 3539158 loop_end 26216351 loop_count 255 The movie's three ADV streams log NO loop records -- they do not loop. Semantics visible in the trajectory: read_offset runs from 32 upward and 20 % of samples sit below loop_start, so the stream plays from the beginning and loop_start is where it returns AFTER loop_end. No wrap was observed -- the 45 s hold ended with read_offset at 17 M against a loop_end of 25.6 M. Two registered predictions REFUTED. loop_start is not ~0 but 11.6 % in. And a linear bits-to-seconds conversion is invalid: it gives 62.34 s and 63.29 s for two stems that must play sample-synchronously, which is impossible, so the data refutes the assumption on its own. That leaves a conflict I am not resolving: the field implies a cycle of roughly [10 s, 72 s]; my audio tracking reported offsets 0.25..57.18 s. Recorded as contested, with the likely weak link named as mine -- that locator's control used slices cut from the wave itself, exact copies, which is an easier problem than matching a real capture, and a control easier than the measurement does not bound its error. The port is told to change nothing: its trimmed 61.93 s loop is verified in its own output, and the length survives better than the placement. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Wuu56cE8vJGTBtn1ppsk8v |
||
|
|
5f386111ad |
re: count the voice-region population properly -- 25 three-chunk, and 17 of them were broken
Pays the debt from the truncated audit. The census prints population, coverage and skips in the same output, and ends with an explicit END line, so a cut-short run cannot be read as a complete one. POPULATION 104 movies; COVERAGE 95 resolved, 9 unresolved, 0 unreadable 70 one-chunk regions, 25 three-chunk regions The port's 25 was right; my '8 of 10' was not a count. Cross-referenced against the fix's own sweep, which also ran to completion (78 + 17 + 9 = 104): all 17 changed regions are three-chunk, none is one-chunk, and 8 three-chunk regions were never affected -- which the 1.5 MB cap predicts, since a region only trips the filter if its span exceeds it. So 'the defect is specific to the multichannel regions' survives with complete populations on both sides, while 'all three-chunk regions were broken' does not. The original 8-of-10 was wrong in its denominator and coincidentally shares a digit with the 8 that are unaffected, which is the kind of resemblance that carries a dead number into a later document. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Wuu56cE8vJGTBtn1ppsk8v |
||
|
|
45a21f0d33 |
method: a sound instrument, a correct number, and the wrong sentence around it
Named by the port after hitting it twice in a fortnight -- a real 3.4 s seam written up as the cost of a missing loop point when our own loop produced it, and a real r=0.998 correlation written up as a duplicate when it was a start-truncated simultaneous stream. Distinct from everything else in this file, which is about broken or misspecified instruments. Controls test whether a measurement is faithful and say nothing about the clause that follows it. The defences that work are naming the alternative explanation so it can be rejected, and noticing when a measurement taken in OUR output is being used to make a claim about THE GAME. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Wuu56cE8vJGTBtn1ppsk8v |
||
|
|
fa832fad1e |
re: the menu BGM loops at 61.93 s, and the game never reaches the fade
240 s parked on the main menu, reached by using the XMA probe log as the screen oracle instead of video -- the route the previous iteration wrote down. Menu in 26.8 s against never-in-378 s for the video rig, guest at 0.92x, capture at 0.08 % silence against the recipe page's own best of 0.31 %. BGM_103's contexts verify the screen and no ADV context appears afterwards, so the attract loop never took over. Three results, two instruments. NO SEAM: zero runs >= 0.3 s below median-18 dB in 232 s. The port's 3.4 s near-silence is a property of its authored loop, not of the game. NOT THE WAVE LENGTH: autocorrelation r at 87.750 s is -0.009 on four independent windows; the top lag is 61.909 s with a 2x harmonic. Estimator controls recover 87.750 and 60.000 exactly. 61.93 s, INDEPENDENTLY: locating 30 s slices of the capture inside the decoded summed waves shows playback advancing exactly +5.00 s per 5 s and wrapping at 61.93, from three wraps. Control: slices cut from the wave itself at 10/45/70 s are found at 10.00/45.00/70.00. Two points mis-lock where the slice straddles a wrap and they carry the two lowest scores in the table. Offsets span 0.25..57.18 s of an 87.744 s wave, so the loop is [~0, 61.93) and the final ~25.8 s is never played -- exactly where bgm-two-stems.md found the fade-out and trailing silence. The game loops before the fade, which is why there is no seam. Also corrects my own '8 of 10 three-chunk regions start mid-stream'. The port counts 25 three-chunk regions; it is right that both numbers cannot describe the same set. My audit run was CUT SHORT -- the committed file ends mid-list with no summary line -- so that was a ratio over an unknown fraction of the population, and the claim that the defect is specific to multichannel regions is now unsupported. The ADV verification and the fix's own sweep are unaffected; that sweep ran to completion and printed its totals. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Wuu56cE8vJGTBtn1ppsk8v |
||
|
|
57035a700b |
handoff: the menu BGM loop is attempted and not captured; the route left
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Wuu56cE8vJGTBtn1ppsk8v |
||
|
|
4ce639c63d |
re: the menu BGM loop is NOT captured -- and the rig that cannot take it
Recorded per 'do not improvise around a blocker'. The question is what the game does at BGM_103's loop seam, where the corpus has 'not a seamless loop, no loop-point field found, so the menu loop is authored' and the port measures a 3.4 s near-silent seam. Audio needs the ALSA tee; detecting the title needs video, so --gpu=null was unavailable. Measured twice: the guest runs at ~0.20x real time (76.5 s of audio in 378 s of wall clock) and the title is not reached in 300 s even after tapping A to skip the movie, with the tee's slave ending in a broken pipe and Xenia in underrun recovery. Not a crash -- rss 701 MB with 9.5 GB free, and the 'Killed' line is this harness's own cleanup. REFUTED along the way: CONTAINER-NOTES says --gpu=null runs here die at ~70 s. The intro-audio capture ran 148.02 s under --gpu=null and ended on its probe's timer with the emulator alive and the whole ADV movie decoded. More than twice the quoted lifetime. That note had been the reason not to use --gpu=null for anything long, which is exactly what a clean audio capture needs. The route left, written down rather than attempted: use the XMA probe log as the screen oracle instead of video. Sitting on the main menu decodes exactly BGM_103's two waves, so their byte_sizes appearing IS the menu -- which is better provenance for an audio question than a screenshot anyway. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Wuu56cE8vJGTBtn1ppsk8v |
||
|
|
3392982e58 |
method: over-warning is what makes the next real warning unreadable
From the port, after two rounds of its 'known incomplete' banner firing wrongly -- once with a message true only for ADV, once claiming a gap over 93.694 s of exact zeroes. Both errors were in the cautious direction, which feels like the safe mistake and therefore goes unexamined longer than a false all-clear would; the cost is deferred onto the one occasion the warning is true. A warning needs the same scrutiny as an assertion, starting with what it keys on. Also records S00A's kept count moving 1 -> 2 after the voice-region fix, on an asset the fix was not derived from and with the prediction preceding the observation -- at the strength it actually has. A different ASSET is evidence about generality; a different IMPLEMENTATION is what would make it independent, and only one of those was present. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Wuu56cE8vJGTBtn1ppsk8v |
||
|
|
dbb12036c1 |
method: an internal check cannot catch a bug that makes the input smaller
The voice-region truncation survived every test because there was nothing to catch: the region parsed, the chunks decoded, the durations were self-consistent. A missing third of a stream is smaller VALID output, and no check written against our own output distinguishes that from correct output. What caught it was a number from outside -- the running decoder's byte_sizes not fitting the region. So: prefer at least one test per decoder pinned to something we did not produce, and say so in the test, because the obvious maintenance of such a test is to re-baseline it against current output, which deletes the only thing it was for. Plus the port's corollary: it was checkable only because the identifier happened to be a byte count. Index a handed-over result by a quantity the recipient can test. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Wuu56cE8vJGTBtn1ppsk8v |
||
|
|
3dbfa320ae |
formats: drop the 1.5 MB cap that truncated 17 voice regions' first stream
The cause, and the fix, with a disc-wide check. resolve_movie_voice_region picks start = the predecessor cue's trailer, then filtered it with 'end - s < 1_500_000' -- 'only within one bank'. ADV's predecessor sits 3 618 816 B before end, so the filter rejected it and start fell back to anchor, which is a TOC offset and not a stream boundary. That explains the shape of the defect exactly: it strikes regions larger than 1.5 MB, which is why the three-stream multichannel regions are hit and single-stream ones never are. 17 of 95 resolving movies took the fallback. ADV's predecessor trailer at 433 425 776 plus 17 040 B of descriptor and padding is 433 442 816 -- the -238-packet start measured against the decoder, to the byte. Dropping the cap: unchanged 78, fixed cleanly 17, changed in any other way ZERO. In all 17 the only difference is a larger first chunk with every later chunk byte-identical, which is what a corrected start looks like and what pulling in a neighbouring asset does not. Regression test pinned to the RUNNING DECODER's byte_sizes rather than to this crate's own output. That is the point of it: every internal check passed happily while a third of a stream was missing, so only an external number could have caught this class of bug. sylpheed-formats: 136 tests pass, 0 fail (the one still running at commit time is an unrelated long mesh test). Exact clips for the other 16 are not independently verified -- the sweep is strong but ADV is the only one with a decoder measurement behind it. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Wuu56cE8vJGTBtn1ppsk8vformats-pin-2026-08-30 |
||
|
|
fb6095ae3a |
handoff: tell the port its refusal found a decoder defect, and what is safe to use
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Wuu56cE8vJGTBtn1ppsk8v |
||
|
|
3e8235ddbd |
re: resolve_movie_voice_region starts INSIDE the first stream, 8 of 10 multichannel regions
Found because the port refused to apply my stream assignment and did the arithmetic instead: the running decoder's three ADV contexts sum to 3 584 000 B against a resolved region of 3 114 352 -- 15 % too small to hold them. Two spans, one wrong, and it was the disc side. The gap is 238 packets exactly (487 424 B), which is what a start offset looks like; ctx0 declares 632 packets and the resolver's leading chunk has 394. Verified against the decoder's own byte_sizes, which cannot be fitted to: at -238 packets to_xma_riffs yields [1294336, 1118208, 1171456], all three exactly. It is a real boundary and not the end of a sweep -- at -300 the previous asset's chunks appear while the three ADV sizes stay stable. Disc-wide: 24 of 24 single-chunk regions start at a boundary; 8 of 10 three-chunk regions start mid-stream. The defect is specific to the multichannel case. The audit's per-movie number is an UPPER BOUND, not the clip -- its stopping rule is the chunk count changing, and to_xma_riffs absorbs a few packets of the previous asset first (243 reported for ADV against a true 238). Only ADV has external ground truth. Consequence: in those 8 movies the leading chunk is a truncated first stream, not a spurious artefact, and anything measured on it was measured on a fragment -- including this corpus's own chunk-0 level, though the assignment survives because its ratio test was chosen to be immune to the clipping. The resolver is NOT patched. Why the predecessor cue's trailer lands 238 packets into the next asset is unanswered, and a fix guessed from one movie would be worse than a documented defect. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Wuu56cE8vJGTBtn1ppsk8v |
||
|
|
8c71520ab8 |
re: which ADV stream sits where -- settled by level, not by waveform
Completes ask #4. The three chunks were dumped from the resolved voice region and decoded; the assignment is ctx0 -> FL/FR, ctx1 -> FC with LFE silent, ctx2 -> BL/BR. Two instruments failed first and both look like results, so both are recorded. Envelope correlation with a per-pair lag search returns 0.86-0.95 for EVERY chunk against EVERY channel, because all six residual channels share the dialogue's activity timing -- that is an instrument with no resolving power, not a finding. Sample-level correlation returns about zero, because the chunks do not start with the movie and the XMA decode's framing offset is unknown. Level settles it under the same 0.600 gain the bed uses: each stream lands within 0.5 dB of exactly one residual pair and misses the others by 4-6 dB. The ratio test is immune to chunk 0 being a clipped tail of ctx0 -- chunk0 - chunk2 is +5.88 dB against FL - BL at +6.18 dB, agreeing to 0.30 dB, where a swap would be wrong by 11.76 dB. Structural confirmation: chunk 1 is the only chunk with a digitally silent channel and LFE is the only output channel with an empty residual (-115.73 dBFS), one to one; and the internal L/R correlations track the residual pairs' (0.932 vs 0.918, 0.962 vs 0.929). Worth having on its own: the same 0.600 scales both the movie bed and the voice, so it is one mixer gain rather than two. Reach: levels, not waveforms; one boot, one movie; and whether 0.600 is a fixed constant or a volume setting is still unknown. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Wuu56cE8vJGTBtn1ppsk8v |
||
|
|
59f5bf1b59 |
method: a rule learned from a burn generalises by resemblance, not by mechanism
From the port agent. This file already carries two divisor bugs of the same shape -- a silent input in a divisor attenuating real signal -- and the lesson taken from them was 'be suspicious of dividing by N'. Applied to the intro's three streams it produced a unity sum that the port's own checker rejected at +2.62 dBFS. The precedent did not transfer because a BGM bank's two waves are stems of one signal while the intro's three streams are positions in a field, whose downmix weights sum to one whatever the assignment. Nothing in 'several streams, one output' distinguishes those. The general point: a rule extracted from a burn is indexed by what the burn looked like rather than by why it happened, so it fires on the next thing with the same silhouette while feeling well-earned. State the mechanism a past lesson turned on and check that mechanism is present. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Wuu56cE8vJGTBtn1ppsk8v |
||
|
|
232ae0fa9c |
re: ask #4 answered -- the intro is a 5.1 WMAPro bed at 0.600 plus three streams
ADV.wmv carries ONE audio stream and it is wmapro 5.1, not XMA. Any framing of the intro's audio as only 'which of three voice streams to ship' was missing the bed. Aligned the 148 s capture against that track (envelope r 0.769 against a median of -0.001, refined to +224 samples, r 0.900) and solved capture = g x movie + residual per channel. The gain is 0.600 on every channel -- a uniform -4.44 dB, a mixer setting rather than a fit artefact. LFE reproduces to -115.73 dBFS, 72 dB down, which is what rules out codec difference as the explanation for the other residuals. FC is the exception: the movie explains NOTHING of it (-0.09 dB), and the movie's own FC is 91.6 % silent. The residual is three signals, not one: a front pair (r 0.918), a rear pair (r 0.929), and a centre whose partner LFE is empty. The FC residual spans 34 dB across 100 ms frames -- bursty, not steady noise. That CONFIRMS the corpus's 5.1 reading, which voice-three-streams-are-concurrent recorded as not established, and it confirms the specific detail it offered: that the mono-in-stereo stream is 'a centre paired with a silent LFE'. Measured from the output with no access to the stream contents. Also corrects my own census page: it labelled channels with the ALSA permutation [0,1,4,5,2,3] from the recipe page, which does NOT apply to this capture. The 6x6 matrix was computed assuming no order, every row's max falls on a distinct movie channel, and the answer is the identity -- so the census's 'BR is 82 % silent' was really LFE, reconciling with the movie's own 80.64 % silent LFE. Reach: one boot, one movie; which XMA context is front/centre/rear is not determined, only that the residual occupies those positions; and whether 0.600 is a fixed constant or a volume setting is unknown. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Wuu56cE8vJGTBtn1ppsk8v |
||
|
|
ef4ea8fe86 |
re: the boot intro's audio output -- five live channels, not a stereo mix
Groundwork for the port's ask #4; it does not settle #4. Captured the game's own output over the boot intro following the ALSA file-tee recipe exactly -- paced pulse slave, --gpu=null, both mutes off. 148.02 s, 6ch float32 48 kHz, 0.15-0.16 % silence against the 0.31 % the recipe page records for its own clean run. Provenance is the XMA probe rather than a screenshot, which is the right evidence for an audio question: ADV's three contexts appear byte-exact (1294336 / 1118208 / 1171456), then the documented BGM_102 pair. Five of the six channels carry distinct content; BR is 82 % silent and 11-15 dB down. No channel is a copy of another -- the largest pairwise correlation is 0.70 between FL and FR. That rules out a stereo mix, so 'ship one stream' cannot be right and the port's held-wrong value stays wrong. It does NOT establish that summing is right, and the 6-channel count is Xenia's hardcoded kFrameChannelsDefault -- what is evidence is that five of them differ, which a stereo guest cannot produce. NOT settled and named as such: the stream-to-channel mapping. The cross-correlation of each captured channel against each decoded ADV stream has not been run. One boot, one movie, and --gpu=null means no video cross-check. Raw is 170 MB and is not committed; sent over share to the port. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Wuu56cE8vJGTBtn1ppsk8v |
||
|
|
6f87ecc4db |
re: the pulse floor gets a second witness, and two METHOD entries
The port reproduced the floor exactly (159) once the predicate was named, and counted an independent capture from a different session: 753 against this run's 714, a ratio of 4.7x against 4.6x. 'Never goes off' is no longer single-run. Two METHOD entries. A detector that can fire on a single frame will fire on the wrong one. The A/B's first pair was void because the title detector tested one frame against a glyph threshold and the intro movie throws sub-second green flashes of 1298..5433. The presses were real and skipped the movie, so both legs returned a clean, symmetric, meaningless result -- a void test that looks like it ran is worse than one that errors. Same shape the corpus already recorded for screen_id.py calling the SQUARE ENIX logo 'title'. Twice paid for. The rule is that a screen detector matches a signature over time, and a broken run's own series is the cheapest control for its replacement. A demand for reproducibility can surface a defect that is not the one demanded. The literal answer to 'your figures are unverifiable' was 'here is the predicate', after which they verified exactly -- but writing the method down is what exposed the cross-geometry floor comparison, which nobody was looking for. And both sides were wrong at once: the challenger's counts were the wrong measurement AND the published figure had a real flaw. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Wuu56cE8vJGTBtn1ppsk8v |
||
|
|
e0de5c6f22 |
re: the A-press A/B is run -- signed-in profile, no swallow, menu opens
The debt from two iterations ago. Two boots, same binary and ISO, one A tap each, fired only after the plate's pulse had been seen for 12 consecutive samples. ARGV recorded per leg, because the config dump provably cannot say. leg A no profile flag 3811 swallow lines and climbing leg B --logged_profile_... 0 swallow lines, final glyph 327 = MAIN MENU 327 is the documented main-menu glyph count, reproduced by this instrument's own control, so leg B's press opened the menu. Capture committed. Leg A demonstrates the SWALLOW, not the crash: I stopped it at ~2.3 M swallowed calls because kernel tracing at log_level=3 was eating the 300 MB budget the crash dumps need. The fault itself remains measured once, historically. One run per leg. A void pair came first and is recorded, because it is why the detector is what it is. The first version fired on a single frame over a glyph threshold and hit the INTRO MOVIE -- green flashes of 1298..5433 lasting under a second -- about 6 s before the title, in both legs. The presses were real (each skipped the rest of the movie, which is Q9's behaviour) but the pair tested nothing. The fixed detector requires 12 consecutive in-band samples, and was replayed against the void runs' own series as its control: it declines the movie flash at 84.8/85.5 s and fires at 93.9/94.7 s inside the sustained pulse. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Wuu56cE8vJGTBtn1ppsk8v |
||
|
|
6072d216a8 |
re: name the region and the threshold -- and the floor was cross-geometry
The port agent could not reproduce this page's 159/714/1520 from the capture it holds: counting green>150..200 over a plate box it got 3-5x at every threshold. The page named neither the region nor the predicate. Stated now: the whole 1280x720 frame, and is_title.py's three-channel predicate (g>130 & g-r>45 & g-b>45), which is why it counts far fewer pixels than a bare green>N. That reproduces 1520/714/159 exactly. Writing the method down exposed a defect the prose had hidden. The 159 floor came from live-title-build4-no-plate.png at 1279x675 -- the game surface -- while the pulse frames are 1280x720, the whole display. Different crops, silently compared. Replaced with a same-run, same-geometry floor that was in the series all along: 154, flat for ~2 s immediately before the plate ramps in. So 'it never goes off' now rests on one run in one geometry, at 714 against 154, which is where it should have rested from the start. The port's independent ratio of 1:10.4-10.9 brackets this page's 1:9.6 and is the part robust to how anyone counts. Two METHOD entries: a pixel figure needs its region and its predicate, and a comparison between two counts needs them to share a geometry; and the port's observation that a fix which overshoots leaves no symptom until a third change needs the part it disabled. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Wuu56cE8vJGTBtn1ppsk8v |
||
|
|
b6f0cf3fb2 |
re: RETRACT -- a Canary config dump is the FILE, not the run
Refuted my own evidence with a direct test. The A-press fault page cited the faulting run's dumped logged_profile_slot_0_xuid = "" as proof no profile was signed in. Xenia prints its config dump BEFORE applying command-line overrides: in a run launched with --apu=sdl --hid=file --mute=true --log_mask=13, the dump says apu="any", hid="any", mute=false, log_mask=0. Four for four. So the dump is a statement about xenia-canary.config.toml and nothing else, and this page cannot know the faulting run's profile state. Anything in the corpus citing a config dump as evidence of what a run did is making the same mistake; to know a run's settings, record its argv. Survives: the mechanism (swallow -> unbounded pump -> failed allocation -> fault), which rests on the [RE-INPUT] counter and the crash dump's registers; and canary-scripted-input-traps.md section 3's measured sign-in-dialog claim, which has a capture behind it. Also records the port's base-plus-glow mechanism for the plate, which explains why the pulse floor is 714 rather than the plate-absent 159 -- ptbtn00's fade at t=244 is an exit ramp so the base holds at 255 while the screen is held, and ptbtn00f's 0->80->0 glow draws over it. Marked as agreeing with the measurement, not confirming it: their renderer is not an oracle. It does rule out a glow-only plate, which could not produce a non-zero floor. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Wuu56cE8vJGTBtn1ppsk8v |
||
|
|
3c004845fa |
re: the PRESS A plate PULSES -- measured, and it keeps an authored entry
Answers the port's ask #1, which it had flagged as the only one of its four that could delete an authored entry rather than confirm one. It confirms one. Held at the title with no input, the plate oscillates continuously: two windows in one boot, 58 s and 57 s, ~23 cycles each, no decay. Periods 2.530 and 2.540 s by upward mid-crossings -- 0.4 % apart. It never goes off. The plate-absent floor is 159 green pixels, measured on the committed live-title-build4-no-plate.png; the pulse bottoms at 714, 4.5x that. So the port's 'flash and nothing after', reasoned from ptbtn00 expiring at t=244, is wrong on the boot's end state -- ptbtn00f's 120-unit cycle is what runs. Instrument controls were run before it was pointed at anything unknown: the glyph counter reproduces the documented 753 on live-title-press-a.png and 327 on live-main-menu.png exactly. Two estimators, and only one replicates. Mid-crossings agree across the two windows to 0.4 %; a single-sinusoid least-squares fit does not (2.553 vs 2.413), because the waveform is fast-rise/slow-decay rather than sinusoidal -- its own r2 of 0.468 and 0.228 is the tell. Both were controlled on synthetic sinusoids at 2.24/2.55/3.10 s laid on the ACTUAL timestamps and recovered every one exactly, so neither is broken; one is misspecified. Recorded as such. The wall-clock is 13 % longer than the corpus's earlier 2.24 s mean. Same declared 120 units, different emulator pacing (x1.27 here against x1.12), so this corroborates 'author the units' rather than disturbing it. Reach stated: one boot; does not distinguish the boot title from an attract-loop title; and the glyph count is a thresholded pixel count, so 714/1520 is not an alpha ratio and no duty cycle can be read off it. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Wuu56cE8vJGTBtn1ppsk8v |
||
|
|
ec06c50bf6 |
method: the mirror trap -- two records that drift, and a weakened control
Two corrections from the port agent, both of which make earlier claims smaller. 1. Its 'reproduces your published centres to half a pixel' was model against model. This corpus's 981/478 are the model's output at t=355, not the capture's; the capture measured 992.0/467.2, the 11.5 px residual the page declines to fit. So that control shows two implementations of one model agreeing, not the model matching the oracle. Neither of us applied the correlated-instrument test to that sentence at the time. The discriminator survives: it asks whether two captures are the same frame, and the model is monotone in t at ~4 px/unit, so a 42-unit gap cannot come out of one frame however wrong the absolute times are. Recorded as such. 2. Running my 'grep for the symptom' audit against its own tree, the port found the opposite failure: a control recorded in BOTH a tool table and a document, drifted to 53.3 % and 53.2 %, with the evidence file gone so neither can be re-measured. One hard-to-find record announces itself as missing; two disagreeing records announce nothing, which is worse. So the rule is not 'write it down twice' -- one record in docs/re/, everything else cites it, and any number that must appear twice is generated rather than typed. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Wuu56cE8vJGTBtn1ppsk8v |
||
|
|
8dfa0ebac5 |
re: the A-press dialog is the SIGN-IN dialog -- and the corpus already knew
Answers the open half of the A-press diagnosis, and most of the answer was already in the tree. The faulting runs booted with logged_profile_slot_0_xuid = "" -- their own config dump -- while a profile existed (Found 1 Profiles). With nobody signed in, A takes the state-0 branch of sub_821D03A0 and calls XamShowSigninUI(1,1); Canary raises its Sign In dialog with a no-op close handler and nothing in an unattended run dismisses it. 85 instructions verified against the image, 0 mismatches; the state-3 branch is XamShowDeviceSelectorUI, already ruled out by storage_selection_dialog = false. The correlation runs through the tooling: boot_menu.sh passes the profile flag and Q4/Q5 pressed all five buttons; frame_clock.sh, which produced the faulting run, does not. So there is no blocker -- boot with boot_menu.sh. Flagged as retrodicted rather than A/B tested, since I have not myself booted both ways and pressed A. The uncomfortable half: canary-scripted-input-traps.md section 3 already named the sign-in dialog WITH a committed capture, and boot_menu.sh's header already carried the mechanism and the 8.4 million figure. The fault page searched for the cause it had hypothesised and never searched for its own symptom. Added to METHOD.md, along with the more expensive lesson -- a measurement whose only record is a script comment is invisible to the document that needs it. What this session did add is the join: that the known blackout is what drives an unbounded guest queue into a failed 128 MB allocation. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Wuu56cE8vJGTBtn1ppsk8v |
||
|
|
15d9037774 |
re: the sweep discriminator resolves -- 294.9 against a predicted 295
The port ran the check and returned 294.9. Different frames; both measurements stand. Its renderer also reproduces this page's published t=355 centres to half a pixel on both quads, which is the control that makes the 295 worth anything, and it confirms the 600/720 cycles from its own export rather than from the header word. Worth recording as method: the observable and the value were specified before the port computed anything, so it produced the number without knowing whether 295 was the pass or the fail. Neither agent checked its own instrument with its own instrument. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Wuu56cE8vJGTBtn1ppsk8v |
||
|
|
59f3ac6846 |
re: ask #2 -- t=357.7 came from a GPU draw capture, and a sweep cannot date a frame
The port asked whether the refined sweep fit t=357.7 was measured against live-title-build4-no-plate.png, because if so one of us is 42 units out. It was not. 357.7 was solved against title-draw-capture-vertex-colours.log, a GPU per-draw capture of the submitted vertex buffer -- four observables at once, two quad centres and two vertex alphas. No framebuffer, no PNG. The gap is not a fitting error either. Posing the leaves directly, t=400 misses the captured quads by +169.0 and -172.2 px. Probe control: it reproduces the page's published t=355 centres, 981 and 478, exactly. Refutation attempted and FAILED: I expected the port's fit to be minimised by the quad leaving the screen -- 'best fit' meaning 'draws least', the same shape as the .tbm control that could not fail. At t=400 quad B is fully on screen and quad A is 319 of 400 px. Their number is fitting something present and it survives. The real reason the two must differ is better than 'different frames'. The sweeps are nested records on a free-running loop and their cycles differ -- 600 and 720, read from the record header +0x08 -- while the top-level clock stops at settle. So two captures of the same settled title share a screen time and not a sweep phase, by construction. Consequence for the port: a sweep position does not date a frame; it gives a phase on a 600- or 720-unit loop. And 357.7 is a joint fit over both leaves while the port's ~400 poses one, so the two are not comparable in kind -- the phases coincide only every LCM 3 600 units. Discriminator handed to the port rather than taken: if its ~400 is pteff03 and the frame is in the first cycle, pteff03a must be at centre 295 in that same frame. The fit is against its renderer, so it owns the check. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Wuu56cE8vJGTBtn1ppsk8v |
||
|
|
bec7f02c0a |
re: not ONE of the 80 forced instances has a file-read key
The port agent pointed out that forced_backdrop_necessity.rs collapsed
sprite_layer_key (a u16 read from the T8aD header, decoded) with
implied_layer_key (this crate's table of positions MEASURED in the running
game), and that 'has its own key' therefore reads as file-backed when it is
not. Splitting them is stronger than either of us stated:
read from the T8aD header: 0
implied (measured): 14 10x pfbase.tbm, 4x palogo_eff0.prm
nothing at all: 66 62 decided, 4 inert
Zero. There is no instance on the disc where a forced element also carries a
file-read layer key, so this rule has never been checked against a decoded
field -- there is no case where both can speak. That is what a keyless-element
fallback necessarily looks like, but it removes a check a reader would assume
exists.
Also corrects something I said to the port and had wrong. 'None of the 18 is
evidence for the rule in any direction' conflated two questions. Whether the
rule changes the composite: no, the sort already had the key. Whether the rule
gets the RIGHT answer: yes, and the 14 implied keys are measured positions, so
this is the rule agreeing with the oracle -- its only external corroboration,
and there are 14 instances of it.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Wuu56cE8vJGTBtn1ppsk8v
|
||
|
|
f8abb56bc4 |
re: reconcile the two ink counts -- we agree at >1 and not at >0
The port agent produced a genuine second witness for the pixel-cost claim: it
re-checked GP_TITLE entry 12 in Godot, which shares no code with compose,
swapping only paint_order. 59 530 px ink with the rule, exactly 0 without it.
The strong form -- the screen ceasing to exist, not merely changing a lot --
now has two real renderers behind it on that entry.
Its figures did not match ours, so I counted the same composite every way:
RGB > 0 ours 49 771 Godot 59 530 16 % apart
RGB > 1 ours 48 043 Godot 48 368 0.68 % apart
The entire disagreement lives in pixels whose value is exactly 1. That is a
1-LSB sampling artefact between two samplers, not a different set of inked
pixels. So '>0' is not a portable ink convention between renderers on a
mostly-dark frame and '>1' is; any future cross-renderer ink figure should say
which it used.
Also worth recording: our 49 771 was never a threshold figure. It is exact RGBA
inequality between the two paint orders, which over a black backdrop coincides
with ink>0 -- so it belongs against the port's 59 530, not its 48 368. Matching
it to the 48 368 would have made the two renderers look like they agreed for
the wrong reason.
The without-the-rule column is 0 at every threshold here too, matching Godot:
the strong form is not threshold-sensitive in either renderer.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Wuu56cE8vJGTBtn1ppsk8v
|
||
|
|
aa9b7ef340 |
re: the forced-backdrop rule's pixel cost -- 38 screens go black without it
Follows the necessity census. 'The order moves' is a property of the sort; the
tie-break work already found reorders costing zero pixels, so the picture
moving is a separate claim. Rendered each of the 62 deciding builds twice and
diffed.
38 .prm deciders: changed_px == ink_px in ALL 38. Without the rule the
primitive sorts last, paints over everything, and the
screen composites to pure black. The port's original
contradiction argument, measured on 38 builds across seven
archives instead of argued on two.
24 .tbm deciders: zero -- and that is MY INSTRUMENT, not a finding.
The control asked whether the composite had ink; it always does. The question
was whether the reordered ELEMENT has ink, and compose draws no pixels at all
for a .tbm. So those 24 zeros measure our renderer's blindness by construction.
tie_break_pixel_cost.rs already had the per-element ink_mask this needed.
Reported rather than quietly patched: a control that cannot fail is the shape
this corpus keeps paying for.
Also corrects two things the port agent caught:
- 'Two renderers, same answer' was true of the six GP_TITLE instances and not
of the other 74. The port's re-run of my probe is my code executed twice;
its independent leg was removing its own exporter post-pass, which covers
GP_TITLE only. The disc-wide 62 has one witness and the page now says so.
- forced_backdrop_necessity.rs defaulted to GP_TITLE with no argument, so a
bare run printed 6 instances in the same format as 80. It now walks every
dat/*.pak and reports the archive count.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Wuu56cE8vJGTBtn1ppsk8v
|
||
|
|
304ce9efaa |
re: forced_backdrop DECIDES 62 of its 80 instances, not 6
The port agent raised that every check this corpus ran on the rule measured its STABILITY -- that no verdict moved -- and never its NECESSITY. It is right, and the distinction is load-bearing. New probe: recompute derived_paint_order with the forced_backdrop fallback removed and diff the orders, over every dat/*.pak. 80 forced instances = 62 the rule DECIDES + 18 it merely AGREES with. The 80 reproduces the page's own census exactly, which is the check that the probe sees the same set. Every one of the 62 deciders is keyless; no keyed element is ever moved. Of the 18 that agree, 14 have their own key -- and that includes the palogo_eff0.prm 'control', whose implied key is 0x00000000 and would sort it first regardless. So that agreement is the rule reproducing our crate, not the game confirming the rule. The port saw this before I did. The remaining 4 are keyless but inert: every element on those two builds is forced, so the tie-break gives the same order either way. Confirms the port's GP_TITLE finding from the other side: entries 10/11/13/14 unchanged without the rule, entries 12/15 decided by it. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Wuu56cE8vJGTBtn1ppsk8v |
||
|
|
e94e203a71 |
re: the A-press fault is SOLVED -- Xenia swallows input, the guest pump is unbounded
The 326 MB log from the failing run was still on disk, so this needed no emulator time at all. Mechanism: Xenia's XamInputGetKeystrokeEx returns X_ERROR_SUCCESS with a zeroed keystroke on every call while a XAM dialog is up (xam_input.cc:197, upstream Canary). The game's keystroke pump -- sub_82457038, read out of the image -- is an unbounded 'while (GetKeystrokeEx() == SUCCESS) queue.push_back()'. It queued 8 388 608 empty keystrokes, grew its vector to 64 MB, asked for 128 MB, got a failed allocation back unchecked, and copied off the top of the guest stack. Two independent instruments agree to within 7: the Canary counter's last report before the crash says 8 388 601 swallowed calls; the crash dump's r29 says the vector held 8 388 608. The reporting granularity is 600. Retracts this page's own 'r9 is a wild pointer above 4 GB'. Xenia prints si_addr, a host address; the guest is mapped at 0x100000000, so the fault address is guest 0x701D0000 -- which is exactly r9 in the register dump. Also refutes nothing of the port's, but answers its ask #3: the two press-a captures are different frames (40.84 % of the band's pixels differ at the best alignment, which has a sharp minimum), so its 0.301 % is not an instrument floor. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Wuu56cE8vJGTBtn1ppsk8v |
||
|
|
6d7bc87b0f |
re: diagnose the A-press fault -- a wild pointer, and a third failure mode
The blocker on all menu-side dynamic RE in this container, measured over four runs and traced to an instruction. A single A press on the title produces a Xenia CRASH DUMP with PC 0x824578A0 and "Access Violation: write at 0x00000001701D0000", repeating 32 356 times and writing 326 MB of register dump in about ten seconds. Four A runs faulted; four no-input runs in the same sessions completed. REFUTED, my own hypothesis: it is not an unimplemented instruction. The config carries break_on_unimplemented_instructions = true and Xenia's own message reads "to skip, disable break_on_unimplemented_instructions", so the flag looked like the fix. Booting with it false faults identically, and no "Unimplemented instr" line is ever logged on stdout or stderr in any run -- and since that path emits its XELOGE BEFORE the guarded DebugBreak, the absence rules the mechanism out rather than leaving it open. The dump comes from Emulator::ExceptionCallback, a genuine guest exception. The instruction, read from the image rather than the database: b0c90000 is sth r6, 0(r9), the first of four halfword stores at offsets 0/2/4/6 through r9 inside a bne- loop -- code filling an array of 8-byte records with four u16 fields each. So r9 is a wild pointer, and 0x1701D0000 is above 4 GB, outside the guest's 32-bit address space entirely: not a null dereference and not a small overrun, but a base that was never a guest address. The database agrees on the containing function, sub_82457780 at +0x120. It is a THIRD failure mode. Not the cache-flush crash at 0x82307128, and not the loader stall documented in canary-scripted-input-traps.md, which logs ZERO crash dumps. Unlike the stall it reproduced 4 of 4, so that page's "retry whole boots" does not obviously apply. It does not explain how Q4 and Q5 pressed A successfully; what differs between those runs and these has not been found. frame_clock.sh's 300 MB guard killed the run as designed -- the session log's "EMULATOR GONE at 56s" is the guard, not the crash. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01QsEPXWVaEpyfudtR6re1Pd |
||
|
|
159778faf1 |
formats: test backdrop coverage per instant, and record where the .tbm hunt reached
Two things, neither of which moves a verdict. The port pointed out that rejecting on DECLARED size replaces one error with its mirror: an element scaled ABOVE 100% could cover the screen from a smaller declared size, and my guard would silently exclude it. Checked against the disc first: across 921 keyless elements, ZERO cover the screen only via scale, so the mirror case does not occur here. Adopted anyway, because the construction does not need that to stay true -- coverage is now tested per instant against the scaled size, alongside the opacity test, since both animate on the same ramp. 80 forced instances before and after, split 42 .prm / 38 .tbm, unchanged. Second: an attempt to upgrade the 38 .tbm verdicts from inferred to decoded by finding the texture and measuring its alpha coverage. It cannot be located. Not in its bundle (no RATC record, no sprite-table entry, for any of the 13 names); not a file (no .tbm anywhere on the disc); not a pak entry (its archive's hashed TOC contains none of the name, its uppercase form, its stem, .t32/.tga/.xpr variants, or ui\\ and tex\\ prefixes, across four archives); and not visible in our composite, since compose skips an element with no resolvable sprite, so we draw no pixels for a .tbm at all -- and no committed capture covers a screen that has one. So a second reading survives and is recorded rather than excluded: a .tbm may contribute no pixels, in which case its paint position is INERT rather than correct. That leaves the 38 harmless instead of right -- a different claim with the same consequence. Distinguishing them needs a capture of GP_SAVE_LOAD, GP_BUNK or GP_DEBRIEFING_PILOTLOG, all behind the A fault. One upgrade: pfbase.tbm's first position is MEASURED, not inferred -- it is element 0 of the save/load frame and the order read off the running game starts [0, 1, 2, ...]. Twelve of the thirteen .tbm names still rest on the rule. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01QsEPXWVaEpyfudtR6re1Pd |
||
|
|
29c99e1b3e |
re: primitive blend mode -- undecodable with reach, and no longer a risk
Looked in four places. The bundle has no field: a primitive has no RATC child at all and the declaration words are constant across every element of three measured screens -- the two grounds ui-prm-primitives.md already used to refute a bundle-side LAYER key, and they apply identically to blend. The colour census: every full-screen *eff00* primitive on the disc carries pure black at its various alphas, and the only non-black primitive anywhere is pbafc.prm, RGB 00e8e0 cyan. The occlusion constraint cannot reach that one. pbafc.prm looked alarming at a declared 844x600 and alpha ff; it is a small moving glint. It strobes between alpha 255 and 124 every 2 units, travels from x=178 to x=291, and is scaled 2%x3%, so it draws about 17x18 pixels. At that size it occludes essentially nothing. The oracle is unavailable: GP_READY_ROOM is a recorded no-go and gameplay needs the A press that faults the guest in this container. But the consequence closes even though the question does not. For a BLACK quad -- which is every primitive forced_backdrop touches -- the hypotheses differ only in whether it hides what is beneath. Drawn first it is correct under both; drawn last it is correct only under additive. So the rule's verdict is robust to the open question, and the port's original "layerless sorts last" was wrong under alpha-over and merely pointless under additive. This is explicitly NOT evidence for alpha-over. The investigation also found forced_backdrop judging coverage from the pivot alone, ignoring scale -- pbafc.prm is the disc's own proof that a nominally 844x600 element can draw at 2%. Checked before changing anything: all 80 forced instances are at scale 100% on every opaque instant, so no verdict moved. The guard now requires scale >= 100 at the instants it counts as opaque. Defensive, not a fix. 4 + 13 disc tests green either side. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01QsEPXWVaEpyfudtR6re1Pd |
||
|
|
1f6e07598e |
re: the primitive colour census -- and it refutes 38 of my own 80 forced verdicts
A disc-wide census of the ARGB that keyless elements carry. Every full-screen *eff00* PRIMITIVE is pure black at its various alphas (ff000000, 7f000000, 40000000, b2000000, cc000000, d4000000, 00000000). Black at alpha a over content is exactly an alpha-over dim or fade, and an additive black quad would be a no-op nobody would author -- so this narrows the open blend question a long way. The only non-black primitive on the disc is pbafc.prm, RGB 00e8e0 cyan at alphas up to ff, and it is 844x600, NOT full-screen, so it sits outside forced_backdrop's geometry guard. It is now the sole additive candidate. The census also refutes my own argument for nearly half its verdicts. Of the 80 forced-first instances only 42 are .prm; 38 are .tbm carrying fade ffffffff. A SOLID white quad at alpha 255 painted first would make the screen white, and no screen is white -- so a .tbm is a white modulation on a texture, and element alpha does not establish its coverage. That is the .t32 error one file extension further out. I guarded that with el.sprite.is_some(), which fixed the symptom and not the cause: an element's alpha is not its texture's opacity, and only an untextured primitive makes the two the same fact. So 42 verdicts stay decoded and 38 drop to inferred -- still almost certainly right, since all are named *base*, all are full-screen, and pfbase.tbm's first position is measured in the running game, but that is a name-and-role argument which this page elsewhere calls the weaker kind. The code is deliberately unchanged. Restricting forced_backdrop to .prm would send eleven screens' backgrounds back to u32::MAX -- last -- which is the blank-screen bug the rule was written to fix. Downgrading the status is honest; reverting the position would be wrong. The 42/38 split is pinned by a test so anyone tightening the rule sees what it costs. Separately, on the port's black_hold_units ask: four more no-input boots yielded one usable log, which armed late and missed the publisher splash, so the sample is still two runs spanning 3 and 4 frames. Their 6.5-9.2 range stands. And a reason it may not be resolvable this way: the draw log DROPS frame numbers -- in the 3-frame run, frames 121 and 124 are absent entirely, so "frames with no sprite" and "span of frame numbers" are different quantities. Their statistical correction is taken: at n=3 the sample SD (3.893) is the estimator, not the population SD (3.179), making my run 1.88 sigma from the corpus mean rather than 2.31. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01QsEPXWVaEpyfudtR6re1Pd |
||
|
|
7a5f7b886a |
re: downgrade -- the drift explains the 4.1% in sign, not magnitude
The port refuted the stronger half of the last claim and was right. I wrote that the units/frame drift explained the publisher splash's 4.1% error against its declared dwell. It explains the sign only. Their test verified exactly here: the publisher/developer dwell ratio is 1.2143 declared, 1.2784 as the corpus's three cold boots measure it, and 1.3678 as this container's drift predicts -- so the drift's direction is right and real evidence, but its magnitude is about 2.4x too strong. One refinement, because the means are being compared more finely than n=3 supports: the corpus's three boots individually give excesses of +0.89%, +8.24% and +6.79%, a spread of 7.3 percentage points -- WIDER than the 5.30 pp gap under test -- and boot 1's ratio (1.2251) is essentially the declared 1.2143. This run sits 2.3 sigma above their mean: suggestive, not established. Not closable without a frame log from the corpus's instrument, which was screenshot timing and has none. An attempt to give this side an n of 3 failed on tooling and is recorded: ARM=early loses its F10 about 40% of the time -- two of five runs logged "ARMED EARLY" and produced no draw log at all, with nothing in the session log distinguishing them. Also fences the 33% drift against a misreading the port flagged: it is PRESENTATION pacing and cannot reach keyframe_units_per_second = 60, which is the game's logical rate, decoded under Q1, and which a renderer converts through at its own frame rate. And records a cross-check neither side went looking for: the batch counts are 1 and 2 on the publisher against 3 and 6 on the developer, and the port reports a count restricted to SPRITE-BEARING elements reproduces that exactly from the export -- so palogo_eff0, the layerless forced backdrop, is not in the batched draw, confirmed from the file. Two instruments that disagreed about that element in every previous iteration now agree on which one it is. New tool splash_boundaries.py carries the corrected counting method. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01QsEPXWVaEpyfudtR6re1Pd |
||
|
|
6c8ab5db94 |
re: withdraw the splash frame boundaries -- count the batch, not the logged quads
The port refuted the boundaries in boot-splash-dwells-are-declared.md by arithmetic: the two splash spans gave 2.237 and 2.414 units/frame, 7.9% apart on one boot of one guest, which must be one number. They proposed the spans were anchored on different elements. The log says the cause is worse. The developer splash batches SIX quads into one draw (indices=24) and the log dumps only the first two. While the three glows are alive they occupy that prefix, so the three wordmarks are invisible to the log until the glows stop being submitted at t=45. "Developer wordmarks first drawn at frame 140" was the logging prefix shifting, not the game -- and the same defect explains why palogo_anima never appeared at all. The fix costs nothing: indices/4 is how many quads the draw actually holds, and the 8-vertex cap cannot touch it. Its transitions land exactly where the declared count of elements with alpha>0 changes, giving free calibration points: publisher 1->2 quads at frame 5.5 (t=15), 2->1 at 22.5 (t=45), ends 119.5 (t=255) developer 3->6 quads at frame 126.5 (t=15), 6->3 at 139.5 (t=45), ends 209.5 (t=210) That yields 1.765 and 2.165 units/frame on the publisher, 2.308 and 2.357 on the developer -- the developer's two independent segments agreeing to 2%, and the rate rising 33% across the run. One cause for both the port's 7.9% inconsistency and this page's open 4.1% publisher error, exactly as they predicted: the publisher splash runs during the first seconds, where the rate is furthest from its later value. It also means no single units-per-frame figure describes a run here, which is the dwell-is-emulator-paced conclusion from a third direction. The declared dwells (255 and 210 units) and the corpus's three-cold-boot confirmation are untouched -- neither uses this draw log. METHOD.md gains the general form: when an instrument truncates, the surviving sample is not random, it is the first N, and what falls in the first N is itself a moving function of the thing being measured. A truncated view looks like a complete view of a smaller set. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01QsEPXWVaEpyfudtR6re1Pd |
||
|
|
acaacc36e0 |
re: the boot splash dwells are declared -- and wall clock is the wrong unit
The port asked for two wall-clock timestamps across the boot splashes. Measured, and the measurement's own result is that timestamps are not the invariant. The dwells are the bundles' own declared timelines: publisher t=0..255 = 4.250 s at 60 units/s, developer t=0..210 = 3.500 s. The corpus's independent screenshot timing over three cold boots gives 4.30/4.60/4.37 and 3.51/3.50/3.37 -- the developer agreeing to 1.1%, two of its three runs to 0.3%. A fresh no-input boot with a frame->wall-clock map puts the same two dwells at 5.10-5.61 s and 3.83-4.30 s, 15-20% longer than both the declared values and the corpus's runs, on the same disc and the same declared timeline. So the wall-clock dwell is an emulator-pacing artefact that varies run to run, and a port authoring seconds is authoring one run's pacing. Boundaries from the draw stream, read per quad: publisher glow frame 1, wordmark 6-119, three frames with NO sprite drawn, developer glows 123, wordmarks 140-209, intro video 216. The 3-frame gap replicates the earlier 4-frame measurement within the +-1 both are quantised to. New tool frame_clock.sh, and its limitation found by its own control: it resolves to one BUFFER FLUSH, not one frame. The capture writes through a C++ ofstream, so tail sees the log in bursts -- 69 of 125 samples showed no advance and the rest jumped 7-15 frames. Naive interpolation inside a burst made the apparent rate swing between 0.0164 and 0.0316 s/frame, which is the flush and not the guest. Frames 119 and 123 fall in one burst, so the inter-splash gap is not separable by this clock at all. Everything is quoted as brackets and the point estimates were withdrawn before being reported. palogo_anima never appears in the log and is NOT reported as undrawn: the developer bundle batches 7 elements into one draw and only the first two quads are logged. That is the trap that produced the eff3 false negative, so it is named rather than claimed. Also records the port's correction: ptcopyright has 105 instants with alpha >= 1 (t=139..243) against 105.89 units of span; I had quoted the rounded span. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01QsEPXWVaEpyfudtR6re1Pd |
||
|
|
78328c5022 |
re: the top-level clock freezes at the settle point -- closing the 114-vs-120 gap
Measured in the title draw capture, re-read with the per-quad parser. GP_TITLE build 4 declares t = 0..269, about 120 presented frames at this run's pacing. The title dwell lasted ~1100. ptcopyright declares alpha >= 1 for 106 units (t=138..244) and is drawn for 1050 frames; ptlogo1 declares an exit at t=264 and is drawn for 1095. Both vanish within three frames of the dwell ending. So the top-level clock advances through the build-in, stops inside the settle window [160,236], and holds. The exit ramp is not played on a timer -- it plays when something makes the screen leave. That is ui-settle-time.md's decode seen from the other side and observed in the running game rather than inferred from the file. A nested record keeps looping on its own clock throughout. This closes the 114-vs-120 gap, and it was my arithmetic rather than a discrepancy in the decode. The 2.231 units/frame was regressed over BUILD-IN events -- the only stretch in which the top-level clock advances -- and applied to a period measured over the settled dwell, where that clock is frozen and only the plate's own record is running. Two different clocks. The declared 120 was never in doubt from the calibration-free dark-fraction test. The 51.158-frame period is now confirmed by a second independent estimator: autocorrelation returns lag 51 with clean harmonics at 102 and 154. Its FIRST version failed its control, returning 48 for a period known to be 51.158, because it indexed by sample position where the log's frame numbers have gaps. Recorded, because the failure is the reason the second version can be trusted. Not settled: the sweeps' period. The same validated estimator disagrees between two dwells of one screen -- 515 vs 452 frames for the same family -- and a 14% disagreement within one screen is not a period. The +0x08 field cannot settle it either, since ptloop01/ptloop02 have zero slack. Blocker recorded in CONTAINER-NOTES: a single A press on the title faults the guest. Three menu-capture attempts, two ending in register dumps of 223 MB and 519 MB, against three no-input runs in the same session that all completed. And a guest fault writes an UNBOUNDED register dump to stdout on a filesystem at 91%, so any scripted button press needs a size guard. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01QsEPXWVaEpyfudtR6re1Pd |
||
|
|
cf91ad1dcc |
re: the forced-backdrop span -- 256 vs 211 is a bundle mismatch, and the hold
decides 55% of verdicts The port implemented the forced-backdrop rule and reported a discrepancy: palogo_eff0.prm at 256 opaque instants against this corpus's 211. There is no discrepancy. palogo_eff0.prm appears on BOTH splashes -- the publisher (entries 10, 13) runs to t=255, giving 256 instants; the developer (11, 14) runs to t=210, giving 211. Same definition, different bundle. The page now names the entries so it cannot recur. The definition, stated: the span is 0..=max keyframe time over every element in the build, and an element HOLDS its final pose past its own last keyframe -- which is what pose_at does, and which is decoded rather than assumed (a group holds at its last keyframe rather than looping; the declared +0x08 never falls short of the last keyframe, the slack being that hold). The port's instinct that the hold was load-bearing was right. Over the 130 keyless full-screen primitives with an opaque interval: * span = the header's declared +0x08 -> 0 verdicts change * span = the primitive's own last keyframe -> 72 change * elements GONE after their last keyframe -> 72 change So the hold decides 55% of verdicts -- and dropping it is REFUTED by a measured order. palogo_eff0.prm is a single keyframe at t=0: without the hold it is opaque for one instant, no other element is up yet, and the rule calls it free, against a game measured painting it first. Pinned by a new test that spells out the counterfactual rather than importing it. The verdicts that matter are convention-independent: pgloading_eff00.prm is FIRST under all four conventions and pteff00.prm FREE under all four. And the header length is interchangeable with the elements' maximum -- zero disagreements disc-wide. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01QsEPXWVaEpyfudtR6re1Pd |
||
|
|
cfcda5501c |
formats: a keyless primitive that would hide the screen is forced to paint first
Partly closes ui-prm-primitives.md's standing blocker, "where an UNMEASURED
primitive paints". Raised by the port: build_12/build_15 composite to solid
black at every instant of their declared life, because pgloading_eff00.prm -- a
full-screen opaque quad -- sorts last.
The rule is a constraint read off the file, not a preference: an element that
covers the screen and is fully opaque at some instant cannot paint above
anything visible at that instant. Where the elements visible during its opaque
span are ALL of them, its position is forced to first.
pgloading_eff00.prm is opaque for 39 instants and all 9 other elements are
visible inside that span -> forced first, 4/4 instances.
Two controls, both measured orders from the running game, and the rule has to
survive both:
* palogo_eff0.prm is measured painting FIRST -- opaque 211 instants, forced
below 6 of 6. It is NAMED like an overlay, so a name-based rule sorts it
wrong against a measured order. Occlusion gets it right.
* pteff00.prm is measured painting LAST -- opaque for 2 instants at its
screen's entry and exit, forced below only 3 of 23, so the constraint
permits it on top where it belongs.
Disc-wide: 80 instances forced first, 50 constrained but not forced, 0
unconstrained. The split runs almost exactly along the names -- every *base* is
forced, every *eff00* is not -- with three families crossing it, which is
exactly why the name is not the rule.
It also explains 36 builds the corpus had recorded as "coming out one colour"
with no cause: pzeff00.prm is forced first in 32 of 32 instances, so they were
wiped by our own sort rather than by the game.
The rule's real limit was found by its own disc-wide test failing. Applied to
any element it claimed 22 .t32 SPRITES must sort first against their own layer
keys -- pneff01.t32 (key 0xd850, #8 of 13) and pbfriendly.t32 (0x9230, #17 of
49). A sprite's ELEMENT alpha says nothing about whether its TEXTURE covers the
screen, so forced_backdrop is now restricted to untextured primitives, which is
also the only case derived_paint_order consults it for.
Reach stated: assumes straight alpha-over (blend mode is still open, and an
additive quad at alpha 255 would not occlude); it is a lower bound, not an
ordering; and there is no new oracle measurement -- both controls are prior
ones, and a loading screen is not reachable from the title path.
3 new disc tests; the 13 paint-order tests are green, including
the_derived_order_matches_the_measured_ones_up_to_ties.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01QsEPXWVaEpyfudtR6re1Pd
|
||
|
|
47faeaa7a9 |
re: RETRACT "the game never draws eff3" -- a batched draw merged two quads
The console draws all five title flashes. My claim that ptlogo_back2eff3 is never drawn was an instrument artefact, and I had reported it to the port with three alternative explanations "ruled out". A GPU draw can batch several quads -- indices=4 is one, indices=8 two, indices=24 six -- and the UI draw log dumps only the first 8 vertices. Taking min/max over a line's whole vertex list merges quads into one box. eff3 is batched with eff4, and because the wipe family is right-aligned, eff3 (788..1196) lies ENTIRELY INSIDE eff4 (447..1196). The union is exactly eff4's own extent, so the merged box matched eff4 to 1 px, eff3 vanished, and nothing looked wrong. Parsed per quad, all five fire in both title entries in the declared stagger: eff1 130-131, eff2 133, eff3 133-134, eff4 133-135, eff/eff5 134+, back2 136+; and 5953-5955 / 5955-5957 / 5957-5958 / 5957-5959 / 5958+ / 5962+ in entry 2. Frames 133 and 134 are t=60.1 and 62.3, inside eff3's declared t in (58,64). Also retracts "the developer splash is one composited quad" -- the same bug, which the port refuted by arithmetic first (a 259-tall box cannot contain three logos spanning y 164..585). It draws three logos and three glows as separate quads in one indices=24 call; the 525x259 was gamearts_eff merged with seta_eff. The 9-unit black hold is unaffected: those glows are the developer splash's first draw. The three "ruled out" explanations were all aimed at the wrong failure. In particular the invisible-draw check counted draws with NO geometry line, when the hiding place was draws with PARTIAL geometry. Refuting three wrong hypotheses is not evidence for a fourth, and a list of failure modes written by whoever built the instrument is the least likely to contain its blind spot. Recorded in METHOD.md, along with the tell that was present and explained away: a merged box carries the first quad's colour, which made one element's alpha read 255/127/254 on consecutive frames. New tool: tools/re-capture/quads_per_frame.py parses vertices in groups of four and warns when the logged quad count falls short of indices/4. Also guards a double-A-tap in ui_draw_capture.sh: the movie branch ignored that TARGET=menu had already tapped, so a run tapped A on the title at t=23s and again at t=27s on the transition; the guest faulted and Xenia dumped registers to stdout until the file reached 519 MB. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01QsEPXWVaEpyfudtR6re1Pd |
||
|
|
1a2f4fdc2d |
re: the boot splash black gap is ~9 units, measured in draws not luminance
The port found its boot had no black frame between the publisher and developer splashes and authored 12 units by analogy with the menus' transition quad. On the boot path that analogy has nothing behind it -- palogo_eff0.prm is a single static keyframe, so the splash bundles declare no fade quad. I had agreed with the dismissal that hid the defect: told the residual was 0.03 s against a bound built from two measured ranges plus jitter slack, I said it said more about the bound than the game. The real gap was 0.2 s. Measured in the draw stream, which separates true black from a fade tail where luminance cannot: palogo_sqex is drawn to frame 125 at alpha 7, frames 126-129 submit NO sprite quad at all, and the developer fades in at frame 130 from alpha 34. Four presented frames, the only such run in the sequence. Converted with the disc as its own clock rather than a frame rate -- this run presented at 13.1 fps against 28 elsewhere -- palogo_sqex declares alpha >= 1 for 239.8 units and is drawn in 105 frames, giving 2.284 units per presented frame, which the title capture independently corroborates at 2.231. So the gap is ~9.1 units (0.152 s), against the 12 authored; +-1 frame is 6.9-11.4. And the true black is SHORTER, since both boundary frames still carry picture. Second finding: the developer splash is ONE composited 525x259 quad at the bounding box of its three declared logos, none of whose individual sizes is ever submitted. That is why an earlier pass reported "developer splash: 0 frames". Declaration sites ruled out: the splash bundles (no fade quad) and the top-level +0x08 (a family constant, 300/60, slack 12-226 units). The executable is NOT looked at and is named as the next place rather than claimed. Also answers the port's sweep question: +0x08 canNOT settle it, because ptloop01/ptloop02 have zero slack and a zero-slack record cannot distinguish "loops" from "runs once and stops". The oracle settles it for the TITLE -- the sweep oscillates over its whole range and resets hard to the same start, once in dwell 1 and twice in dwell 2, so it does not park. The MENU is unmeasured and stays open. Tooling: GRACE and NOTAP knobs for ui_draw_capture.sh. The script taps A on "the screen changed a lot", which is also true of a fading splash -- a first run tapped through the publisher and the developer never appeared. The instrument was perturbing what it measured. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01QsEPXWVaEpyfudtR6re1Pd |
||
|
|
69bc4cd1cd |
re: the game never draws ptlogo_back2eff3 -- reproduced, with three explanations
ruled out
Last iteration I recorded eff3's absence as unexplained after withdrawing a bad
explanation for it. The previous capture survived on disk with 6907 frames, and
the attract loop returns to the title, so it contains a SECOND build-in at
frames 5942..7025. eff3 is absent there too.
Three alternative explanations tested and failed:
* sampling phase -- eff3 is non-zero for t in (58,64), SIX units, against a
2.23-unit step. A window wider than the step cannot be missed; frames 133
(t=60.1) and 134 (t=62.3) sit inside it and draw eff2 and eff4 instead.
* a draw the log cannot see -- exactly 2 draws per frame carry no geometry,
on all 932 settled title frames, always the same full-screen-triangle
shader, and present on frames where no wipe element is active.
* a bad position guess -- dropping position entirely, ZERO quads anywhere on
screen in either build-in window have a width within +-30 of 408. The width
spectrum jumps straight from 262 to 748.
Draw counts across both entries: eff1 4, eff2 3, eff3 0, eff4 6, against ~5
expected each. The four are a right-aligned wipe (938+258, 788+408, 447+749,
64+1133, all ending at x~1196) -- a left-growing reveal in four widths, of
which the game draws three.
Why is NOT established: nothing in eff3's element record differs from its
neighbours. Classified measured, not decoded, and the port is told that
dropping eff3 means authoring a behaviour I cannot derive from the file.
Two further corrections, both to my own earlier claims:
* "frame 107 is the title composited once" was an over-read. It binds NO
texture and only 4 of its 27 draws log geometry. The second title entry
has no such frame.
* the two build-ins are NOT frame-identical. I had that from a coincidentally
aligned pair of rows; aligned properly only 4 of 46 frames match. They are
the same animation at different sampling phases -- which is precisely what
makes the eff3 result robust.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01QsEPXWVaEpyfudtR6re1Pd
|
||
|
|
311bd16ad8 |
re: withdraw the eff3 explanation and the flash advice; add a calibration-free
test that refutes 105 Two claims shipped this morning are withdrawn, and the port had already acted on one of them. WITHDRAWN 1: "eff3 was never drawn because a 2-unit flash peak is sub-frame." eff3's alpha is non-zero for t in (58,64), and the capture's frames 133 and 134 sit at t = 60.0 and 62.2 -- squarely inside that window, with eff2 and eff4 both drawn in the same frames. It should have been submitted and was not. The absence is real and UNEXPLAINED; it is not sampling phase. WITHDRAWN 2: "a port drawing all five flashes shows more sweep than the console". No evidence behind it. The port checked against its own renderer and found it draws them sequentially at their declared times, never more than two at once -- which is exactly what frames 131-135 show the game doing. The pile-up worth warning about was the rest() bug, now fixed. Kept, at the port's request: a frame-by-frame comparison of the build-in WILL disagree about which flash lands in which frame -- 2 units per submitted frame against this run's 2.231 units per presented frame -- and neither side is wrong. Without that stated, the discrepancy reads as a port defect. Added, and stronger than the argument it replaces: a calibration-free test of 105 vs 120. The glow's draw is omitted when its alpha reaches zero, and the smallest alpha actually submitted across 807 drawn frames is 1, so the culling threshold is read off the data rather than assumed. Measured dark fraction 17.7% (173 of 980 settled frames); a 120-unit cycle with its declared 15-unit hold predicts 14.4%; a 105-unit cycle predicts 2.2%. 105 is out by 8x and would need a threshold of alpha 11 out of a peak of 80, while the capture contains submitted draws at alpha 1..12. No frame rate, no pacing factor, no wall clock. Also recorded: a regression of five build-in events against their declared times (residuals <=0.9 frames) recovers t=0 at frame 106.1 when the composite spike, not in the fit, is frame 107 -- and that same slope makes the glow's period imply a 114-unit cycle against a declared 120, which is unexplained. And the vertex-alpha identity holds for the glow but does NOT generalise: eff4 reads 255/127/254 on consecutive frames. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01QsEPXWVaEpyfudtR6re1Pd |
||
|
|
d98c8214cc |
re: the title's build-in measured in the guest's draw stream -- the flashes are real
The settle-time decode was confirmed only against a SETTLED frame, which shows the end state is right and says nothing about whether the five flashes ever happen. This runs the oracle: a draw capture armed before the title exists, so the window contains the frames in which the screen is built. The flashes fire in a six-frame window and are absent from all 155 other sampled frames. `ptlogo_back2eff1` is drawn in exactly two frames at t = 54.0 against a decoded peak of t54-56; `ptlogo1` first appears at t = 42.2 against a decoded t42. Units-per-frame was taken from the GLOW's period alone, a different element, so the timings are not circular. The two holders are continuous from frame 134. The plate glow's quad carries a per-vertex colour whose alpha IS the element's fade alpha, so the ramp is read straight out of the guest: observed range 0..80 against a decoded peak of 80, exact and unfitted; period 51.158 presented frames over 20 cycle starts. Fitting the decoded ramp gives RMS 13.16 alpha levels against 38.18 for the same ramp REVERSED -- if the shape carried no information those would be equal, so the asymmetry is real and correctly directed. Further controls: symmetric triangle 15.73, flat 31.13. `ptlogo_back2eff3` was never drawn, and that is expected rather than a miss: a 2-unit flash peak is 0.85 of a presented frame, so catching one is a matter of phase. A port drawing all five every time shows more sweep than the console. METHOD.md gains the trap this cost: a 2D draw's identity is its vertex geometry, not its bound texture. These sprites sample shared pages, and matching texture dimensions produced a false negative (no flash is ever drawn) and a false positive (the intro movie's 640x360 YUV planes read as `ptbase2`) in the same pass. Also records the top-level restriction on the settle window, which the port raised and which is verified here: top-level [160,236] width 76, including the `ptloop` leaves [269,540] width 271 -- an instant past the end of every top-level element's timeline. Evidence committed as a derived per-frame series, not the 7 MB raw log. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01QsEPXWVaEpyfudtR6re1Pd |
||
|
|
4c74e579a0 |
re: 210 focus records pulse, not 2 -- and 8 of them fail in a way that looks right
The port censused focus-record alpha over its own export -- 34 elements, 2 varying, both `ptbtn00f` -- and concluded there is nothing to fix. That is correct and correctly scoped. This asks the same question of the whole disc. 1 130 focus records, 2 664 timed elements, 210 with a varying alpha. 202 have `rest()` returning the PEAK, the `ui-settle-time` pathology. By pak: PILOTLOG 116, MOVIE_THEATER 54, HANGAR_ARSENAL 30, LEADERBOARD 8, GP_TITLE 2. So the port's 2 is right because GP_TITLE has 2. The scope was load-bearing and was not stated as a limit -- "only 2 have a varying alpha" reads as a fact about the format and is a fact about one pak. The pathology is concentrated in exactly the screens a wider port reaches next. The 8 LEADERBOARD ones are the worse mode. `py_ranking_btn01f` swings 255->127->255 with no two adjacent keyframes equal, so `rest()` falls through to its longest-dwell rule and returns 244 -- neither the peak nor the trough. A glow stuck at its peak is visibly wrong; one stuck at 244 of a 127..255 range looks entirely plausible and nothing reports it. Verified rather than asserted: two hits dumped keyframe by keyframe, and a control on `ptbtn01f`, which is genuinely constant across its cycle and is correctly NOT flagged. `py_ranking_btn01f` also confirms the loop-length decode independently -- its ramp ends at t=90 inside a declared 120-unit cycle, holding bright for 30 units. Reach stated: 210 is a floor. Focus records are matched by the `Xf.rat` name rule, and elements with constant alpha but varying scale, rotation or position have the same problem and are not counted. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01QsEPXWVaEpyfudtR6re1Pd |
||
|
|
d4a08ad194 |
re: a nested record's +0x08 is its loop length -- the plate's period is 120, not 105
Answers the question the port agent asked: does the `PRESS A` plate's pulse group loop from its start, or hold at alpha 0 between cycles? It holds. A nested record is itself a RATC bundle with its own header, and that header's `+0x08` is the loop length -- the same field ui_header_time_disc already tests as an animation length at the top level. Its keyframes need not fill it, and the slack is a hold at the final pose. `ptbtn00f` is 105 units of ramp inside a 120-unit cycle, so the glow rests dark for 15 units between pulses. The five main-menu focus records fill their 120 exactly, which is what shows the slack belongs to this record rather than to the format. Disc-wide over 1 781 timed nested records: 92.3% declare exactly their last keyframe time, 7.7% declare more, and 0 declare less. That last row is the falsifier -- a cycle cannot restart before its own last pose -- and it never fires; the 7.7% is what keeps the reading from being an unfalsifiable relabelling of the keyframes. Falsification against the running game, using a pacing factor measured INDEPENDENTLY on the main menu's focus ring (declared 120 units, measured 2.177 s, factor 1.0885): to reach the corpus's four measurements of the plate pulse (2.12/2.19/2.34/2.31 s), a 105-unit period needs a factor of 1.211-1.337, which EXCLUDES the ring's; a 120-unit period needs 1.060-1.170, which CONTAINS it. Predicted 2.177 s against a measured 2.12-2.34. The two elements are in different bundles and were measured in separate runs; the only thing tying them together is that both declare 120. So the port should stop shipping 105. Its 123-vs-129 ambiguity straddled the right answer without containing it, and 129 only fitted because it was 105 + the exit_ramp_units constant it has since correctly deleted. Reach is stated: this says where a cycle ends, not which records cycle, and the TOP-level +0x08 is a different field left untouched -- every GP_TITLE entry declares 300 while its elements end at 244-269. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01QsEPXWVaEpyfudtR6re1Pd |
||
|
|
7b5a4aa041 |
re: the paint-order tie-break costs one pixel, on one screen we do not ship
Closes the open half of Q3. `ui-paint-order-derived-check.md` bounded WHERE a wrong tie-break could show -- overlapping same-key pairs -- and said outright that nobody had measured how many change a pixel. At the instant the player sees, the answer is: at most 1 px at max channel difference 1, on the JAPANESE title only (`ptlogo2` x `ptlogo_tm`, 5 px of shared ink). Exactly 0 px on all five port screens. The earlier 24-pair bound was counted at `rest()`, and 10 of the title's 11 overlapping tied pairs are between `ptlogo_back2eff1`..`eff5` -- the five transient flashes from the settle-time finding, transparent on the settled screen. A tie between two invisible elements cannot cost a pixel. Not a knife-edge. Sweeping every keyframe time and every midpoint between keyframe times, the live-pair count is flat across the ENTIRE settle window: 1 on the EN title, 2 on the JP title, 0 on all four loading bundles -- whose tie is live only at t17..t33, during the build-in, which matters because their settle windows are narrow enough to deserve little trust otherwise. Controls: every entry reporting zero also swaps an overlapping DIFFERENT-key pair, which must and does move pixels (25 310 / 268 698 / ~765 000 px). Zeros are explained by shared-ink counts rather than asserted -- the `ptframe` pairs overlap by bounding box and share 0 px of ink. Entries 0/1/12/15 have NO live control and their zeros rest on keyframe data rather than a render; recorded as the weaker claim it is. Refutation attempt on the corpus's "24 overlapping pairs": it SURVIVES as a rest-pose count -- an independent recount reproduces entry 7's 16 exactly. What is overturned is its interpretation as the risk surface. `tie_break_pixel_cost` gains a settle-time case and an alpha/scale filter on its rect test; `tie_cost_over_time` is new. Also strips 611 bytes of captured cargo warnings from the head of the committed tie census. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01QsEPXWVaEpyfudtR6re1Pd |
||
|
|
38b80302b7 |
re: the title's light arc is five transient flashes, not a tone or rotation error
Records the settle-time decode, and corrects two claims it overturns.
docs/re/structures/ui-settle-time.md is the finding: a settled screen is one
instant every element is posed at, the disc names it (the midpoint of the
longest keyframe-free interval), and the title's arc closes from 33.22 to
11.79 with the clipped-pixel count landing on the console's 1459 within 0.5%.
Includes the disc-wide reach -- only 30% of bundles have a window wide enough
to trust -- and a three-way figure.
Withdrawn in ui-rotation-implemented.md:
* "Flat. No minimum." was not a property of rotation. `at` posed LEAVES ONLY,
so the scan moved the light sweeps and never touched the top-level flashes.
* "our renderer does not draw ptlogo1/ptlogo2 at all" is wrong. Both are
drawn; the four elements the diagnostic named are kind-0x4 ghosts sharing
their template's name. Hiding the real ones makes the error WORSE by
+5.20 and +7.47.
* Its 10.92 baseline is not reproducible -- 14.07 at its own pre-change tag
and 14.07 today -- so the "1.7% better" verdict rests on an unrecorded
recipe. Flagged in title-residual-tone-vs-geometry.md too.
METHOD.md gains two traps: a shared CARGO_TARGET_DIR makes a `git worktree`
build silently replace the binary you run next (it cost three renders here,
caught only because a missing flag was a hard error rather than a wrong
number); and an aggregate computed per-element is not a state of the system.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01QsEPXWVaEpyfudtR6re1Pd
|
||
|
|
d0735d2c25 |
formats: a settled screen is one instant, not one hold per element
`Element::rest()` picks each element's last hold keyframe independently of every other element, so a composite built from it is not the screen at any moment in time -- it is a per-element maximum. For a transient that is exactly wrong: a two-frame flash's last hold IS the flash peak, so it burns forever. GP_TITLE build 4 is the case. `ptlogo_back2eff1`..`eff5` are five staggered two-frame flashes -- one light sweep drawn as five frames, all extinguished by t110 -- that `rest()` draws simultaneously and permanently. Five stacked white glows saturate the light arc behind the logo. The disc names the right instant: the midpoint of the longest interval containing no keyframe of any element. `UiBuild::settle_time()` and `settle_window()`; `screen render --settle` applies it and prints the window, whose width is how much the midpoint is worth. Predicted t=198 from [160,236] BEFORE scoring. Against the console capture, the arc band goes 33.22 -> 11.79 and pixels at the clipping level 8581 -> 1452, where the console has 1459 -- an unfitted statistic. Whole frame 14.07 -> 12.06. Controls at t=100 and t=358 are far worse, and a hand-picked visibility list reaches the identical numbers. `ComposeOptions::at` now poses every element rather than leaves only, which is why the earlier rotation pose scan was flat: it moved the sweeps and never touched the top-level flashes. `at = None` is byte-identical (cmp), the pre-rotation tag renders identically at rest, and the 13 paint-order tests plus the keyframe/focus/opt-link disc tests are green. Also fixes the diagnostic that caused a wrong finding to be sent to the port agent: `not drawn` listed bare names, and a kind-0x4 ghost carries its template's name, so four ghosts printed as `ptlogo1.t32`/`ptlogo2.t32` and read as "the logo is missing". It now prints index, name and reason. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01QsEPXWVaEpyfudtR6re1Pd |