8ebbfc70c1d19d104de015968988dbf00264d224
347 Commits
| Author | SHA1 | Message | Date | |
|---|---|---|---|---|
|
|
8ebbfc70c1 |
re: the focus reader was two items out -- initial focus is NEW GAME, and my labels were wrong
menu_focus.py's row centres are design-space rows from screenshot output; my probes fed it whole-display x11grab frames carrying Xenia's chrome and a surface scaled 1.060. Caught by ground truth, not by a control: the probe announced 'on EXTRAS', pressed A, and opened OPTIONS. Measured directly with ring_row.py: initial focus on a fresh boot is NEW GAME, 2/2 fresh boots, both the first menu entry. That agrees with boot_menu.sh's own line and menu-state-in-memory.md's four-downs, and withdraws this page's 'TUTORIAL 2/2' as the outlier. Persistence stands and is now geometry-free -- 384.0 vs 385.5, 1.5 px apart. An equality test is immune to a constant offset, which is why the conclusion survived a broken reader when the published item names did not. The control was structurally blind: 'two DOWNs move two items' tests relative motion, and a constant offset preserves it exactly. EXTRAS remains unmeasured; that run navigated to OPTIONS. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Wuu56cE8vJGTBtn1ppsk8v |
||
|
|
8bcb1d1976 |
re: the main menu remembers its cursor across menu -> title -> menu
F1 TUTORIAL, two delivery-confirmed DOWNs to EXTRAS, B to the title, A back: F3 is EXTRAS. Re-entry restores the item you left. Reframes the initial-focus disagreement rather than settling it: if focus persists, any 'initial focus' reading not taken on a fresh boot's first menu entry measures history. It still says nothing about what the menu opens on -- this run's F1 was itself carried over from a prior probe's press. Reached on the plate-pulse gate, not boot_menu.sh, whose stillness test cannot fire on this title -- TITLE at 422.7 s on a boot skip_intro could not gate at all. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Wuu56cE8vJGTBtn1ppsk8v |
||
|
|
982b6349c6 |
re: two boots failed because the title gate tests for stillness on a screen that never stills
skip_intro.sh admits a static screen at d <= 1500 between grabs 0.6 s apart. Over
72 samples of the failing boot the MINIMUM was 1551 -- zero could ever pass. The
timeout is unreachable by construction, not bad luck about intro length.
The premise is in the script's own comment ('the resting title barely changes')
and it is refuted by this session's own draw capture: the title free-runs two
full-screen-height sweep leaves and pulses the plate. HANDOFF already said a
settled screen is not a static screen. wait_plate_pulse.py, which counts glyph
pixels instead of demanding stillness, reached TITLE SETTLED at 245.6 s on the
same game the same day.
Threshold deliberately NOT raised: 7 of 72 samples fall under 2000, so a gate loose
enough to admit this title would also admit movie frames -- the confusion the
script's own header records paying for once already.
Cost recorded: the focus-persistence question it was booted for is unanswered.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Wuu56cE8vJGTBtn1ppsk8v
|
||
|
|
f6e1f12728 |
re: read the suppressed set -- 7 correction contexts, zero live revivals
Also dedups the suppressed listing: two registered claims can be substrings of one line, which reported that line twice (8 -> 7). Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Wuu56cE8vJGTBtn1ppsk8v |
||
|
|
5c97d3819d |
re: check_refuted.py's clean run was not a pass -- 8 of 8 mentions were suppressed silently
A real revival planted inside a paragraph that merely discussed corrections was missed: the words 'refuted' and 'withdrawn' in the surrounding prose vouched for it. Measured reach: 100 % of registered-claim mentions in the corpus are suppressed by marker language, so the reported 0 was 0 regardless of whether any was live, and I had been reading it as a pass. sylpheed-port's token-based hook has the opposite bias -- it over-reports on well-written corrections, which is the safe direction. Under-reporting is disguised as success. Fixed by making the suppression visible rather than removing it: suppressed mentions are counted and listed with --show-marked as not verified, only vouched for. Controlled -- the planted revival moves the suppressed count 8 -> 9 and appears in the listing. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Wuu56cE8vJGTBtn1ppsk8v |
||
|
|
4dd6a3f325 |
re: a bank's wave 1 is not a filtered copy of wave 0 -- and my own discriminator cannot finish the job
Coherence on BGM_103, the menu's bank, with controls run first: a real linear filter of wave 0 reads 0.93-0.94 in every band, a different bank reads 0.001, and wave 0 misaligned by 1 s reads 0.004-0.057. The measurement reads 0.027 at 1-4 kHz, so the 'wave 1 is wave 0 filtered' model is refuted. The frequency structure is inverted relative to any mic-pair or reverb model: coherence rises with frequency (0.169 -> 0.827) while energy falls (71 % -> 0.2 %), and a rear pair decorrelates fastest at HF. In the midrange the two waves are 13x further apart than the two channels of one wave. But the L-R control is what limits the tool and it is recorded as such: within one wave, genuinely one performance in two channels, coherence is only 0.221-0.497. So 'same performance' does not imply high coherence here, my positive control was the wrong model of the rear-pair reading, and the 🟡 is NOT settled. The tool tests for linear filtering and neither surviving reading requires it. Also corrects MISSION's Q10 row, which still carried the refuted three-sub-wave premise and had directed work at a dead question for days. Its gate is in fact met. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Wuu56cE8vJGTBtn1ppsk8v |
||
|
|
95ceb70cb5 |
re: the refuted register ignored the deaths I just wrote, and two false positives shared a cause
Three refutations written as prose under ### headings never entered the register:
check_refuted.py parses * "claim" lines, so the count stayed at 188. Registered
them properly (188 -> 192). A register that parses one syntax silently ignores
every other, and it is invisible from the author's side -- ask the register what it
holds, do not re-read what you wrote.
Both standing false positives were bullets under a header that retracts the whole
list, with no marker in the +-4-line window: scope marks them, not proximity. The
scan now includes the nearest preceding header and matches markers
case-insensitively ('An earlier version' was missed by the marker 'an earlier
version'). Controlled by planting a real revival and confirming it is still caught;
register now runs clean at 0.
Also records sylpheed-port's diagnosis of the phase-lock fallout: a number can be
inapplicable rather than wrong, and a tension built on one is manufactured. Plus
their point that some claims are not registrable in a substring register at all.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Wuu56cE8vJGTBtn1ppsk8v
|
||
|
|
c5d685ba15 |
re: the sweep IS drawn on the JP title -- and my gate was phase-locking the shutter
The occlusion hypothesis is refuted: build 7 draws the same three ROT strips at higher alpha than English, so there was never an absence to explain. The 0.32-vs-11.9 tension that motivated it was an artefact of my own instrument. Both JP captures were shuttered on the plate pulse, and the plate's pulse is part of the animation -- so the gate synchronises the shutter to the animation's phase. Measured at the shutter instant, the sweep sits 25-26 px apart across two runs in different locales and different sessions: 1.6 % of a ~1600 px traverse. So the 0.32 I recorded as between-session capture noise measures my trigger's repeatability, and I read it as evidence the title is still when it is evidence the gate works. The era adjudication is unaffected -- margin 16.72 clears even the un-locked 11.9 -- and unaffected for the reason that file already gave: correlated noise cancels in a margin. Refutation attempt on sylpheed-port's positional-mechanism rejection: FAILED, the claim stands. Its residual sits inside lit logos, and the logo ROI is byte-identical across five differently-phased frames in two sessions. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Wuu56cE8vJGTBtn1ppsk8v |
||
|
|
897be7bfdd |
re: build the enforcement check REFUTED.md lacked -- 0 real revivals, and why
sylpheed-port's check-claims fails their run when a refuted claim is quoted without an explicit token, and feeding it four withdrawals flagged three still asserted unmarked -- each inside a correction they had written. REFUTED.md publishes deaths without enforcing them, which is the gap I named last iteration and did not close. check_refuted.py is the prose equivalent: for each quoted claim in REFUTED.md it searches docs/ for that text and reports occurrences whose neighbourhood carries no refutation marker. Controlled first -- a claim planted unmarked in a scratch file is detected, so a clean run means something. 9 raw hits, ZERO real revivals. All false positives, and the kinds are the finding: 2 were text explicitly DECLINING to revive a claim; 1 a duplicate report; 4 were BACKLOG.md entries under a 2026-08-12 header, an append-only log recording what was believed then; 2 were the claim quoted inside its own correction. The structural limit is worth more than the clean result. A neighbourhood-language detector cannot separate "asserted now" from "recorded as believed then", because a dated log entry and a revival read identically. The port's design avoids this by testing for a token an author must PLACE rather than for language -- theirs fires correctly inside a correction, which is what caught their three, while mine fires incorrectly there and would miss a revival reworded. Stopped tuning at two remaining. Each marker phrase added fits the detector to this corpus's habits of expression and away from being a test of them; tuning until it reads zero would be fitting the instrument to the answer. Left over-reporting, which is the safe direction. Reach: it matches a claim's exact wording, so "no verbatim revival" is not "no revival". Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Wuu56cE8vJGTBtn1ppsk8v |
||
|
|
06aa031980 |
re: a ninth transition -- the same origin gives gap 0 and 1 by destination
sylpheed-port confirmed "nothing declared predicts the gap" from their export independently, and deliberately declined to search combinations: four pairs against many candidate two-screen functions fits by construction. Right call, and it applies to me unchanged. So this iteration adds a PAIR rather than a fit. menu -> a second screen outside GP_TITLE, reached by stepping the cursor two items before arming. The button is not controlled -- there is no focus readout -- so the destination is identified afterwards by its draw signature: incoming primitive [255] at 7-9 draws/frame, against the first run's [127] at 12-13. Different screens. Outgoing quad rises 25, 51, 102, 229, 255 across frames 37-42, then at frame 44 the new screen is already drawing. NO empty frame anywhere. GAP = 0. So the menu as origin gives four values across four destinations: title 0, EXTRAS 1, other-1 1, other-2 0. The same origin yields both 0 and 1 depending on where it goes, while the two repeated pairs stay internally identical (3,3,3 and 2,2). Further evidence for the ordered pair over the origin. Recorded as an observation with its counter-example rather than fitted: the incoming screen's own full-screen primitive is [255] where the gap is 0 and [127] where it is 1, which suggests a screen beginning from opaque black needs no blank frame. That FAILS on menu -> EXTRAS, which declares a black backdrop and still gives 1. Nine transitions against many candidate functions is the construction the port declined to search, and I am not searching it either. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Wuu56cE8vJGTBtn1ppsk8v |
||
|
|
09af29f1dd |
re: the symmetric audit -- port-sourced claims in my corpus are attributed
sylpheed-port promoted my unverified "EXTRAS is stuck at n=1, a structural limit"
out of a message into DECISIONS.md as an established fact, while holding the file
that refuted it -- their own authored/flow.json, recording ptbtn11 ->
GP_MISSION_SELECT. Their corollary is sharper than my original entry: distrust
"structural" and "impossible" hardest when SOMEONE ELSE writes them, because they
arrive without the doubt the author would have had.
Swept this side for the same shape. It is clean: port-supplied figures are
attributed in the text ("port reports 866 keyframes ... 0 untimed"), the
ui_layout.rs comment on the unreachable fallback cites MY OWN measurement of 0
untimed of 24 811 across 965 builds rather than their 866, and their quantisation
floor of 0.41 appears in no document of mine at all.
Reach stated: this tests attribution WORDING and the port-supplied figures I could
enumerate, not every reliance. A negative from a naive check is not proof of
absence, and saying so is the point of recording it.
What protected it was a habit rather than vigilance -- writing the source into the
sentence. That is now the third instance of one remedy: state what the number is a
number of; write the index space into the token (e10 rather than "build 10"); write
the source into the claim. Put the qualifier in the text, never in the reader's
memory.
Also fixes the half-guard the port called out. The effective-config block reported
`arming on` from screen_id.py, which cannot separate the main menu from EXTRAS --
so it announced "menu" while the run was armed on EXTRAS, a field the guard could
not resolve for exactly the two screens in question. It now prints both that value
AND the discriminator with its margin, so the ambiguity is visible rather than
hidden. NOT yet verified in a run -- per the port's own --no-hold lesson, parsed
and edited is not working.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Wuu56cE8vJGTBtn1ppsk8v
|
||
|
|
cd829b6dad |
re: break the EXTRAS n=1 cap -- which I had wrongly called structural
I recorded EXTRAS as able to supply only one gap measurement because "its sole
exit is (B) to the menu", and called that n=1 STRUCTURAL -- a word that retires a
question. The disc refutes it in one command: build 6 declares three buttons,
ptbtn11/ptbtn12/ptbtn13, all kind 0x3002. The cap was an unverified assertion I
had already written into HANDOFF twice.
Measured EXTRAS -> a screen outside GP_TITLE via (A): outgoing quad rises across
frames 36-40 (4-5 frames, matching build 6's declared 10-unit close), then THREE
empty frames at 42, 43, 44, then a different archive builds (23-28 draws/frame
against GP_TITLE's 11-14). Gap = 3.
So EXTRAS as outgoing gives {2, 3}, and seven transitions now group as:
menu {0,1,1} n=3, EXTRAS {2,3} n=2, title {3,3,3} n=3.
A pairwise control that holds the destination class constant: menu -> another
archive gives 1, EXTRAS -> another archive gives 3. Same kind of destination, gap
differs by outgoing screen. That is the strongest support yet for the
outgoing-screen dependence because it removes the destination as the variable.
But the clean ordering is GONE: EXTRAS {2,3} and title {3,3,3} overlap at 3, so
"menu < EXTRAS < title" no longer separates them. What survives is weaker -- the
outgoing screen constrains the gap to a ~2-wide band and the bands are not
disjoint.
METHOD: a structural limit is a claim and needs checking like any other.
"Structural" and "impossible" are the two words most worth distrusting in your own
notes, because they retire a question rather than answering it and nothing later
re-opens them.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Wuu56cE8vJGTBtn1ppsk8v
|
||
|
|
e823cfe6fa |
re: a third menu-outgoing gap, and leaving the archive costs no extra black
sylpheed-port's BLOCKED row asks for a second value on one outgoing screen --
what would make "the gap tracks the outgoing screen" predictive rather than a
restatement of the data.
First, a correction their ask surfaced without needing a run: THE MENU ALREADY
HAD TWO VALUES AND THEY DIFFER -- 0 leaving for the title, 1 leaving for EXTRAS.
So "the outgoing screen determines the gap" was too strong and is withdrawn; what
holds is an ordering, not a determination. Also recorded: their ask is answerable
only from the menu, since the title's sole exit is (A) to the menu and EXTRAS's
sole exit is (B) to the menu.
Then took a third menu-outgoing measurement, to a screen outside GP_TITLE.
Confound named in advance rather than after: that transition leaves the ARCHIVE,
so a pak load could inflate the gap for reasons unrelated to the outgoing screen.
Result: outgoing quad rises across frames 24-28 (4-5 frames, matching build 5's
declared 10-unit close), then ONE empty frame at 30. Gap = 1, identical to
menu -> EXTRAS. So the confound is measured ABSENT -- leaving the archive costs no
extra black, which is worth having on its own.
Six transitions now group as: menu {0, 1, 1} over three different destinations
including another pak, EXTRAS {2}, title {3, 3, 3}. The ordering rests on 3+1+3
measurements and the menu's three agree to within one frame.
Still not predictive: outgoing closes are 5, 5, 4 frames against gaps {0,1}, {2},
{3}, and EXTRAS has n=1 with no way to obtain a second value.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Wuu56cE8vJGTBtn1ppsk8v
|
||
|
|
36c01ae253 |
re: the black gap tracks the OUTGOING screen -- direction and button ruled out
Applied my own log-line rule to my own instrument first, which is the "rule written down is not a rule applied" failure I have on record three times. Every branch of fade_decompose.sh now announces its EFFECTIVE configuration -- derived from the variables in force, not from $WHERE, per sylpheed-port's sharpening -- and the run REFUSES if no branch announced itself. That is the guard that would have caught last iteration's silent fall-through at a glance. With it in place, took the measurement that failed last time: menu -> EXTRAS, the reverse of the pair measured at a 2-frame gap. Navigation verified both ways (extras margin 11.23, back on menu 11.60) and the config block confirmed the right branch. Result: outgoing quad rises across 5 frames matching build 5's declared 10-unit close, then ONE logged empty frame. Quoted as 1 with an upward uncertainty, since its two neighbours carry no frame header at all. Five transitions now order by the screen being LEFT: menu -> title (B) 0 outgoing menu menu -> EXTRAS (A) 1 outgoing menu EXTRAS -> menu (B) 2 outgoing EXTRAS title -> menu (A) x3 3,3,3 outgoing title Direction is ruled out: EXTRAS->menu (2) and menu->EXTRAS (1) are the same pair both ways and differ. Button is ruled out: (B) gives 0 and 2, (A) gives 1 and 3. Incoming screen is ruled out: an incoming menu takes 3 from the title and 2 from EXTRAS. NOT a rule, and recorded as such. Three outgoing screens with one value each means "each outgoing screen has its own gap" restates the data rather than predicting, and nothing declared predicts it -- outgoing closes are 5,5,5,4 frames against gaps 0/1,2,3, inverted if anything, on three points. What it changes for the port: a UNIFORM black_hold_units is now positively excluded rather than merely unsupported. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Wuu56cE8vJGTBtn1ppsk8v |
||
|
|
1b3a9e9086 |
re: a third title->menu replicate, from a run that ran the wrong experiment
Set out to measure menu -> EXTRAS, the reverse of the pair measured at a 2-frame gap, to test whether the black gap is a property of the screen pair or of the direction. The run did not do that. A three-part patch to fade_decompose.sh asserted two of its three replacements and left the third -- the branch condition -- unchecked. It silently failed, so WHERE=menu2extras fell through to the `title` branch. The capture is well-formed and is of a different transition than intended, which is the build-ordinal error's shape again: right-looking output for the wrong object. What caught it was the log LACKING the navigation lines the intended branch prints; the data itself looked entirely fine. Salvaged, because the accidental transition is one already measured twice: run outgoing ramp black incoming decay 1 67-70: 63,127,191,255 3 73-77 2 64-67: 63,127,191,255 3 70-74 3 92-95: 63,127,191,255 3 98-103 Three independent runs, gap = 3 frames every time, outgoing ramp byte-identical in all three. That takes "the black gap is not a load" from two replicates to three, and makes the 4-frame outgoing ramp as solid as anything measured here. menu -> EXTRAS remains open; the condition is fixed (with an assertion this time) and the run has not been taken. METHOD gains two entries. Assert every edit, not most of them -- and have each branch announce itself in the log, so a run that took the wrong path says so before its numbers are read. And: "appears nowhere in crates/" is a claim about a TREE. sylpheed-port found SYLPHEED_KF_TIME_SHIFT live at ui_layout.rs:497 on their branch, which carries the stale era; both statements are true of different trees. With main 145 commits behind and each agent on a topic branch, any claim about what the code contains needs its ref attached. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Wuu56cE8vJGTBtn1ppsk8v |
||
|
|
a1af583725 |
re: verify the splash's opaque-black backdrop, and the noun amendment
sylpheed-port found the fifth member of our error family on their own side: their "visible" test counted any element with alpha > 0, which includes palogo_eff0. Verified from the disc rather than accepted -- entry 10 [0] palogo_eff0.prm 1 kf t=0 fade=0xff000000 scale=100x100 pos=(0,0) entry 11 same Alpha 255 over RGB 000000: full-screen opaque black, drawn from t=0 and showing nothing. So "any element drawn" reports these screens visible from t=0 while the frame is black -- "visible" read as "drawn". Worth having on its own: this verifies from the disc the premise behind `screen render --black`, which its own help states as "what the game composites over on a screen carrying its own background". On the splash builds that background is DECLARED, not assumed. METHOD gains their amendment, which is the sharpest formulation either of us reached this week: all five instances are a failure of a NOUN, not of a number. Extent, bounding box, duration, span, visible. The number was always correct FOR SOMETHING; what went missing was which thing. Every other check in that file tests whether a number is right, and not one tests whether it is a number of the thing you think. Also teaches fade_quads.py to address a PAK ENTRY directly (`e10`) rather than only a build ordinal. The splashes are entries 10/11 and are not screen builds, so no ordinal addresses them -- and writing `e10` states which index space is meant, which is the standing lesson of build-ordinal-vs-entry.md. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Wuu56cE8vJGTBtn1ppsk8v |
||
|
|
9a80ed6bd2 |
re: (A) on a settled boot title DOES reach the menu -- the withdrawal explained
Clearing my own debt: I withdrew navigation.md's "boot title accepts a single A" counter-example as confounded by three concurrent emulators and never re-ran it, which left the claim unsupported rather than settled. Clean trial: exactly one emulator verified by count, gated on the plate pulse (glyph in [500,2500] held 12 samples) so the press lands on the BOOT title rather than the attract loop's, delivery confirmed at [file-pad] keystroke vk=5800 down/up. Glyph after the press is 0 at +2 s and +4 s -- the transition -- then 327 steady from +6 s through +39 s. 327 is a proxy and reading a proxy is the habit this corpus keeps cataloguing, so the screen was checked with which_title_screen.py instead: main_menu at RMSE 19.91 and 20.08 with margin ~10, inside the 9.9-11.7 band its control establishes on four known captures. The before frame gives the "neither" signature at margin 0.10, correctly, since the title is neither main_menu nor extras. So the count is 3 of 3, the latency is 4-6 s -- which is why a script that presses and looks 0.5 s later concludes the press was dropped -- and the two earlier failures were the confound, not the game. Refutation attempted: sylpheed-port's leaf segment rates. Derived independently from the disc and they SURVIVE exactly -- pteff03 +4.0000 then +4.0000 then a hold, pteff03a -4.0667 then -4.0625 then a hold. So their inversion stands: my linearity gate fails on the leaf whose declared track is perfectly straight. And records the third structural consequence of main being stale, which they raised: HANDOFF.md is the delivery contract and it lives on an unmerged branch, so their checkout contains none of this week's entries. Findings written into the contract reach them only through messages -- the channel the protocol says does not count as delivery. Writing it in the contract is necessary and not sufficient when the contract lives where the other party cannot see it. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Wuu56cE8vJGTBtn1ppsk8v |
||
|
|
1538c3e333 |
re: the leaf is NOT frame-locked -- and a residual gate disqualifies half my fits
The frame-rate test sylpheed-port and I agreed was the only clean route left.
Same strips, same screen, --framerate_limit=15 against the default. The limit
demonstrably took effect: the title settled at 862 s against 241 s.
First, a gate this work should have had from the start. A slope is only a rate if
its residual is random, so count sign changes in the residual:
default 1299x1303 -4.348 rms 3.33 43/111 OK
883x1134 +4.284 rms 3.08 21/76 SYSTEMATIC
890x1134 +4.284 rms 3.19 15/54 SYSTEMATIC
limit 15 1299x1303 -2.032 rms 1.51 44/83 OK
883x1134 +2.003 rms 1.12 36/61 OK
890x1134 +1.999 rms 0.74 12/37 SYSTEMATIC
So one of the two strips I quoted as "agreeing to three significant figures"
FAILS the linearity gate at default fps: that agreement was between a rate and a
slope through a curve. The port had already caveated the claim for a different
reason; this weakens it further from my own side.
The result, on the one group passing the gate at both settings: -4.348 px/frame
at default against -2.032 at limit 15, a ratio of 2.14.
THE LEAF IS NOT FRAME-LOCKED. A fixed number of units per submitted frame
predicts px/frame unchanged; it changed by 2.14x. Dead.
A simple wall-clock model is dead too, in the other direction: fewer frames per
second means more wall time per frame, so a time-driven leaf should move MORE
px/frame at a lower limit. It moved LESS. Neither model fits and I have no third.
Reach: the effective frame rate was NOT measured. The timing instrument I added
polls for the capture log, which is created when the capture is ARMED rather than
when it finishes, so it reported 0.728 s and is void. The 3.6x boot slowdown says
the limit took effect, not that fps went 28 -> 15. The RATIO is measured; the
absolute rate still is not.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Wuu56cE8vJGTBtn1ppsk8v
|
||
|
|
4c92f54439 |
re: make the one-emulator rule enforceable instead of remembered
The withdrawal last iteration was caused by `rm -f /tmp/xenia-canary.lock` -- the obvious way past a lock orphaned by kill -9, which also disables the guard for every later launch. Three instances ended up live at once, sharing /tmp/xenia_pad.txt and display :98, and silently confounded an input experiment. Care is not a fix, so this is tooling. ensure_single_emulator.sh counts live instances, stops them (plain kill, then -9, each with a bounded wait), verifies ZERO, and only then removes the lock -- refusing loudly if any remain. The lock is never removed before the condition it guards against is verified absent. FOUR scripts did the bare `rm -f`, and only two were mine from today: menu_loop_session.sh, title_draw_capture.sh, poke_control.sh and resume_reliability.sh. So the footgun was corpus-wide rather than introduced this session. All four now route through the guard. The guard is controlled rather than assumed: run against a deliberately started live instance it reports "1 instance(s) live -- stopping them", ends at 0 with the lock cleared, and exits 0. A guard that only ever passes on an already-clean slate would prove nothing. It also kills by process NAME. `pkill -f xenia_canary` matches the shell running it -- that has now cost this corpus three commands, one of them a cleanup that died halfway and left the very instances it was meant to remove. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Wuu56cE8vJGTBtn1ppsk8v |
||
|
|
969b816aad |
re: WITHDRAW the (A)-press finding -- three emulators were live at once
While chasing the draw-stream question I found THREE xenia instances running simultaneously (started 15:39, 15:44, 16:12), which violates the "one emulator at a time" hard rule and confounds the finding I recorded last iteration. All three read the same /tmp/xenia_pad.txt and share display :98. A press written to that file is delivered to EVERY instance, while `screenshot` grabs whichever window is topmost -- not necessarily the one that acted on it. So "(A) was delivered and the screen did not change" may simply be two different emulators, and the keystroke-level confirmation proves only that SOME instance received it. The navigation.md entry claiming the boot title's "2 of 2" is no longer 2 of 2 is withdrawn as unsupported, pending a clean re-run. The cause was mine. run-canary's lockfile is the IMPLEMENTATION of the one-at-a- time rule; a kill -9 orphans it, and the obvious unblock -- rm -f the lock -- also disables the guard for every later launch. I did that more than once today. METHOD gains two entries. A lockfile is the rule, not an obstacle to it: clear a stale lock only after confirming zero live instances, and COUNT them rather than trusting a kill landed, because a plain kill is asynchronous and a -9 on a stuck process can take seconds. When a guard blocks you, the question is whether the condition it guards against is present, not how to remove the guard. And a third instance of pgrep -f matching the shell that runs it -- this time it killed a cleanup command halfway through, leaving the emulators alive and the lock in place. Already recorded for wait-loops; promoted to "reach for -C first". Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Wuu56cE8vJGTBtn1ppsk8v |
||
|
|
cce20b83ca |
re: WITHDRAW "ptloop01/02 do not free-run" -- I measured a pivot, not an extent
sylpheed-port noted that build 5's ptloop parent can be static while the leaf record animates, and asked me to check it against my table. My own corpus refutes my claim outright. ptloop-leaf-sweep-positions.txt -- written earlier in this same corpus -- records ptloop01.rat's nested record at loop length 600, whose leaf pteff03.t32 sweeps a 400 px-wide quad with its centre running x~921->1041 over t=340..370. The parent's declared rect is (441,270) 200x90. The leaf draws 300 px outside it: the parent rect is a PIVOT ANCHOR, not the drawn extent. Checked against the two JP captures: my measured rect differs by 0 px -- and so does the whole dead region y 270..450 x 480..960 around it -- while the band the sweep actually occupies (x 721..1241) differs by 44 025 px. The zero was measured where nothing happens. So the port's reading is right and now confirmed from the disc: parent static, leaf animates, and the two nested records cycle at DIFFERENT lengths, 600 and 720. My "single static keyframe" described the parent only. The era adjudication is unaffected -- its box overlaps the sweep band only at x 721..776, which shows no between-session differences. The menu-loop question is still unsettled after a second attempt, and the second attempt's failure REFUTES my diagnosis of the first. menu_loop_probe.py gated on the plate pulse (glyph in [500,2500] held 12 samples), fired at t=484.5 s with glyph 1723 -- a verified settled BOOT title, not the attract one -- pressed A, and the press was delivered ([file-pad] keystroke vk=5800 down/up, 8 RE-INPUT lines). Twenty seconds later all five frames still classified as the title (rmse ~67-70, margins 0.06-0.16, the "neither" signature; screen_id says title). So "the attract title accepts nothing" does not explain attempt 1, and the corpus's "the boot title accepts a single A, 2 of 2 runs" is no longer 2 of 2. METHOD: a declared rect can be an anchor, not an extent -- confirm an element draws in a region before diffing that region to ask whether it moves. navigation.md: confirm the screen changed, do not infer it from a delivered press. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Wuu56cE8vJGTBtn1ppsk8v |
||
|
|
5a49511952 |
re: ptloop01/02 do not free-run on the settled title -- and the menu is not settled
sylpheed-port found ptloop01/02 free-running in their renderer on the menu path, pinned them, and was explicit that pinning picks one pose rather than the game's: "a capture question, not a harness one". It is, and it lands in my lane. On the title it is now answered. Those leaves rest at (441,270) 200x90, INSIDE the box the ptlogo_eff3 era adjudication uses, and across my two JP captures from different sessions they are byte-identical: 0 of 18 000 px, max |d| 0, against a whole-frame contrast of 116 492 px differing. So they are static at rest, and the in-box between-session noise of 0.32 is not theirs -- the 645 differing pixels all lie in a 30-row band at y 99..128, nowhere near the loop rect. That also closes the reach caveat on the EN->JP noise transfer. The MENU is a different bundle and is not settled. Build 5 declares the same rect with a single static keyframe, and that is where their row drifted. menu_loop_rest.sh was written to capture five settled menu frames and diff the rect; it did not complete. The run reached a title at t=146 s and (A) did not take across six attempts -- the documented intermittency where the attract loop's title accepts nothing, unlike the boot title. Recorded rather than re-rolled. Two committed main-menu captures cannot substitute: they differ across 57 % of the surface (different geometries and capture paths), so the 88 % differing on the loop rect measures the mismatch, not the loops. The control fails and the comparison is void. navigation.md gains the trap that cost this iteration a run: kill -9 on xenia orphans /tmp/xenia-canary.lock, the next run-canary refuses to STDERR where a polling script never looks, and a probe then sampled a dead display for 484 s reporting `other` every 4 s -- because screen_id.py on an empty screen returns `other` and "not the title yet" is indistinguishable from "there is no emulator". Kill plainly so it clears its own lock, and assert the emulator is alive before entering any wait loop. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Wuu56cE8vJGTBtn1ppsk8v |
||
|
|
281a058aca |
re: a second JP capture closes the transfer -- and corrects my own noise claim
Last turn I transferred the EN title's capture noise to the JP box and flagged the gap: build 7 carries ptloop01/02.rat which may animate inside that region where the EN plate does not, and the era adjudication rests on a single capture. Took a second, independent capture from a fresh boot in a separate session (jp_title_session.sh -- sets ja, captures, always restores en; verified back at language=1). Within-run stability reproduces: 0 of 138 600 px in the ROI across four comparisons, with 47k-73k px moving whole-frame as the contrast control. BETWEEN SESSIONS, inside the box the adjudication uses: 645 of 164 124 px differ, RMSE 0.3215, against 116 492 px whole-frame -- genuinely different sessions. And the verdict reproduces to three decimals: stale 58.412 -> 58.413, fixed 41.690 -> 41.692, margin 16.722 -> 16.721. The shape is the useful part: capture noise moves both candidates together, so it nearly cancels in a MARGIN. Absolute scores moved 0.001-0.002 while the margin moved 0.001 against an in-box noise of 0.32. A margin between two renders scored on one capture is far more robust than either score is. CORRECTION to a claim I made earlier today and sent to the port: I said the settle-vs-rest negative was STRENGTHENED because 1.48 sits below the whole-frame capture spread of 2.8. Wrong comparison -- the measurement lives in the box, and in-box between-session noise is 0.32, so 1.48 is well above it. The negative rests on the render axis alone (1.2, ratio 1.2x), exactly as first stated. I reached for a number that was to hand rather than the one that applies, which is the same family as the errors we have both been cataloguing. METHOD gains: match the noise floor to the quantity, including which noise applies; and sylpheed-port's point that an instrument which rounds away the thing being verified cannot verify it (they called a harness reproducible from an RMSE printed to two decimals when the residual was 0.0565). Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Wuu56cE8vJGTBtn1ppsk8v |
||
|
|
589d23e44a |
re: (B) from EXTRAS DOES go black -- "(B) has no black interval" refuted
sylpheed-port's BLOCKED.md ask #1. They declined to suppress their uniform black_hold on the cancel path because (B) menu->title was one transition. The test says they were right. EXTRAS -> main menu, also via (B): the outgoing quad ramps frames 34-38 (5 frames, exactly build 6's declared 10 units), then frames 39 AND 40 are completely empty -- 3 draws, zero textured, a harder black than either earlier capture -- then the incoming menu's quad decays 41-45. So (B) does not imply a cross-fade; menu->title is the outlier of three, and the generalisation I was one step from publishing is false. The screen was verified, not assumed. screen_id.py cannot separate EXTRAS from the main menu, so which_title_screen.py checked the armed frame: extras 18.58 vs main_menu 29.85, margin 11.27, inside the 9.9-11.7 band its control sets on four known captures. Three transitions now agree on one thing and disagree on another: outgoing ramp = the declared final ramp, THREE FOR THREE, against three different declared values (10u/5f, 8u/4f, 10u/5f), and exactly linear where nothing overlaps it. Authorable from the file. black gap = none / 3 frames / 2 frames. Not a per-button property, not a per-direction property, not a constant. black_hold_units should not be authored as one. Build 5's incoming ramp is confirmed at 12 units by its RATE rather than its count: the count came out 5 against a predicted 6 in both runs -- reproducible, so not noise -- but capture 3's steps are -21, -42, -43, -42, i.e. 255/6 per frame after a half-step start. Capture 2's decay does not fit that and is unexplained. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Wuu56cE8vJGTBtn1ppsk8v |
||
|
|
2a1ecc1c63 |
re: a menu/EXTRAS discriminator that failed its control, and the fix
sylpheed-port's BLOCKED.md ask #1 -- does (B) from EXTRAS also show no black interval, or is "(B) has no black" one screen pair -- needs the harness to know it is on EXTRAS. screen_id.py cannot tell: both are dark blue GP_TITLE screens and it reports `menu` for either. which_title_screen.py correlates a grab against our build 5 / build 6 renders. First version FAILED its control: it called live-main-menu.png "extras" and live-extras.png "main_menu", both backwards, margins under 1.1 on RMSE ~33. Cause: it applied the y=45 game-surface offset unconditionally, but only a full 1280x720 display frame has the menu bar -- a 1279x675 grab IS the surface, and two of the three reference captures are surface-sized. Offset made conditional; the control now passes 4/4 with margins 9.9-11.7 against ~18 within-class. The tool is a navigation aid for driving the emulator and says so: it identifies a screen by agreeing with our own renders, so nothing measured may rest on it. Also records the METHOD entry sylpheed-port offered from their own wedged check script: an absence of output is not a status. They reported "still running, two lines, both ok" for three iterations while the first attempt had died silently under its own timeout with block-buffered output -- zero information, reported as patience. An orphan from an older form of the same script was found running after 9.5 hours. Line-buffer and bound long jobs, and check the artifact rather than the exit code: the artifact reached its correct duration while the process never returned. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Wuu56cE8vJGTBtn1ppsk8v |
||
|
|
aa4ffafbc5 |
re: the decaying quad is the INCOMING screen -- and (A) and (B) are different shapes
Last iteration left an unidentified full-screen untextured quad decaying 255->15 during a menu->title transition, which build 5's declaration does not account for. Hypothesis: it is the INCOMING screen's own pteff00, which opens at a255 and clears. 8 frames matching build 4's declared 16 units is a FIT, so the test was a transition whose incoming screen declares something else: title->menu brings in build 5, 0->12 = 12 units = 6 frames. Prediction recorded before the run. Measured: menu->title decay 8 frames (incoming build 4, declared 8), title->menu decay 5 frames (incoming build 5, declared 6). Different incoming screen, different decay, in the predicted direction. The second is one frame short of prediction, inside the documented +-1. The tell that clinches it: a screen contributes TWO primitives, pteff00 at 255 and pteff02 at 64. The settled menu's untextured set is [64]; at frame 34 it becomes [64, 255, 64] -- build 4's opening pair, which no single element explains. Bonus, and it closes the alpha puzzle: in capture 2 the outgoing quad ramps with no other untextured quad present -- 63, 127, 191, 255, steps of exactly 64, four frames, against build 4's declared 261->269 = 8 units = 4 frames. Exact and exactly linear. Capture 1's 102/127/255 was a composite of two overlapping quads, as sylpheed-port proposed. The thing neither of us predicted: the two directions are not the same shape. (A) title->menu is SEQUENTIAL with a real black interval of 5 frames (~10 units, against the port's authored 9). (B) menu->title is a CROSS-FADE with no black interval at all -- the incoming title starts drawing at frame 34, before the outgoing menu's quad begins ramping at 40. Authoring one hold for both directions inserts black that (B) does not have. Also fixed: fade_pair.py's automatic rising/decaying classifier worked on capture 1 and produced nonsense on capture 2, where the title has no full-screen primitive at rest and the heuristic latched onto a transient. It now prints and does not decide. Refutation attempted: sylpheed-port's structural prediction of a 6-frame decay for an incoming menu. Measured 5. Survives as direction, one frame short as duration; recorded as both. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Wuu56cE8vJGTBtn1ppsk8v |
||
|
|
4bcb35cef7 |
re: the transition is overlap, not ramp-then-hold -- and the fade-in was 5x wrong
screen-transitions.md carried a 14-unit "black hold" that the page itself flagged as arithmetic rather than measurement. Measured it against the running game; the guess was wrong, and finding the instrument to measure it turned up a second, larger error in the same page. 1. fade_quads.py was STALE. It read each pose's time from blk+36 -- the next record's time word -- the association the keyframe record-layout fix retired in the crate. sylpheed-cli was rebuilt at the time; the Python helper was never swept with it. Signature: it cannot time a group's last pose, so it printed a trailing `t=-`. Fixed, controlled against the rebuilt `screen info` ([0 12 70 80] for build 5's pteff00.prm). 2. Through it, the page labelled the quad's CLEAR-hold as its fade-in and published 0.87 s / 0.97 s / 4.08 s for a ramp that is 0.20 s / 0.20 s / 0.27 s. A port pacing its menu fade-in off that would run it 5x too slow. 3. The measurement. fade_decompose.sh boots to the main menu, arms the UI draw capture there, then presses (B), so one 260-frame window holds the whole screen change. The fade quad is identified rather than guessed: a .prm carries no tex[base=] and paints last, so it is the last full-screen untextured quad of a frame. Control first -- the quad's ramp is decoded at 10 units = 5 frames, and measures 4 submitted-frame steps with one unlogged frame in the span. Result: content elements begin fading at frame 34; the black quad first appears at 40 and is opaque by 43; the menu's last frame is 45; frame 46 has 6 draws against 12. So the ~14 extra units are the content's own fade-outs OVERLAPPING the quad's ramp, not a hold after it, and the inter-screen black is one frame. Refutation attempted: sylpheed-port's entries 13/14 twins. Re-derived off the disc -- 3.06 / 4.33 / 47.91, identical to two decimals. Recorded as confirming their addressing and arithmetic, NOT as independent support: same renderer, same disc, which is their own rule. Reach: one transition, one run; the frame axis has gaps (232 headers over frames 3..260), so every span is +-1 frame. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Wuu56cE8vJGTBtn1ppsk8v |
||
|
|
279a33846e |
re: the Japanese title at rest -- the capture MISSION has wanted since 2026-08-29
Asked for by the port: its title_jp row drifted, localized to a 350x396 block at (405,74) -- the logo stack -- and with no JP capture in the corpus it could say the renderers moved apart but not which one moved. Three earlier attempts failed to reach the interactive title in either locale. The reason is now known and was never the locale: A at the title needs a signed-in profile, and no run had one. Locale set through canary's own persisted XConfig and restored afterwards, verified back at language=1. INDEPENDENT confirmation it took: the XMA probe logged a different voice-context set from every English run (ja 1112064 / 1150976 / 1177600 against en 1294336 / 1118208 / 1171456), so the switch reached the guest rather than being a menu-language cosmetic. 'At rest' is demonstrated rather than assumed. Five frames ~1.5 s apart after the plate pulse says the screen has settled: the port's ROI is byte-identical across all of them, max |delta| 0 over 138 600 px, while the WHOLE FRAME moves 39 584 to 71 927 px -- the plate pulse and sweeps. That contrast is the control: the instrument can see motion and the ROI still shows none. The capture shows what the English title does not -- the katakana subtitle, and a crystalline burst behind the wordmark, the ptlogo3a/b/c + ptlogo_back2eff* stack that this corpus records as transparent at rest in English. Exactly the region the port's drift is localized to. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Wuu56cE8vJGTBtn1ppsk8v |
||
|
|
7a63501bc1 |
handoff: split Q5's bundled 'measured' -- a label is as strong as its weakest cell
The port's authored/flow.json stamped title/on_cancel_why = 'MEASURED, HANDOFF Q5' for a clause whose evidence cell in the source table reads 'none'. It did not invent that: HANDOFF's Q5 row opened with one **measured** covering six clauses of different strength, and HANDOFF is the document it authors against. Split per clause. Measured: initial focus varies; up/down move one item per press and wrap both ends; left/right do nothing; B on a submenu restores focus 4/4; B on the main menu goes to the title in <= 0.4 s with no loading screen. NOT measured, evidence cell empty: 'no auto-repeat at the durations tried', and 'B on the title -> nothing'. Both marked do-not-stamp. Also splits the source table's own up/down row, which bundled 'one item per press' (indirectly but soundly evidenced by the 4-press wrap count) with 'no auto-repeat' (nothing behind it, and the hedge was carrying the claim). METHOD entry: the failure is in summarising, not at either endpoint. The source table was honest and the consumer cited its source; flattening six claims into one adjective created a provenance nothing supports. A strength label is not distributive. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Wuu56cE8vJGTBtn1ppsk8v |
||
|
|
78cb1d4e9b |
re: B on the main menu goes to the TITLE -- measured, filling an empty evidence cell
menu-navigation-semantics.md had this row at yellow with an EMPTY evidence cell,
and it is what the port still authors as on_cancel.
Delivery-confirmed via [RE-INPUT] (B is kXInputPadB = 0x5801), change detected
rather than timed. B delivered at 331.2 s; the glyph leaves 327 by 331.6 and
73.5 % of pixels differ. Both captures name themselves: PROJECT SYLPHEED with the
(C)2006,2007 SQUARE ENIX line.
Three things measured:
* B on the main menu goes to the title;
* latency <= 0.4 s at a 4 Hz sample rate, where the corpus previously had this
as 'not measured (a backlogged probe void)';
* NO loading screen in between -- the disc carries four pgloading_* bundles and
none appears on this path.
What the run CANNOT say, recorded in the table rather than glossed: 'B on the
title -> nothing' is still unevidenced. The second B was delivered during the
title's build-in, so the glyph 0 -> 154 change after it is the build-in
completing, not a response. A run that answers that row must wait for the title
to settle before pressing.
The 're-draws PRESS A after a beat' half of the first row is also still
unevidenced -- the run ended with the plate absent.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Wuu56cE8vJGTBtn1ppsk8v
|
||
|
|
77e54e95a5 |
re: a submenu is REACHED -- and correlation cannot identify it
Third attempt at the .tbm question. All three fixes from the previous page were applied and all three were needed: hold A for 0.5 s, confirm delivery from [RE-INPUT] rather than from the pad, and detect the screen change instead of timing it. Title at 288.6 s, both presses delivered on attempt 1, submenu at 303.4 s with 87.1 % of pixels changed. The capture is 99.7 % inked and uniform top to bottom -- a full-screen background. Our renderer gives 1.9-3.0 % for all 19 GP_SAVE_LOAD builds, 6.0-6.4 % for GP_TUTORIAL, 78.4 % for GP_SYSTEM 0/1. So two of the three archives render essentially nothing where the game draws a full screen. But WHICH screen was captured is not established, and the reason is worth more than the run: correlation cannot discriminate when the candidate renders are near-blank. All 19 GP_SAVE_LOAD builds score -0.004..-0.010 -- a ranking with no information. A matching statistic is useless against a hypothesis that predicts an empty image, which is exactly the hypothesis under test. Focus could not be read either: the two labelled menu captures fit at 2.52 and 2.48 mean absolute difference, 1.6 % apart. That is a SECOND statistic failing on the focus problem after the per-row brightness one, so it is an open item rather than an oversight. Kept regardless: the game surface sits at y=45 in the 1280x720 display frame, fitting the committed 1279x675 captures to 2.5 mean absolute difference. That is the alignment the earlier cross-geometry comparison got wrong. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Wuu56cE8vJGTBtn1ppsk8v |
||
|
|
bbc167425f |
re: the .tbm submenu is not reached -- and the second tap was never delivered
Two runs, neither answering whether a .tbm draws pixels. Run 1 TIMED the title->menu transition and was still on the title 8 s later (glyph 714, the plate's pulse trough), so the second tap did the transition and the 'submenu' capture is the menu. Void. Run 2 DETECTED the menu instead -- glyph 327, matching live-main-menu.png exactly -- tapped 0.8 s later, and 12 s after that was still on the menu. The log says why: 2 file-pad vk=5800 lines, i.e. ONE press, and one RE-INPUT delivery. The second tap was never delivered, with zero swallow lines so it is not the sign-in path. A 0.12 s press issued while the guest is still loading a screen is missed outright. So 'the press did nothing' and 'there was no press' look identical from the screen, and only the log separates them. Worth more than the run: this is the third time in one iteration that timing was used where detection was required -- the title->menu wait, the menu->submenu wait, and the press itself. Each fix is the same substitution, and each was written only after the timed version had produced a confident wrong answer. Also records that no focus detector is needed for this question, since every main-menu destination except EXTRAS carries a .tbm decider. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Wuu56cE8vJGTBtn1ppsk8v |
||
|
|
12159be61f |
re: land the loop-point correction where the claim actually lives
The port found its exporter still shipping 'no loop-point field has been identified anywhere' in the field manifest.json concatenates, days after the correction existed in other fields. Auditing this corpus the same way found the same failure here: the refuted sentence was still standing untouched in bgm-two-stems.md -- where anyone looking up BGM behaviour arrives -- and in HANDOFF.md, the one page the port is told to read. My correction had gone into a NEW page only. Both fixed in place, each naming the refutation rather than quietly deleting the old claim, and each carrying the measured window [9.44, 71.31] s at 61.87 s. METHOD entry: writing a correction down is not landing it. Grep the corpus for the CLAIM, not for the file you were working in. Plus the port's trap in doing that audit -- a replacement that quotes the refuted sentence in order to name it will match a substring search from inside the paragraph saying it is false. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Wuu56cE8vJGTBtn1ppsk8v |
||
|
|
e1f2a7f714 |
re: the menu loop starts at 9.44 s -- measured, and the fix was scheduling
Tailing the log from BEFORE the music starts cut the unsampled backlog from 616
samples spanning offsets 32..2,559,033 to 125 spanning 32..515,239, so the first
pass is sampled like any later cycle. Offsets below loop_start play exactly once,
which is why the previous run could not measure them.
Wraps at 96.46 / 158.33 / 220.21 s, gaps 61.87 / 61.87, both contexts together.
Two derivations, neither converting bits to seconds:
(a) time to read_offset crossing loop_start, plus a 1.33 s head correction at a
rate measured on 748 timestamped samples of that same stretch
(b) first pass (offset 32 -> loop_end) minus the cycle
Both give 9.44 s on both contexts -- four numbers, one value.
So the loop region is [9.44, 71.31] s of an 87.744 s wave, cycling every 61.87 s.
The first 9.44 s is an intro played once; the last 16.4 s, the fade-out
bgm-two-stems.md documents, is never played at all.
The decoder reads ahead of playback, but both endpoints are read_offset events so
the lead cancels in the difference. One boot, one bank.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Wuu56cE8vJGTBtn1ppsk8v
|
||
|
|
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 |
||
|
|
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 |
||
|
|
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 |
||
|
|
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 |
||
|
|
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 |
||
|
|
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 |
||
|
|
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 |
||
|
|
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 |
||
|
|
c5fe6a460c |
re: initial focus is TUTORIAL x3 / NEW GAME x3, and never anything else
Two more data points for the Q5 instability, from today s drives. A run that pressed A with no d-pad movement ended in a tutorial mission, correlating +0.960 with the committed capture, so that boot opened on TUTORIAL. A later boot read NEW GAME from a focus detector on the first menu frame. Six boots on the same harness now: TUTORIAL three times, NEW GAME three times, and no other item ever observed. The distribution is not uniform over the five buttons -- only these two occur -- which is a real constraint on whatever selects initial focus and something an explanation will have to account for. Also records in METHOD a bug that cost a seven-minute driven boot: a value was clamped for readability BEFORE the comparison that used it. A focus detector printed a degenerate margin, so it was capped at 999; the cap ran before the vote-sorting step, two different votes compared equal, the stable sort kept the wrong one, and a correct NEW GAME became an out-of-range index and a refusal. The measurement was right throughout -- a cosmetic fix changed a decision. Clamp at the point of display, never upstream of a comparison. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01QsEPXWVaEpyfudtR6re1Pd |
||
|
|
8b4dcccb67 |
handoff: BGM_103 as the menu music now has a runtime leg
The port asked for this to have its own line rather than sitting inside a drive report, and they are right -- it is a third independent confirmation of a claim that the port authors from. The claim rested on GamePart_Title s sub_821C5580 playing cue 1103 (static code) and on the bank s two declared wave sizes matching what an XMA probe saw (disc census). On a driven boot, BGM_103 s two waves were handed to the XMA decoder at the moment the main menu appeared -- observed being decoded on arrival at the screen, rather than inferred from a table or matched by size afterwards. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01QsEPXWVaEpyfudtR6re1Pd |
||
|
|
63573d2b50 |
re: settle_time measured -- the title is drawn at 2 s, not at rest.t s 4.18
The port s boot sequencer paces every screen off rest.t, which is the last hold keyframe rather than when a screen arrives. Measured on one cold boot: the container had no Xenia storage root at all, so this is a fresh profile with no shader cache, the slowest case. title build-in (first ink -> art fully drawn) 0.23 s title settled -> PRESS A plate on 2.247 s (disc declares 120 units) plate pulse period ~2.37 s main menu build-in 0.531 s B -> title 0.482 s A -> menu 3.763 s DO NOT AUTHOR, see below The title s rest.t is 251 units = 4.183 s and its art is finished at about 2 s, so a sequencer pacing off rest.t holds it roughly twice as long as the game does. Instrument controlled before the run: 9/9 on the content classifier including the movie-frame and difficulty-screen negatives, 4/4 on the plate detector; the run sampled 7.99 fps against a requested 8 with an independent one-shot grab cross-checking every 20 s. Records a refutation attempt of mine that FAILED. The probe s own marks gave a plate delay of 3.203 s against the corpus s 2.13 s, which on a cold-cache boot looked like a real effect. It was the instrument: the plate pulse period is an internal clock for presentation rate and measures 2.369 s here against the corpus s 2.3, so the run is not slowed, and re-measuring from content gives 2.247 s. The probe s title_static mark fires during the crossfade out of the attract movie, before the wordmark has drawn -- glyph was still 0 when it fired. Also a third independent reproduction of the A-path load stall: 13 frames, 1.53 s, surface mean 26.631 against the earlier 14/1.53 and 12/1.39 at 26.626. This boot had no shader cache, so it is not a warm-cache artefact. Noted that the earlier pair agreed to six decimals and mine agrees to three. Reach: one run. The menu build-in and B->title rest on it alone. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01QsEPXWVaEpyfudtR6re1Pd |
||
|
|
5744f379b2 |
formats: a keyframe's time comes before its pose, and none of them was missing
The placement region is `frames` records of `{u32 time; 36-byte pose}` after an
8-byte header, so the time word PRECEDES the pose it belongs to. Our parser's
40-byte window opened at the pose, four bytes into the record, and then read the
word at its `+36` as that pose's time -- which is the NEXT pose's. Every pose
field was right; only the time association slipped by one.
Two things the corpus has carried for weeks are that off-by-one and nothing
else: "a group's data stops 4 bytes short of its final block's time slot", and
"the last keyframe carries no time". The group is not short (8 + frames*40 is
exact) and no time is missing -- the first pose's time is the lead-in word at
`header + 8` that `parse_placements` skipped without asking what it was.
Disc-wide, 33 archives, 13 991 groups, each test with a control:
A lead-in prepended to the shifted times is non-decreasing 13991/13991
B a non-zero lead-in is strictly below the next time 5058/5058
control (another group's lead-in, same bundle) 70.9%
C multi-segment alpha ramp at a constant rate, corrected 857/1540
the same, under the old reading 0/1042
C is the one that cannot be argued with: interpolation between keyframes is
linear, and under the old reading not one multi-keyframe ramp on the disc comes
out at a constant rate.
Adoption is free on every static composite, which is what the corpus previously
declined it over. `SYLPHEED_KF_TIME_SHIFT=1` moved GP_TITLE build 7 by 13.1% of
its pixels because it left pose 0 untimed; with the lead-in restored, all 12
GP_TITLE builds render byte-identically, and across 217 builds in six archives
only two elements pick a different rest pose -- both times between two poses
that are equally invisible.
`SYLPHEED_KF_TIME_SHIFT` is gone; `SYLPHEED_KF_TIME_LEGACY=1` restores the old
reading for A/B work.
ui_header_time_disc needed one line: 546 bundles whose every group is a single
static pose now report max_time = 0 where they previously reported no time at
all. Excluding them, the result it guards strengthened -- the bound holds over
2 859 bundles instead of 2 313, still with zero violations.
Not established: the executable's own parser. Reach is written down.
docs/re/ui-keyframe-record-layout.md
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Nsxw1A9JseUw99Yw1ZRQzY
|
||
|
|
14fced07b6 |
re: I cannot measure this emulator's clock -- and that answers the port's 2%
The port put two of my pages against each other: settle->plate 2.135 s and one
focus-ring revolution 2.177 s, both a declared 120 units during a static hold,
2% apart against a 6 ms run-to-run agreement. Fair challenge.
The resolution is that the question assumes a stable wall clock. Same interval,
same container, same day: 2.138, 2.132, and 2.549 s -- a 19% swing, caused by
adding --log_ui_draws=true. The 2% is a fifth of that. The two pages were never
in conflict about the game; they are three readings of one declared quantity
through a clock that moves. What settles the quantity is the disc.
Wall clock cannot separate the hypotheses, so I tried to measure frames instead.
Both instruments are recorded as failures rather than published as numbers:
* Canary's own [UI-CAP] counter -- the one that produced the corpus's 28.5 fps
-- costs a third of the frame rate. 300 frames in 16.567 s = 18.11 fps on a
screen that gives ~28 without it. That reclassifies 28.5 as a load-dependent
lower bound; it does not overturn it.
* A distinct-frame counter over the spinning ring FAILED its decisive control:
15.88 fps against the game's own 17.59 in the same window, 10% low, so the
ring does not change on every presented frame. Its static control also read
2.63 instead of ~0. Dead, not tuneable, per METHOD.md.
The rule that follows, and it applies to everything I hand the port: a measured
interval landing near a round number of declared units almost certainly IS that
number of units. Ship the units.
Also recovered here, because the same question needed it: the static PPC route.
Four tools open /work/xenia-rs/sylpheed.db and nothing in this repository builds
it -- no disassembler, no PPC decoder, and default.xex is encrypted (zero
plaintext "GamePart"). Xenia decompresses the image at load, so dump_image.py
reads it out of guest memory and validates it against the corpus's own landmarks:
the 29-entry GamePart id table at 0x820A1630 and the Xbox 360 D3D runtime
strings. String search and table dumps work again; instruction-level work does
not, and the present interval I wanted is an immediate, not a string.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_014voBspJ6kFncNErZJuZcLw
|
||
|
|
3ee1a25f47 |
tools: a title timing probe that costs 8.7 ms a frame, not 1503
The four durations withdrawn yesterday were produced by a classifier costing
1503 ms/frame draining an 8 fps x11grab at 0.64 fps -- a backlog, which
preserves ordering and destroys durations. This is the instrument for retaking
them.
What makes it cheap: every committed capture aligns at exactly dy=0 dx=0
(five-screens-acceptance), so the +/-8 px offset search screen_match does at
full resolution is 25 ZNCCs buying nothing on this path. Decimate 4x, do one
ZNCC per reference. Measured 8.7 ms per frame including the glyph count -- 173x.
Controls, run before the measurement and not after it:
* 9/9 content controls, including the two committed movie frames that are the
class this oracle exists to reject;
* 4/4 on the plate detector itself, which is a threshold on the green-glyph
counter and so needs its own control (no-plate title 159, plate title 753,
movie frames 0).
And three things learned from run 1, folded back in:
* do NOT restart the stream once the measurement is under way. Run 1's restart
landed 0.25 s after the (A) press and its stale frames straddled exactly the
interval being timed;
* press INLINE, not through pad.py's subprocess -- an interpreter start plus
the 0.25 s hold sat between the press and the timestamp;
* count the longest run of byte-identical surface means and report it. That is
the freeze signature, and it is how run 2 showed the 26.626 hold is the
guest rather than the capture path.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_014voBspJ6kFncNErZJuZcLw
|
||
|
|
dd4f30a79f |
tools: fade_quads could not run -- two pre-monorepo paths
`screen-transitions.md` cites `fade_quads.py` as the command behind its decoded fade ramp, and the command had been dead since the monorepo migration: it read regn_decode.py from /work/Syplheed-Reborn and defaulted its pak to /work/sylph_extract, neither of which exists. Resolve the helper beside the script and default the pak under $SYLPHEED_DISC, the way run-canary and sylpheed-cli already do. A cited command that no longer runs is a citation nobody can check. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_014voBspJ6kFncNErZJuZcLw |