dcaa32214633626ffca3e83e3f94477a8a443e96
1238 Commits
| Author | SHA1 | Message | Date | |
|---|---|---|---|---|
|
|
dcaa322146 |
re: the decoder's timers are a double-tap latch on LB/LT, not key repeat
Answers H1's first half with a negative, and decodes what the timing constants are for. C_PAD_DECODER's +0xB4/+0xB8 and +0xBC/+0xC0 (10 and 90, twice) are not a key-repeat delay/interval pair. They are two identical channels of a DOUBLE-TAP detector, on cfg +0x74 (LT) and +0x70 (LB), firing output bits 0x20 and 0x40. The mechanism, from the image: both timers tick down once per update; a press arms the short timer to 10; a RELEASE adds 1000 to it as a flag stored inside the counter, which is why the tick watches for exactly 1000 and clears both there; a second press while the flag is set arms the long timer to 90; and while the long timer runs the output bit is asserted on EVERY update, with the short timer re-armed to 1010 each time. So it is a latch, not a repeat: a double-tap opens a 90-update window and the bit is held for its whole duration. That is a dash or barrel-roll shape, which fits the buttons it is wired to. H1: the directions have NO timer. The D-pad and left stick reach the output word through bare mask tests -- the four left-stick literals at 0x8220C458, C474, C490, C4AC, and DPAD DOWN through cfg +0xA4 -- with no counter loaded, decremented or tested on any of those paths. On the evidence of this layer a held direction does not repeat. Reach: one layer. A menu could implement repeat on top of a held bit, and this says nothing about that -- but it does establish the repeat is not in the shared decoder, so it would have to be per-screen. "One step per deflection" stays authored for the port; this narrows rather than settles. Refutation of my own earlier note that a decoder "is where a game normally puts its repeat timing, its edge detection and its button remap": remap survives, edge detection survives, repeat timing is REFUTED. That clause was a prior about how games are written, not a reading of this one. Also commits tools/ppc-dis, the minimal PowerPC disassembler this corpus has been rebuilding in scratch and losing to container restarts three times in one session. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Jc4pciRArGHfxGGhEbwp5t |
||
|
|
cac31deccd |
re: sub_822380B0 is a type-tagged draw-queue walker, not the interpolator
Walked the route the bounded-negative page named -- trace down from the quad emitter -- and got one step. sub_822380B0 is not a geometry emitter. It fetches a vertex pointer from sub_823C2AC0, stashes it at this+0x20, then loops over an array of item POINTERS at this+4 bounded by this+0x0C and this+0x10, loading a type tag from item+8 and dispatching on it. So the object is a draw QUEUE and this function consumes it. That is a partial answer to a different open question: ui-quad-class-foothold.md records that no function iterating screen elements has been found. This iterates UI items and dispatches per item. It is a draw queue rather than a screen's declared element list, so it is not that walk, but it is the consumer immediately downstream and the type tag at item+8 is a concrete field to chase. Still not the interpolator: alpha is already decided by the time an item reaches the queue. The evaluator runs before the enqueue, so the next step is whoever pushes items -- the writer of +0x0C/+0x10 on this object. Recorded as an increment, not a finding: one function identified by disassembly, no behaviour measured, identification resting on code shape alone. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Jc4pciRArGHfxGGhEbwp5t |
||
|
|
b32bcb97ae |
re: CORRECT the resample consequence -- the captures are crops, not resamples
The port pre-registered a test and ran it: against live-splash-publisher.png a cropped render scores RMSE 558.1 (0.85%) and a scaled one 10118.8 (15.4%). Cropping is 18x better. Confirmed here independently, from a different observable: the committed captures are 1279x675, 1280x690 and 1252x754. VARYING heights. A fixed presenter resample produces one size; crops of differently-sized windows produce exactly that spread. And ui-render-tone-curve.md had already recorded every capture aligning at dy=0 dx=0 with correlation 0.9466, which a 0.9375 vertical scale cannot produce -- the evidence was in the corpus before I wrote the claim. So the captures are crops of a 1:1 surface, and every RMSE, glyph count and surface mean against them is pixels to pixels with no filter to caveat. The blanket "everything measured off a PNG carries the resample" is withdrawn. Not refuted: the cvar reading. Canary does letterbox by default. What is refuted is my inference that the corpus's capture path went through it. Whether the presenter is bypassed, the window is 1:1, or the tool crops before saving is open and unestablished. The error is the one this session keeps paying for: I read a configuration and inferred a consequence FOR THE DATA without testing it against the data. The test costs one render and one RMSE and I had every capture needed to run it. Also downgrades my refutation of the corpus's oracle principle from "survives with a qualifier" to "survives, and my qualifier was wrong", kept rather than deleted because the failure is the instructive part. Section 1 (gamma: VdGetCurrentDisplayGamma is kStub, the splash shader has no pow/ramp/lookup) and the two-path distinction stand unchanged. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Jc4pciRArGHfxGGhEbwp5t |
||
|
|
515ad205e5 |
re: what Canary does between the guest's draw and a captured pixel
Answers question 3 of the 2026-09-02 play-test, from Canary's own source.
Gamma: Canary applies NONE. VdGetCurrentDisplayGamma is declared kStub and
only reports kernel_display_gamma_type (default 2, TV/BT.709) to the guest
so D3D can build a ramp. And the guest does not apply one either, for the
splash: its dumped pixel shader is four ALU ops -- tfetch2D, three muls, a
max -- with no pow, no ramp, no lookup.
Geometry: yes, the presenter resamples. present_letterbox defaults true and
present_safe_area_x/y default to 100, so the guest's 1280x720 is scaled to
fit the window and letterboxed with nothing cropped. That accounts for a
number the corpus has carried without explaining: captures measure the game
surface at 1279x675, and a single-pixel oracle placed at 1280x720
coordinates read the copyright line instead.
The structural consequence is the useful part. There are two measurement
paths and only one has Canary in it:
pixels guest draw -> EDRAM -> resolve -> front buffer ->
presenter (scale + letterbox) -> X11 -> screenshot -> PNG
=> carries a resample
vertex stream guest CPU writes a vertex buffer -> the draw logger reads
guest memory directly
=> carries nothing
The per-frame alpha series is the second path, which is why it can be
stated as the game's values rather than as pixels we measured. Everything
measured off a PNG carries the resample: every RMSE against a capture,
every glyph count, every surface mean.
Refutation attempt on this corpus's own founding principle, "the oracle is
the real game running in Canary, captured": it SURVIVES but needs a
qualifier it has never carried. A PNG capture is the oracle plus a
resample. Harmless for ordering, counts, durations and change; a filter in
the path for anything pixel-exact. The vertex stream is the stronger oracle
and should be preferred where the question can be asked of it.
Not measured: the resample's actual filter. I read the cvars saying scaling
happens, not the kernel doing it.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Jc4pciRArGHfxGGhEbwp5t
|
||
|
|
934fbfbbbf |
re: the interpolator is not found, and four routes are excluded
Question 1's behavioural half is answered elsewhere and measured. This is
the other half -- which function -- and it is not found. Recorded as a
bounded negative so the next attempt does not repeat four searches.
Excluded, all by exhaustive scans of the image:
integer lerp shape (divw with mullw and subf within 10 instructions):
28 sites image-wide, NONE in the UI region 0x82200000-0x823FFFFF
mulli by 40, the keyframe record stride: 31 sites, NONE in the UI region
addi rX,rX,40 in the UI region: 43 sites; the screen/bundle ones at
0x823CCA6C and 0x823CCA94 disassemble to a 40-byte container COPY loop
(CTR=10, ten-word copy), a vector reallocation, not an evaluator
fmadd-family in the UI region: 811 sites over 142 pages -- too diffuse to
select on, so float is neither excluded nor narrowed
The first two together say the evaluator does not compute its fraction with
integer multiply-and-divide and does not index records by multiplication.
With the measured steps landing on exact integers, the likeliest remaining
shape is a float lerp with a per-segment reciprocal, converted to a byte --
stated as a hypothesis, not a finding.
Names the route I would take next and did not have budget for: trace DOWN
from the quad emitter. sub_823C2AC0 has exactly 6 callers, four of them
sibling emitters, and sub_822380B0 reads its colour from this+0x04..0x10.
Whoever writes those fields is one step from the interpolator.
Reach stated: the two opcode negatives are exhaustive over the whole image
rather than sampled, but they do not exclude the interpolator living
outside the UI region, which is an assumption inherited from
ui-quad-class-foothold.md and not independently checked.
Not blocking the port: it needs whether to lerp and how, which is answered.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Jc4pciRArGHfxGGhEbwp5t
|
||
|
|
acc6c09632 |
re: the game interpolates every frame, and its splash is ALSO mostly frozen
Answers question 1 of the 2026-09-02 play-test: interpolate or hold. It interpolates, piecewise-linearly, evaluated once per present at one unit per present. palogo_sqex_eff gives 28 distinct alphas over 28 consecutive presents, changing on 26 of 27 adjacent pairs. It is not one slope, and the disc says why: that element declares 0:a=0 -> 15:a=255 -> 30:a=212 -> 45:a=0, three segments with three gradients. Predicted -2.87 and -14.13 per unit against measured modal steps of -3 (x6) and -14 (x9). The declared keyframes predict the per-frame steps, which makes this a prediction rather than a description. So the port must lerp: hold-to-next-key would emit 3 states where the game emits 28. And "eased" is the wrong description -- there is no easing function, the envelope only looks eased because consecutive declared segments have different gradients. Alpha lives in the per-vertex k_8_8_8_8 colour, rewritten into a fresh vertex buffer every frame. Not a PS constant (ps_c[n=0] on 1048/1048), not a blend factor, not a texture swap. 🔴 And the game's splash is ALSO mostly frozen. Measured with the same statistic the play-test used on the port: the game moves 21.2% and 27.8% against the port's 16.4%, and its longest frozen run is 3.34 s against the port's 3.20 s. The publisher declares 205 of 255 units -- 80% -- as a flat hold at full opacity. That refutes the play-test's second clause. "A fade does not hold one picture for 3.20 s" -- this one does, for 3.34 s. Its first clause stands: 26 states for a 45-unit build-in is too few, the game gives 49 and 51. The deficit is the state count, not the freeze: ~100 against 26. Acting on the second clause would have sent the port to remove the one part of its splash that is already right. Not answered: which function does it. This is the behaviour; the image-side half of question 1 is still open. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Jc4pciRArGHfxGGhEbwp5t |
||
|
|
33a6b4ea6f |
re: the three routes to 60 are one witness in three coats -- audit, and the capture sized
The port observed that the justification for 60 has changed three times while the number never moved, and that three routes sharing an upstream assumption are weaker than they look. Checked. They do share one. Route B needs "the guest presents 60x/s", which comes from the vblank histogram UNDER XENIA'S 60 HZ LIMITER. Route C needs "the vblank is 60 Hz", which is that limiter's cvar directly. Route D is a wall-clock duration that lands on 60 only because the vblank is 60 Hz and Canary roughly keeps up. All three reduce to one fact: the display refreshes 60 times per second on this emulator. I presented them as corroboration and that was wrong. What is actually established, by manipulation rather than agreement: units/second EQUALS the display refresh rate. Forcing 30 Hz gave 30.2 units/s; at 60 Hz it is 59.8/61.3. One factor changed, the output tracked it. It becomes "60 units/s" only via an external fact this corpus has not measured -- that an Xbox 360 outputs 60 Hz. That is a hardware specification and it is solid, but it belongs outside the measurement rather than laundered into a third agreeing route. The conditional form is more useful anyway: it says what to do on hardware that is not 60 Hz, which is exactly why the port's time-based clock at a fixed 60 units/s is the right construction rather than a coincidence. And it keeps the port's `authored` classification correct -- nothing here promotes it. Also sizes the clock-origin capture properly. FRAMES=9000 ran to completion still in the movie at 8999, so the cap really fired this time. Content hashes show 3967 distinct decoded frames against ADV.wmv's declared 4131 -- 96% complete -- at 1.79 presents per decoded frame, not the 2.00 I assumed, which is why the estimate was short. Needs ~294 more presents to clear the movie plus >=236 for the plate, so FRAMES=11000. Free on the way past: 3967 decoded frames over 7091 presents at ~52 presents/host-s is 29.1 movie frames/s against the disc's declared 30.000, a 3% match that ties the present rate to a disc fact rather than a clock. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Jc4pciRArGHfxGGhEbwp5t |
||
|
|
befcb74780 |
re: the clock rate follows the VBLANK -- reconciling three pages that disagreed
h3 says 2 units per guest frame, units-per-second-measured says time-integrated at 56.8 units/s, and my own page says 1 unit per present. All three rest on real data and one mechanism explains all of them: the clock advances one unit per VBLANK, and presents can be dropped without the clock caring. That accounts for the corpus's steps of +17/+34/+51 (1, 2, 3 vblanks between two logged presents), for the same animation spanning 21 labels in one capture and 33 in another -- which a strict per-present clock cannot produce -- for h3's three plate steps of 23, and for my own 14 consecutive steps of 17 in a run that dropped almost nothing. My "1 unit per present" was nearly right and named the wrong clock. At --framerate_limit=30 Xenia vblanks at 30 Hz and the guest presents ~30/s, so presents and vblanks coincide and the test could not tell them apart. It correctly refuted time-integration; it could not locate the tick. Solid: the RATE follows the vblank rate. 255 declared units take 4.26/4.16 s at a 60 Hz vblank and 8.45 s at 30 Hz -- 59.8/61.3 against 30.2 units/s. A time-integrated clock predicts 4.25 s in both. So a console at 60 Hz gives 60 units/s, and the port's value stands on a third independent route. Not solid: per-vblank vs per-present. My step samples are ~12 per run, which cannot separate them, and I say so rather than reading 18% vs 0% of two events as support. The load-bearing observation for the mechanism is the corpus's 21-vs-33, not mine. The discriminating experiment is named and not run: log Xenia's D1MODE_V_COUNTER beside each present and check every step is exactly 17 x (vblanks elapsed). Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Jc4pciRArGHfxGGhEbwp5t |
||
|
|
a7013a8fe1 |
re: the long capture ran and fell 32% short -- sized the next one from measurement
Attempted the capture this page named: FRAMES=8000, MAXDRAWS=400000, 700 s. Reached frame 5954, still in the movie, zero UI quads after it. Neither cap fired -- 24 213 draws of a 400 000 cap, 5954 frames of 8000 -- so it ended on the script's wall-clock timeout and nothing about the method is wrong. It needs a longer window, not a different approach. Sized from what this run measured rather than guessed: ~460 presents for the splashes, a 137.714 s movie at 30.000 fps from the disc = 4131 decoded frames, 2 presents per decoded frame measured, so ~8700 presents to clear the movie. This reached 5954, about 68%, at ~22 presents/s armed. So FRAMES=9000 and a timeout of at least 1200 s. Also noting a saving I did not take: the h= content hash reads guest memory for every sampled texture and the movie binds three planes per draw, but the clock-origin measurement needs vertex alpha and not hashes. That field is unconditional in canary-patches/0004; putting it behind its own cvar would make this run materially faster. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Jc4pciRArGHfxGGhEbwp5t |
||
|
|
e354e11f4c |
method: a finding is only as portable as the tool that produced it
Records today's trap where the corpus keeps its traps, so it outlives the session that paid for it. Four Canary commits existed only inside the container and were cited the way one cites a public reference -- "canary sylpheed-re d90d14e02, already built" -- a line that reads as a complete recipe and is reachable from nowhere but that box. The failure is silent and delayed by design: the recipe looks complete so nobody checks it, and it fails only for someone on a different machine long after its author could say what the flag did. Nothing in the repository disagrees with itself meanwhile, so no consistency check fires. Notes why citation checkers do not cover the class -- they scan repository paths, and an instrument in another container is not a path -- so they catch the recoverable case (a stale pointer to a committed artefact) and slide past the lost one. And that the audit only works pointed at yourself: both agents ran it on the same day, one finding a stale path to a committed artefact and the other four artefacts that existed nowhere else, neither able to find the other's from the far side of the wall. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Jc4pciRArGHfxGGhEbwp5t |
||
|
|
3e067decef |
re: the clock origin is blocked -- a 600-present boot capture has no title in it
The clock origin is the last surviving candidate for finding 3, and now that the clock is known to advance 1 unit per present it is directly measurable as a count: observe the plate at a known declared alpha, count presents back to the title's first draw, and the difference is the title's clock value at its own first draw. No capture I have contains the title. Three captures agree on what the boot does: publisher splash (219/228/244 presents), developer splash (186/185/204), then the attract movie at 422/429/463. Two splashes, then the movie. There is no title segment. This re-frames an old blocker as expected rather than mysterious. The corpus records "three runs, two locales, two launch paths, ~35 minutes of emulator time, no interactive title" as unexplained. MISSION's own boot order is splash -> intro video -> title, ADV.wmv is 137.7 s from the disc, and 600 presents at ~50/s is ~12 s. The title is on the far side of a two-minute movie; a capture that never reaches it is behaving correctly. Two ways to settle it. Tapping A skips the movie but risks the save-data probe that crashed the guest on 2026-08-18, per the capture script's own header. Capturing through the whole movie needs ~6900 presents against the 600 used here, needs no pad input and cannot crash the guest, so that is the one to run. Not run this iteration, deliberately: I would rather pre-register the origin prediction than start a long capture at the end of an iteration. The prediction is stated on the page so the next run is not exploratory -- the plate's a=17 must land 215 presents after the title's first draw if the clock starts there, and any shortfall is the offset in units. Reach: the negative is specific. Within the first ~460 presents of boot the title does not draw. It says nothing about after the attract movie, which is where the answer is. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Jc4pciRArGHfxGGhEbwp5t |
||
|
|
705a8485dc |
re: the clock is FRAME-based, 1 unit per present -- my own test refuted my claim
Ran --framerate_limit=30 against predictions committed beforehand. Every
discriminating row went to the frame-based column:
frame-based time-based (mine) measured
presents/s ~27 ~27 28.4
modal alpha step 17 unchanged 34 doubled 17 UNCHANGED
units/s ~30 halved ~60 unchanged 30.2 / 30.3
publisher dwell ~8.5 s ~4.2 s 8.450 s DOUBLED
developer dwell ~7.0 s ~3.5 s 6.923 s DOUBLED
Both controls passed first. The limiter took effect (28.4 presents/host-s
against 51-55, interval mass moving from one 60 Hz vblank to two, 422 of
468), and all 8/8 splash quad rects are identical so nothing but the frame
rate differs.
So the UI clock advances exactly 1 unit per presented frame. The step is 17
on every quad at 28.4, 51.4 and 54.8 presents/s, and 255*1/15 = 17 with the
declared T=15. units/second = presents/second, and seconds are not a
property of the game.
The port's 60 stands: the guest presents once per 60 Hz vblank
unconstrained, and 1 unit per present at 60/s is 60 units/s. Same answer as
my first position, finally with a tested mechanism instead of an inference.
This withdraws units-per-frame-is-not-a-constant.md in its central claim.
My "a time-based clock is immune to dropped frames so the dwell is stable"
was a real prediction and it failed -- the dwell doubled. The four-run
agreement I read as evidence was four runs at similar frame rates.
h3-units-per-frame-measured.md's +34 is now the anomaly rather than the
rule: 34 per label at 27.2 labels/s against 17 per present at 28.4
presents/s. Both cannot be presents. Not asserting it is wrong, only that
one of them must explain the disagreement.
Three of my four positions came from inference over a measured quantity;
this one came from changing an input and watching what moved. The
opportunistic comparison pointed exactly the wrong way because nothing
controlled what else differed between those captures.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Jc4pciRArGHfxGGhEbwp5t
|
||
|
|
5d72bda77d |
re: PRE-REGISTER the forced-frame-rate test of the time-based clock
The time-based-clock claim rests on two captures that happened to run at different speeds. Nobody has changed the frame rate on purpose and watched. --framerate_limit=30 halves Xenia's vblank ceiling. Predictions committed before the run: quantity frame-based time-based (my claim) presents/s ~27 ~27 modal alpha step 17, unchanged 34, DOUBLED units/s ~30, halved ~60, unchanged splash dwells ~8.5 / ~7.0 s ~4.2 / ~3.5 s, unchanged Accept time-based only if the step lands in 30-38 AND the dwell stays within 10% of 4.2/3.5 s. If the step stays 17 and the dwell doubles, the claim is refuted, the clock is frame-based, and the port's 60 is unsupported again. The control is the present rate itself, read FIRST: a doubled step also appears if the limiter did nothing, so if presents/s does not fall to ~27 neither prediction is tested. Second control: the eight splash quad rects must be unchanged, or something other than the frame rate differs between runs. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Jc4pciRArGHfxGGhEbwp5t |
||
|
|
73f5f57966 |
re: WITHDRAW 120 -- units per FRAME is not a constant, the clock is time-based, 60 is right
My fourth position today, and it returns to the port's. Splash B's logo quads in this capture step +17 per present, 14 gap-free steps, four quads agreeing. h3-units-per-frame-measured.md measured the SAME elements at +34 and concluded 2 units per frame. Both are right. With the declared T=15, dA/present = 255*(units/present)/T: h3 capture 27.2 presents/s +34 2.0 units/present 54.4 units/s this capture 51.4 presents/s +17 1.0 units/present 51.4 units/s Units per present halved when the presentation rate doubled. Units per second did not move. The UI clock advances by ELAPSED TIME, not by frame count, and "2 units per frame" was a property of a capture that ran at 27 fps, never of the game. So my 120 units/s is withdrawn: it was 2 units/present x 60 presents/s, and the first factor is not a constant. The movie result is re-explained rather than refuted. 2 presents per decoded movie frame at 51.4 presents/s is a movie decoding at 25.7 fps -- a 30 fps movie at 86% under a slow emulator. The measurement held; the inference assumed the movie decoded at 30/s in real time, which it does not when the emulator is slow. Same shape as the first withdrawal. 60 is now positively supported rather than merely undefended. A time-based clock is immune to dropped frames, which predicts the dwell in seconds is stable across runs at different frame rates -- and it is, across four runs whose present rates differ by 1.9x: 255/4.27 = 59.7 and 210/3.46 = 60.7, both within 1% of 60. h3-units-per-frame-measured.md's conclusion needs demoting: its measurement stands, its law is a single-capture artefact, and it is the origin of the constant this question has thrashed on. Finding 3 is open again with no surviving named cause. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Jc4pciRArGHfxGGhEbwp5t |
||
|
|
33f141a3df |
re: the dwell corpus does not falsify 120 -- it measures the screen, not the animation
The port raised this as load-bearing and it is answered, without a speed factor. I expected to find the three cold boots slow and argue contamination. They are not. My capture reproduces them: publisher 4.263 s against 4.297 / 4.604 / 4.370, developer 3.457 s against 3.508 / 3.503 / 3.366. Four runs agree, so that defence is unavailable and I am not using it. The flaw is in the comparison. 2.125 s is the publisher's declared ANIMATION length; 4.3 s is how long the SCREEN is up, and the screen holds after the timeline ends. Measured as counts in one capture: the publisher is on screen for 219 presents and animates for about 128 of them. The falsifier would have found a contradiction at any units-per-second. The decisive number needs no speed factor: 51.4 presents per host-second on the publisher splash, 53.8 on the developer. Xenia's limiter marks vblank at 60 Hz and caps presents there. A 30 fps guest presents every second vblank, at most 30 per second, and a slow emulator can only make intervals longer. 51.4 > 30, so a 30 fps guest cannot produce this. A 60 fps guest can: 51.4 is 86% of 60, matching the vblank histogram's 14% drops. So 60 units/s is refuted by a count against a hard limit rather than by a duration against a fitted factor -- the argument the 2.13 s reconciliation could not make. The dwell corpus stands in its own terms. Those seconds are the screen's dwell on this emulator, reproducible, and were never a statement about units per second. Recording what I got wrong on the way: I first segmented the atlas eras as "both splashes then the title" and briefly had a 2x discrepancy that would have let me declare the dwell corpus contaminated. The segmentation was wrong, and the durations matching the corpus to 1% is what exposed it. A convenient answer from an unchecked segmentation is the same trap as a clean answer from an unguarded assumption. Reach unchanged: still one boot for the hash ratio. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Jc4pciRArGHfxGGhEbwp5t |
||
|
|
60145720ed |
re: the guest presents at 60 fps -- 120 units/s, and the port's plate IS ~2 s late
Answered against the pre-registration committed before the capture, with a content hash added to the draw logger. The buffer rotates three times faster than the content changes: 177 presents carry 3 base addresses but only 102 distinct content hashes, and the modal run is exactly 2 presents per decoded frame. Consecutive presents with changed content = 0.5739, inside the pre-registered R band of 0.40-0.60. That is precisely the failure that invalidated my first answer this morning. The base address changed every present, which I measured and read as one decode per present. The content did not. ADV.wmv is authored at 30.000 fps, so 2 presents per movie frame is 60 presents/s, and 2 units/present x 60 = 120 units/s. Both controls pass, and they are the ones the withdrawn version lacked -- its two guards tested how I READ the buffer, neither tested whether a buffer change meant a decode. Control 1, a static texture must hash constant: the splash atlas changes once, at an era boundary, and never within an era -- 1 change in 403 samples. Noting that I first wrote this control as "must be constant" and it read FAIL; stated that way it was wrong, because a re-upload is real content change and the control has to separate temporal from alternating. A control that is too strong gets waved away, which is its own failure. Control 2, the movie luma hash must not be constant: 102 distinct. Consequence: the plate's t=236 is 1.97 s, not 3.93 s, and the port shows it ~1.96 s late. That is play-test finding 3, and "about two seconds" is the size the human reported. Every declared duration in seconds across the corpus is half what we have been quoting; unit counts are untouched. The 2.13 s third route is explained by emulator speed, and that explanation is labelled POST-HOC and is not offered as support -- fitting a speed factor to close a gap is what this corpus keeps losing claims to. Reach: one boot. This number has moved twice today and a second independent boot should come before the port rewrites a timeline. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Jc4pciRArGHfxGGhEbwp5t |
||
|
|
56ae05a18b |
re: PRE-REGISTER the decode-vs-rotate test, and add a content hash to the logger
The experiment guest-frame-rate-WITHDRAWN.md named. A triple buffer rotating once per present visits the same three base addresses whether or not anything was decoded into them, so base identity cannot separate "decode per present" (30 fps guest, 60 units/s) from "rotate per present" (60 fps guest, 120 units/s). A content hash can. command_processor.cc now emits h=<FNV-1a over 4096 sampled bytes> beside every sampled texture, omitted rather than faked when the address does not translate, so a missing hash cannot read as a matching one. Incremental build, one translation unit. Predictions committed before the capture: consecutive presents with changed luma content is ~1.00 under decode-per-present and ~0.50 under rotate-per-present, with acceptance bands and "neither" reported rather than rounded. The control is the part I got wrong last time. A STATIC texture must hash constant: the splash sprite page 0x11A50000 is a fixed atlas, and if its hash varies between presents then reading guest memory at draw time races the decoder and nothing in the log may be read. That fails loudly in the direction which would otherwise manufacture the answer I previously reached -- the property my last control lacked. A second control in the other direction requires the movie luma hash NOT to be constant, which would mean hashing the wrong bytes and would manufacture the opposite answer. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Jc4pciRArGHfxGGhEbwp5t |
||
|
|
eeb4473b4f |
re: the port's 12-unit bracket does not exclude 120 -- its low end is the sampler's floor
The port kept 60 on a stated constraint: the transition quad is declared black for 12 units, measured at 0.14-0.30 s, giving 40-86 units/s, so 60 is in and 120 is out. Attempted to refute it, and it does not hold. Two reasons, either sufficient. The low end is the instrument's floor. title-plate-delay-measured.md says of that number, in its own words, "at a sampling resolution (0.125 s) that cannot do better". 0.14 s IS one sample. At 120 units/s, 12 units is 0.100 s, which a 0.125 s sampler reports as roughly 0.14 s -- exactly the value read as excluding it. The 86 units/s upper limit is an artefact of dividing by a floored duration. And a wall-clock duration off Canary is not independent of the unknown. Apparent units/s = true units/s x speed factor, and the speed factor is precisely what makes the three routes disagree. The bracket says "if Canary ran at real time, 40-86" and whether it did is the question. What survives is the declared side, and it is a disc fact worth keeping: the transition opens over 12 units, independently confirmed as 6 frames by screen-transitions.md's 255/6-per-frame ramp. That leg has no wall clock in it and is real evidence -- for units per FRAME, which was never in dispute. This does not argue for 120. Nothing supports 120 either. It removes a reason for excluding it, and my position is unchanged: the value is authored until the content-hash experiment runs. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Jc4pciRArGHfxGGhEbwp5t |
||
|
|
ca401d8b04 |
re: WITHDRAW "the guest presents at 30 fps" -- the clean result WAS the failure mode
Published this morning, withdrawn the same day. The measurement was real; the inference was not established. My own pre-registration named three ways the instrument could lie and guarded two. The third -- "the guest may be frame-locked to its own presentation rather than to the movie clock" -- is the one that occurred, and a perfect 1.0000 is exactly what it produces: a triple buffer rotating once per present gives run-length 1 at ANY frame rate. So the measurement cannot separate a 30 fps guest decoding one movie frame per present from a 60 fps guest rotating a buffer per present. The methodological error is the part worth keeping. I wrote the guard down, saw a result so clean it had no tail, and read the cleanness as strength. A clean result on an instrument whose key assumption is unguarded is not confirmation -- the cleanness may be the failure mode's own signature. Both guards I did build tested how the buffer was READ; neither tested whether a buffer change means a decode. What surfaced it: the draw log carries a per-frame gtick marker I had not noticed. It is host time rescaled (Clock::QueryGuestTickCount is host_tick_count * guest_tick_ratio, scalar 1.0), so it is a wall clock and cannot be read as a rate -- but its SHAPE has no phase. Xenia locks vblank to 60 Hz, and the present interval is ONE vblank 71.7% of the time and two 24.6%. A guest hard-locked to 30 fps presents every second vblank and would put the mass at 2. I am NOT replacing it with 120. Three routes now disagree: the withdrawn movie cadence says 60, the vblank cadence says ~120, and title-plate-delay's 120 declared units in 2.13 s measured twice to 6 ms says ~56. Two of the three must be wrong and I do not know which. Publishing 120 would repeat the mistake this commit withdraws. The port is told to keep 60 for now, and told plainly that it is an authored value rather than a measured one. The settling experiment is named: hash the movie luma plane's CONTENTS per present rather than its base address, which separates "the buffer rotated" from "a frame was decoded". Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Jc4pciRArGHfxGGhEbwp5t |
||
|
|
fa27509937 |
formats: teach the reference renderer the additive blend, and re-open 8 claims
The blend bit has been decoded against RB_BLENDCONTROL0 since 2026-08-31, but ui_layout::blit could not draw it, and said so in a comment citing a refutation that is <render-vs-capture> -- this renderer disagreeing with itself while it had a stale keyframe association, no leaf geometry and no rotation. The consequence the port raised: verify-screen compares two renderers, so a renderer that structurally cannot express a declared field makes the check incapable on every screen that uses it -- 12 of 16 -- and the tolerance silently excuses all of them. A quiet check is worse than a failing one. Both equations come off the game's own pixel shader, which premultiplies (oC0 = rgb*A, A), so only the blend register differs: 0x07010701 gives rgb*A + dst*(1-A), 0x01010101 gives rgb*A + dst. Additive therefore saturates rather than wrapping, and a transparent or black source is the identity -- neither is a choice. No plumbing needed: t8ad::parse already stores +0x04 as T8adImage::flags. Four controls, pinned against arithmetic per the rotation precedent. The fourth is the only one that can fail for the right reason: the first three pass just as well if blit ignores the flag and draws everything additive, so the discriminator flips only the blend on one sprite and requires two different answers, each equal to its own equation. That is the same failure class as the port's non-inverting latch check and my own backward scan that resolved every guard to "internal". 120 passed, 0 failed on the full lib suite. 67 sprites over 14 screens were being drawn with the wrong blend, including 10 of 18 on the title and ptbtn00f, the PRESS (A) plate's highlight. R1: tools/stale-instrument render-vs-capture lists 8 claims that died to this instrument, including both legs of the rest() pair and "the plate-free title capture may be too early to be settled", which sits on play-test finding 3. None is re-derived here; this only records that the instrument no longer exists in that form. Also corroborates the port's H5: pgloading_loop5 is an ELEMENT resolving to sprite pgloading_ring.t32, which is additive. I could not find loop5 as a sprite in any pak and nearly reported a false contradiction from the element/sprite name split. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Jc4pciRArGHfxGGhEbwp5t |
||
|
|
9ea6ee7555 |
re: the blend bit was challenged on pteff10 and SURVIVES; finding 3 loses its second candidate
The port isolated main_menu's 10.88 -> 13.02 regression to pteff10 and asked whether the per-draw log shows it alpha-over, which would be a counter-example to ui-blend-mode-decoded.md. It does not. blend-bit-vs-oracle.txt has pteff10 ADDITIVE on entry 5 (main menu) AND entry 6 (extras), both labels read out of the guest command stream, and HANDOFF states it from three independent menu sessions, every frame. The premise came from a stale coverage table of mine that the same HANDOFF entry had already corrected in place. Recording that: a correction which leaves the wrong table visible upstream of it has not landed. And the regression was predicted on this exact element before adoption -- HANDOFF flagged pteff10 as the one row the port's renderer would not corroborate, because for a dim wholly-semi-transparent glow (max alpha 130) over a dark background additive and alpha-over nearly coincide. A renderer metric getting worse while the render gets more correct is the standing rule with a number on it. Separately, the port answered my finding-3 candidate: a frozen sweep of the plate region rises monotonically across the declared 214->236, so the port fades rather than pops and its t=236 is a completion. That kills the onset branch. Two of the play-test's four named candidates for finding 3 are now dead -- units/s (measured at 60) and the ramp. Finding 3 has no surviving named cause. The clock origin is the one to take next, because every measurement so far is a DIFFERENCE between two events and a difference cannot detect a common offset. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Jc4pciRArGHfxGGhEbwp5t |
||
|
|
27f81d6d91 |
re: the guest presents at 30 fps -- 60 units/s, and the port was right
Answered against the pre-registration committed before the capture.
Units per second was the last open number on the PRESS (A) plate, and both
prior measurements of it were wall-clock readings off an emulator that runs
the guest slow by an unknown factor. They disagreed by 2.9x, because a 30 Hz
guest at full speed and a 60 Hz guest at half speed look identical on a wall
clock.
The ruler here is not a clock. ADV.wmv declares 30.0000 fps in its own ASF
header, so a decoded movie frame is a tick the emulator's speed cannot
stretch. Presented frames per decoded movie frame is guest_fps/30 with no
wall clock in the chain.
predicted H_A 30 fps -> 60 units/s -> 1.0
H_B 60 fps -> 120 units/s -> 2.0
measured 1.0000
Both pre-registered guards pass. Guard 2: a perfect repeating 3-buffer
cycle, 52 uses each (exactly 156/3), 2 chroma planes per luma on 156 of 156.
Guard 1: run lengths are 156 runs ALL of length 1 -- no smear, so the
dropped-movie-frame bias that would have pushed the answer toward 120 is
measurably absent rather than argued away.
So H_A. The port keeps its 60 and changes nothing.
REFUTES the live H3 hypothesis that 120 units/s explains the play-test's
late plate. That hypothesis was well-formed and attractive precisely because
it would have explained the complaint, which is why it needed a ruler that
is not a clock.
Which means finding 3 still has no cause. The strongest remaining candidate
is decoded rather than speculative: the plate's declared onset is t=214, not
t=236 -- a 22-unit fade, matching the T=22 the oracle confirmed by measuring
+23 alpha per presented frame on that element.
The pre-registered control could NOT be run: this logger build emits vb=
addresses, not vertex contents, so there was no alpha to check +34 against.
A weaker control is substituted and labelled -- the splash shader/blend
census, which validates the log's structure (what this measurement uses) and
not alpha extraction (which it does not).
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Jc4pciRArGHfxGGhEbwp5t
|
||
|
|
f0185fba52 |
re: PRE-REGISTER the guest frame-rate test -- the movie is the ruler
Units per second is the one number left on the PRESS (A) plate, and both existing measurements of it are wall-clock readings off an emulator that runs the guest slower than real time by an unknown factor. They disagree by 2.9x, which is what that method is worth here. ADV.wmv declares 30.0000 fps exactly in its own ASF header (stream #2, avgTimePerFrame = 333333 x100ns). That is a disc fact, so a decoded movie frame is a tick of a clock Canary's speed cannot stretch. The measurement is a ratio of counts with no wall clock in it: how many consecutive swap labels bind the same movie luma texture base. H_A guest 30 fps -> 60 units/s -> 1.0 labels per movie frame H_B guest 60 fps -> 120 units/s -> 2.0 labels per movie frame Committed BEFORE the capture so the number cannot be chosen afterwards, with acceptance bands, the three ways the instrument could lie, a guard for two of them, and a named control (the splashes' established +34/frame must reproduce in the same log, or the log is not comparable). Noting the trap I nearly fell into: stream #1's avgTimePerFrame is a packet rate and reads as 3.05 fps. Reading the wrong stream is the obvious way to get this wrong, so it is written down. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Jc4pciRArGHfxGGhEbwp5t |
||
|
|
4518b5c76a |
re: the pad word is REMAPPED -- my own bit table was mislabelled throughout
input-pad-read-path.md says of the word the C_PAD_DECODER reads: "There is no shift and no remap on the way in -- the bit positions are XINPUT's own." That is wrong. sub_8220D500 rebuilds the word out of XINPUT_GAMEPAD before anything else sees it, into the game's own numbering. bits 0-3 A B X Y bits 4-7 left stick UP DOWN LEFT RIGHT (+/-20000 of 32767) bits 8-11 right stick UP DOWN LEFT RIGHT bits 12-15 D-pad UP DOWN LEFT RIGHT bits 16-17 START, BACK bits 18-19 LB, RB bits 20-21 LT, RT -- digital, threshold >220 of 255 bits 22-23 L3, R3 Extracted mechanically from the image, no row typed by hand. The control is the shape of the result: the 24 assignments land on bits 0..23, each used exactly once, none repeated. A misdecode does not produce a bijection over a contiguous range, and coincidence does not put the stick and D-pad directions in the same order in two aligned nibbles. So every mask in that page's tables names the wrong button. The 0xE000 x18 site, read there as "B | X | Y", is "D-pad DOWN | LEFT | RIGHT" -- eighteen sites testing a menu cursor, which is what 18 sites should be. And its headline negative is REFUTED: "LB and RB are not menu inputs" is false. They are bound at config fields this+0x70 and this+0x84, LT/RT at +0x74/+0x80. The negative was searched for 0x0100/0x0200 -- LB and RB in XINPUT's numbering -- in a word where they live at 0x40000/0x80000. Right function, right buttons, wrong bit positions, so it could only come back empty. A negative is only as good as the numbering it was searched in. Also decodes the ring record: +12 HELD, +16 PRESSED, +20 RELEASED, +28/+32 raw trigger bytes. Edge and level are one struct four bytes apart, which displaces that page's guess that press-vs-hold was split between GetState and the XamInputGetKeystrokeEx queue. The superset claim in that page survives and is untouched: sub_82457038 really does compare every XINPUT_GAMEPAD field, and it really is XINPUT-layout. This page depends on it. Not decoded: which output bit means which ACTION, and per-screen sets. 5 of 18 output-bit sites did not resolve to a pad guard, so the output map is a lower bound -- in particular "START is not tested" is NOT claimed. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Jc4pciRArGHfxGGhEbwp5t |
||
|
|
e263041337 |
re: the splash blur is a TEXTURE -- palogo_*_eff is a baked 10-px glow
Play-test finding 4, answered as a mechanism and from the disc, so it generalises instead of describing one boot. ui-splash-draw-pass.md excluded a post-process from GPU state and closed with "that softness is in the texture or in which quads are drawn, not in a pass", leaving the two unseparated. It is both, and they are one fact: each logo ships a second texture that IS the blur -- the same artwork outset by exactly 10 px per side, concentric to <=1.5 px, drawn as its own alpha-over quad. Three results, each with its control: * The capture's eight anonymous quads are NAMED from the disc. Predicting each NDC rect from declared position + decoded sprite size matches all eight bijectively; every match <=0.0061, every runner-up >=0.0272, a 4.5-8.9x margin. That margin is the control -- eight similar boxes would match anything. * REFUTES splash-quad-timeline.txt's "the same three rects scaled slightly larger" (my own earlier wording). The x and y scale factors differ by up to 0.28; a uniform scale cannot do that, a fixed 10-px border can. The conclusion it supported (draw all six quads) stands; the model was wrong, and the wrong model tells a port to scale a sprite. * The T8aD blend bit tested OUT of sample on entries 10/11, which were not in its 35-row fit and are the screens under complaint. Pre-registered additive=false for all eight against 0 additive draws in 1048; held 8/8, with the control still reporting 9 additive on entry 6. Also resolves a REFUTED.md 🟡 <our-reader> in the reader's favour: the prediction is ours and the target is the oracle, so the agreement is evidence about the reader rather than a claim resting on it. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Jc4pciRArGHfxGGhEbwp5t |
||
|
|
df51101faf |
handoff: withdraw the splash rate, and strike the section that carried it
Told the port plainly: their arithmetic was right, the 35-40 is withdrawn, keep 60 for every screen, and do not average or split anything. Struck the previous section's heading in place rather than deleting it. Carried the instrument lesson across, because it is worth more than the number: the guest timebase does not remove the pacing artefact, since the game's animation clock is frame-coupled rather than being the guest timebase. My control verified capability -- does this clock track real time -- when the question was configuration: is the quantity I divide by coupled to the frame rate. Also told them what this leaves: both halves of the human's finding 4 that were mine are answered and neither points at their export, so their own unbound-A observation is now the strongest candidate and it is theirs. |
||
|
|
c1c8aa4288 |
re: WITHDRAW 'the unit rate is per-GamePart' -- it was the emulator's frame rate
The Port's arithmetic was right: a 160-unit sub-interval cannot outlast the 210-unit group containing it, and my hold (4.514 s) outlasted three cold-boot measurements of the whole group (3.37/3.50/3.51 s). My own capture says why, once asked the right question. The three numbers I quoted came from three regions of ONE run, and I never asked how fast the emulator was going in each: splash B (the hold) 3.39 labels/guest-second -> I reported 35.4 splash A (publisher) 15.33 -> I reported 40.0 the title (the plate) 23.20 -> I reported 56.8 Monotonic. The 'per-GamePart rate' is the pacing of the region it was measured in. Splash B was captured at 3.4 fps, an eighth of the title region. And the corpus already had this. boot-splash-dwells-are-declared.md says in its own words that the wall-clock dwell is an emulator-pacing artefact that varies run to run, with a no-input boot 15-20% long on the same declared timeline. I re-derived a documented artefact as a discovery and drew a false conclusion from it. The instrument lesson, which is the part worth keeping: I believed the guest timebase removed the artefact. It does not. The game's animation clock is not the guest timebase -- it is frame-coupled -- so a slow run advances less animation per guest second and no clock can see that from inside. My control asked 'does this timebase track real time', which is capability. The question that mattered was 'is the quantity I divide by coupled to the frame rate', and nothing I ran asked it. That is PROTOCOL's own warning, which I quoted at the other agent two iterations ago and then walked into. Restated: the clock is neither purely frame-counted (21 vs 33 labels for one animation) nor purely time-integrated (rate scales with frame rate). Consistent with a clamped per-frame delta, untested, and now the real open question. Consequence: no rate measured on this emulator is the console's; all are biased low. Best estimate stays the declared timeline against the fastest runs -- 60 units/s, 1.1% on the developer splash. The port keeps 60 for every screen and nothing needs averaging. Untouched: section 1 of splash-declared-vs-captured.md. It compares a disc table against vertex alphas at integer t and never divides by a duration, so the pacing artefact cannot reach it. |
||
|
|
227d9b0439 |
handoff: one units-per-second cannot be right, the splash timeline is confirmed, and H5 refuted
Three sections, the correction first. The rate is per-GamePart: title ~57, splash ~35-40. I gave them 56.8 an hour ago and said the reach was the title; the splashes now have their own number with T read off the disc. The hold is what makes it safe to hand over -- 160 declared units in 4.514 guest seconds, with no T, no alpha slope and no interpolation in the arithmetic, agreeing with the same screen's ramp which shares none of its algebra. Told them a splash played at 60 runs 1.5-1.7x too fast, which is a TIMELINE cause for the complaint we had both filed under blur. Classified measured, not decoded, and told them not to extend either number to any other screen. The R1-re-opened 'declared timeline reproduces the captured splash' settles in favour of the timeline: 39/50 exact under truncation, worst error one alpha level in 255, nothing off by more than one. So their export's splash keyframes are right and the rate was the defect. Refutation attempt on their H5, recorded whether it survived or not: it does not. build_12 and build_15 have identical declaration bodies, so identical statistics is one fact rather than two coincidences -- as do 0/1, 2/3 and 11/14, while 4/7, 5/8, 6/9 and 10/13 genuinely differ. Also recorded the trap I hit first: the dump header carries the build number, so the compared text contained the label distinguishing the subjects and every pair read as different. A self-comparison control caught it. |
||
|
|
4b5ac88f0a |
re: the declared timeline DOES reproduce the splash -- and the unit rate is per-GamePart
Two results, one of which corrects me. 1. The R1-re-opened 'declared keyframe timeline reproduces the captured splash' resolves in FAVOUR of the declared timeline. Instrument is a disc keyframe table against the guest's vertex stream -- no renderer in the chain, which is what the 'our-reader' tag demanded. Calibration-free test: is each captured alpha an exact member of the declared piecewise-linear value set at integer t? 39/50 exact under truncation, 30/50 under rounding, and the worst error under either rule is ONE alpha level in 255. All 11 non-exact samples are low by exactly 1 and all are on falling segments. The old refutation rested on 'still at a=255 nine frames after its declared a=32' -- under the fixed layout a=32 is at t=206, four units from the end of a 210-unit timeline. That was the off-by-one association. 2. The unit->seconds rate is PER-GAMEPART, which corrects what I told the port an hour ago. Title ~57 units/guest-second; splash ~35-40. The splash figure is confirmed two ways that share no algebra: a 15-unit ramp (T read off the disc, not borrowed) and a 160-unit HOLD, which is a declared duration with no T, no alpha slope and no interpolation in it. And my 'the borrowed T=15 does not apply' was wrong in the other direction: the disc says T=15 plainly. What failed was the premise of a single global rate, not the T. Noted at the foot of that page rather than by editing it. The trap worth recording: all four elements give 650-679 alpha/s, agreeing to 2%, which reads exactly like one clock. It is a coincidence -- T differs 22 vs 15 and the rates differ 57 vs 37, and the ratios nearly cancel. A quantity that looks constant across screens is not evidence of one clock when the thing that would vary is inside it. The hold breaks the tie. For the port: a single keyframe_units_per_second cannot be right, and a splash played at 60 runs 1.5-1.7x too fast -- shorter, sharper fades than the game's, which is the direction the play-test reported. |
||
|
|
3d1c3c9564 |
re: fix the stale headline on the units-per-second page
The title still said 'not yet a number' after the second half resolved it to 56.8. Kept the failed first half in place and in order -- the borrowed T is the lesson -- but a reader must not stop at the header. |
||
|
|
d67aaaf30b |
re: the rate is 56.8 units per guest second -- both predictions hold, control passes
The capture reached the title AFTER the harness stopped classifying, so the plate's ramp was in the log with tick stamps after all. ptbtn00: alpha 11->231 over 334.4 guest ms = 657.9 alpha/s. With its independently attested T=22 that is 56.8 units per guest second, inside the pre-registered 55-65 band. The final step of every ramp is excluded because it clamps at 255 and reports more elapsed time than it consumed -- including it drags the plate to 633.0 alpha/s, a 4% error entirely inside the clamp. Control passes at 1.15%: ptcopyright gives 650.4 alpha/s, and at one shared clock that makes its own segment T=22.25. Two elements agreeing on a rate AND independently landing on a round declared length is stronger than either. Why my earlier 29.9 was wrong, and it is the failure the page predicted: it used T=15 borrowed from a row that is about A element with a 15-unit fade, generalised to splash B's quads, which is not what that row says. At 56.8 the splash elements' implied T is 23-34, none of them 15. And the step quantum does not rescue 15: splash steps are multiples of 17 = 255/15, which is what made 15 look confirmed, but at T=28.5 a step of 17 is simply TWO units of 8.9. A quantum fixes T only if you already know the step is one unit. 60 is NOT refuted -- 5.6% away against ~5% quantisation resolution -- so the port keeps it. But this DOES eliminate the unit constant as a cause of a late plate: at 56.8 units/s t=236 lands at 4.15 s against the port's 3.93 s, so the port is fractionally early. |
||
|
|
781a70af9a |
re: the animation clock is TIME-INTEGRATED -- one prediction held, one failed
Reported against the pre-registration, failure first. HELD, and by a cleaner argument than the regression: the clock is NOT frame-counted. The same animation takes 21 frame labels in one capture and 33 in another, and splash A's logo steps +136,+34 in one and +17,+51,+34,+34,+17,+17 in the other. A fixed per-frame increment cannot do that. Steps are always integer multiples of 17 (255/15 = one unit), so the clock advances in whole units at a rate set by how long the frame took. That retires '2 units per submitted frame' as a MECHANISM -- including my own page from two hours ago. The measurement stands; 2 was that run's frame pacing. units = 2 x frames computes an emulator artefact. Recorded as a proposal against the register, not enacted, and noted at the head of the H3 page rather than by editing it. FAILED: predicted 60 units per guest second, accept 55-65. Measured median 29.9 over six elapsed-ratio estimates (25.2-36.6). Prediction 3 said 30 was excluded and 30 is what came out. Why the rate is not a number yet: units/s = (d_alpha/dt) * T/255, and T is the load-bearing term. d_alpha/dt is measured cleanly six ways. T=15 for these elements comes from a corpus row whose usual derivation is circular with the thing just retired -- a step of 34/frame implies T=15 only GIVEN 2 units/frame. T=30 would give ~60. No amount of re-measuring alpha settles it. Settles with ptbtn00, whose T=22 is attested by two independent readers with no clock anywhere in the chain. That capture did not reach the title in 531 s of attract loop against 243 s in the previous run -- the variable attract loop capture-harness-status.md already documents at up to 604 s. Instrument built and control-passed; one run is missing. Instrument: guest timebase, 50 MHz per emulator.cc:225, scalar 1.0 per clock.cc:37, so no host wall clock enters any number. Control: 123.24 guest seconds across a capture running ~118 wall seconds. Told the port to change NOTHING today: ~30 rests on an unverified T, and retiring 2 x frames does not by itself supply a replacement. |
||
|
|
60b05bcd90 |
re: the game blends in the ENCODED space -- no gamma render target, anywhere
The Port asks whether the blend is evaluated on sRGB-encoded values or linearised and re-encoded. It is answered by one register field I already log, and the answer is the same on every draw of two full captures. RB_COLOR_INFO.color_format is k_8_8_8_8 (0) on 2402/2402 splash draws and 33779/33791 draws of the boot-through-title capture; the other 12 are k_32_FLOAT and k_16_16_FLOAT and are not colour passes. k_8_8_8_8_GAMMA (1) appears ZERO times, and color_exp_bias is 0 everywhere so nothing stands in for a gamma either. The mechanism is Canary's own source, not our inference: k_8_8_8_8_GAMMA is the ONLY colour format around which a piecewise-linear gamma<->linear conversion is applied (spirv_shader_translator.h:510 PWLGammaToLinear / LinearToPWLGamma, render_target_cache.h:720, dxbc_shader_translator_om.cc). With k_8_8_8_8 there is none, so the blender operates on the stored values as they are. So a renderer that linearises before blending and re-encodes after is doing a different operation -- and the difference is gamma-shaped and exactly zero on unblended pixels, which is the divergence signature the port reports. Also renamed my units-per-second pre-registration off the 'h4' prefix: the Port's BLOCKED.md numbers this blend-space question H4 and two different H4s in one corpus is how a citation goes wrong. |
||
|
|
8dac5aa264 |
re: pre-register H4 -- is the animation clock frame-counted or time-integrated?
H3 pinned 2 units per guest FRAME. The port needs units per SECOND, and that decomposition is only valid if the clock counts frames. If it integrates elapsed time then units/second is the invariant and units/frame is an artefact of whatever rate the host managed. Evidence it is time-integrated is already in hand and is the caveat H3 had to quote: across empty label 5376 the plate's alpha moved +82 where three adjacent labels each moved +23. 82/23 = 3.57, not an integer number of ticks, and a fixed per-frame increment cannot produce a fractional multiple of itself. Instrument: the draw logger now stamps each frame boundary with Clock::QueryGuestTickCount() and guest_tick_frequency() -- the GUEST's timebase, 50 MHz per emulator.cc:225, scalar 1.0 per clock.cc:37. No host wall clock enters the calculation. Discriminator, within one run: regress alpha step against the label's guest duration. Flat => frame-counted. Proportional => time-integrated, and the slope is the answer. Predicted before the run: time-integrated with r>0.9, at 60 units per guest second, accept 55-65, 120 and 30 excluded. Stated honestly as a CONSISTENCY prediction -- it is what the previous capture's run average implies -- not a blind one. Control: the same regression on ptcopyright's ramp, a different element with a different declared segment. Two elements must agree under the time-integrated model and need not otherwise. |
||
|
|
0565098fa2 |
handoff+index: H3 answered, the settle anchor, and the pad's full field set
Three rows the port is blocked on: H3 -- 2 units per guest frame, measured on the plate's own ramp against a pre-registration. Their 5 excluded by >2x, and the reason named: an alpha step is not a clock rate without the element's declared T, and my own splash-quad-timeline.txt published alpha against frame with no T column. That file now warns at its head. The title settle anchor is t~160, not t=118 -- it is ptcopyright, the last build-in element and the only glyph one. Said plainly that this is the reading under which their clock:'shared' collapses, and that a consequence is not a counter-argument. Told them NOT to change their 60 units/s yet: units/second is untouched by this and two of my own captures disagree ~2.9x on frames->seconds. The pad: sub_82457038 reads every field of XINPUT_GAMEPAD, 14/14 loads verified against the image, plus a second keystroke-queue path. Flagged as the superset the game can SEE, not the per-screen set, so it is used to check a binding table and not to write one. |
||
|
|
6aab30253a |
re: H3 answered -- 2 units per guest frame, and the settle anchor is t~160
The Port asked which of two of my measurements to believe, 55 units/s vs ~150, a factor of 2.7 off one game. Measured on the plate's own declared ramp, against a pre-registration committed first. PREDICTED 11 frames at 2 units/frame, 4.4 at the Port's inferred 5, +/-1. MEASURED 10 labels, and three consecutive gap-free steps of EXACTLY 23, which is 255*2/22 on the nose. 5 units/frame is excluded by >2x. Why the splash read as 5: an alpha step is not a clock rate. For a linear segment d(alpha)/frame = 255*(units/frame)/T. Splash B's quads step 34 with a declared T=15; the plate steps 23 with a declared T=22; ONE clock, two steps 1.5x apart. And the Port's intervals start at each quad's first submission, which on splash A is already alpha=85 -- not the element's t where alpha=0, and biased by a different amount per element because T differs. My own splash-quad-timeline.txt published alpha against frame with no T beside it, which is the column that makes the conversion possible; it now carries the warning. The other half: the 'title settled' anchor is ptcopyright reaching full alpha -- the last build-in element and the ONLY glyph one, which is what a glyph counter settling means. Calibrated on the plate's own ramp it lands at t~168 (t~176 at a flat 2.0/label). The Port's candidates are 118 and 160, 42 units apart: this is 8-16 units from 160 and 50-58 from 118. It is 160. Instrument fact that bounds all of it: labels with zero draws exist, ~1 in 5, and the clock does NOT advance a fixed amount across them -- across label 5376 the plate moved +82 where three adjacent labels each moved +23. So an empty label is a real advance, not a logger artefact, and spans that cross one are approximate. The conclusion rests on the gap-free steps. Also recorded: the sweep leaves never settle. They translate monotonically through every label examined and are still moving when the plate arrives, so 'settled' can only mean the build-in elements are done. NOT answered, and it is what the port actually needs: units per SECOND. units/s = (units/frame) x (guest fps); this pins the first at 2 and says nothing about the second, and 2x30 vs 2x60 differ by exactly the ~2 s the human reported. My own title-plate-delay-measured.md's 2.13 s does not reconcile with this capture's 20 labels for the same two anchors -- a real ~2.9x disagreement, now localised to frames->seconds rather than units->frames. Settling it needs the guest's own frame counter, which neither capture read. |
||
|
|
19aa1a89a3 |
re: pre-register the H3 measurement before reading the capture
The Port asks which of two of my measurements to believe -- 55 units/s from the plate page, ~150 from their reading of my splash timeline, a factor of 2.7 off one game. Neither is safe and for the same reason: both convert an ALPHA STEP into a CLOCK RATE, which needs the element's declared ramp length, because d(alpha)/frame = 255 * (units/frame) / T. My own splash capture shows that biting: splash B steps 34/label while splash A's logo steps 68 or 136 across one label pair. Same boot, 2x or 4x apart. An alpha step is not a clock rate. So measure on an element whose T is declared: ptbtn00, the plate itself, t=214 alpha=0 -> t=236 alpha=255, T=22 units. Predicted, before looking: 11 frames at the corpus's 2 units/frame, 4.4 at the Port's inferred 5. Accept +/-1. Committed first so it cannot be edited afterwards. |
||
|
|
c85e5b7c56 |
re: record that stale-instrument was run for the logger change, and returned nothing
R1 asks for tools/stale-instrument when an instrument improves. The draw logger improved this iteration; all eight claims that <harness> killed are about the SCREENSHOT harness -- polling cadence, x11grab latency, the title/plate classifier -- and none of them ever used the draw logger, so none re-open. Written down because 'ran it, nothing changed' and 'did not run it' are otherwise the same absence. |
||
|
|
4bb67fa166 |
re: the splashes have NO post-process -- one pass, source-over, alpha in the vertex stream
Play-test finding 4 asked, in order: is there a pass, what is it, where do its parameters come from, only then what curve. All four, from GPU state. 1. NO post-process pass. Over all 1 048 draws of frames 4..226 (both boot splashes): rt0=[tile=0 fmt=0 exp=0] on 1048/1048, pitch=1280 msaa=0 on 1048/1048, edram_mode only ever kColorDepth or kCopy, resolve dests only the two alternating front buffers, and NO texture base anywhere in the capture equals a resolve destination. The only texture bound in the whole splash region is the sprite page 0x11A50000. No blur, no bloom, no fade quad over a resolved image, no tone curve, no resolve-and-resample. 2. What it is: per frame, a full-screen replace triangle (the clear), a full-screen black quad through the ordinary blend, ONE batched sprite draw carrying every visible element (indices 4/8/12/24), and the two presentation resolves. 3. Where the parameters come from: NOT the constant banks -- the splash pixel shaders read zero float constants, ps_c[n=0] on 1048/1048, taken off each shader's own float_bitmap. NOT immediates. The fade is the per-vertex k_8_8_8_8 colour in a vertex buffer the guest rewrites every frame. 4. The curve falls out of 3 and is the corpus's existing 34/frame law, reproduced on an independent capture. Not claimed as new. And the composite is ORDINARY SOURCE-OVER, confirmed from the shader ucode rather than inferred from the blend register: the register reads ONE/ONE_MINUS_SRC_ALPHA, which looks premultiplied, and is -- because the shader premultiplies. The two together are src*A + dst*(1-A). So the 'more pronounced' fade is neither a blend difference nor a pass. The likely mechanism instead: the developer splash submits SIX quads, three logos plus three slightly-larger companions that lead them by 8 frames and are gone 79 frames early. Two over-blended copies of the same art at different scale is a halo, on screen only during the entry. Refutation attempt, recorded: REFUTED.md's re-opened rest() pair states its settling condition as 'a draw capture of the developer splash naming which of the three glows is submitted at rest'. This is that capture. All three companions ARE submitted in all 21 frames -- so no rule that hides one describes this stream -- but they are NOT interchangeable: Q6 leaves the plateau on its own -5.6/frame decay while Q4 and Q5 hold 255. The one-byte sibling difference is drawn. Trap recorded with the evidence: censusing the whole 600-frame log finds six 640x360 textures sampled ~330 times each, which reads exactly like a half-resolution blur chain. They are the attract movie's chroma planes and first appear at frame 234, after both splashes. Restricting the window is what separates them. Evidence: docs/re/data/splash-draw-pass-census.txt, docs/re/data/splash-quad-timeline.txt, docs/re/data/shaders/*.ucode.frag. Logger: canary sylpheed-re d90d14e02. |
||
|
|
3e60560344 |
register: reclassify under R1 -- name every instrument, re-open the ten our own killed
Both agents asked for this and neither could do it: the register is the file they both read to decide what NOT to try, so two agents agreeing is not the authority for changing it (RETRO-2026-08-31-agreed §7.1). R1: a refutation whose instrument is one of our renderers is not a refutation, it is "our renderer disagrees" -- 🟡, not ❌. The motivating case was not careless work. "Blending those sprites additively worsens every measure against the capture" killed a real disc field for weeks, and read exactly like a publishable negative; the renderer behind it had a stale keyframe association, no leaf geometry and no rotation. Nothing in the entry could have told you. All 222 entries now end with ⟨instrument⟩, read off each entry's OWN stated evidence -- never inferred. An entry that states none gets `unrecorded`, which is 83 of them. Ten moved ❌ -> 🟡, each naming what would settle it: 8 render-vs-capture, 1 our-reader, 1 harness. Three things the pass turned up: * The rest() question is OPEN and had been reading as settled in both directions -- "rest = last keyframe" was refuted by a sibling argument, and that refutation refuted by correlating our render against captures. Both legs are our renderer. Which one you believed depended on which entry you found first, and it decides the pose every plateau-less element is drawn at. * A withdrawal never reached its sibling: "2 391 frames, max glyph 0" was withdrawn because a long-lived x11grab stream freezes and repeats a stale frame; the 1 674-sample negative three lines above it, same probe, was left standing as a reinstated measurement. * 83 of 222 -- 37 % -- record no instrument at all. Not disputed, not safe: unauditable, and larger than every other group combined. tools/stale-instrument is the --stale query the rule needs, because a colour alone re-opens nothing: the failure was that nothing re-opened a claim when the instrument that killed it improved. Its own --check found a real bug on the first run -- sys.exit("text") exits 1, so three faults documented as exit 2 were reporting the same code as an ordinary miss. R1 is now standing text in PROTOCOL.md, with R5's exception: our tool is the right instrument for a question about our tool. |
||
|
|
d9cdfff0a8 |
handoff: the blend is a bit on the disc, and their three asks
Delivered: T8aD +0x04 bit 0x02 selects additive, so the port derives the blend instead of transcribing my table -- including for screens neither of us has captured. With why I got it wrong first: the bit was already in REFUTED.md, killed by a comparison of two renders made while our renderer had a stale keyframe association, no leaf geometry and no rotation. Their asks: pteff10 IS additive on the main menu, three sessions, every frame, and my coverage table listing it uncovered there is corrected. The sweep ramp is four leaf keyframes on the disc, with the oracle agreeing on sign and magnitude and a second identification from the sub-128 alpha. And kind & 0x2 is not mine to grant -- stated what the decode supports (0 violations in 15493 entries, and it means the declaration marks the element focusable, not that the cursor can reach it) and left the adoption to them. ui-blend-mode-measured.md is superseded in its classification and keeps its measurements, which are what the decode is fitted to. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Wuu56cE8vJGTBtn1ppsk8v |
||
|
|
bac8e17a7f |
re: the blend mode IS on the disc -- T8aD +0x04 bit 0x02, DECODED
Reverses two of my own pages. t32-blend-mode-not-on-disc.md said the mode is not
on the disc; ui-blend-mode-measured.md classified it measured and told the port
that which field selects it was unknown. Both were honest and neither is current.
Bit 0x02 of +0x04 set means the game draws that sprite ADDITIVE
(RB_BLENDCONTROL0 = 0x01010101); clear means premultiplied alpha-over.
Fit: 35 elements over three screens, 16 set/additive and 19 clear/alpha-over,
zero errors, every label read out of the guest command stream rather than off a
render.
Control: of every bit of the first twelve header words, exactly one separates
those 35 without error. Nothing ties with it -- which is precisely what the
+0x08 = 0x8050 candidate failed.
Within-pair: ptbtn00 0x0110 alpha-over against ptbtn00f 0x0112 additive, same
screen, same bundle, adjacent draws, one bit apart. And other f variants are
bit-clear and alpha-over, so it is not 'focused variants are additive'.
Out of sample: a prediction committed at
|
||
|
|
d694bcc53f |
re: the sweep ramp is DECODED -- four leaf keyframes, and the GPU agrees on sign and magnitude
The port asked for the sweep strips' vertex alpha as a function of position. It is not a runtime curve to sample: ptloop01/ptloop02's nested leaves declare four keyframes each, with x, alpha, rotation, scale and time. pteff03 loop 600u x -639 -> 1521, alpha 255 -> 128 -> 255, rot +30, sy 600 % pteff03a loop 720u x 1721 -> -839, alpha 0 -> 128 -> 255, rot -45, sy 800 % Checked against three sessions of GPU draws: both signs right every time, and magnitudes within ~15 % of the declared slopes. The independent bit worth having: across sessions the measured alpha spans 45..242, and only pteff03a declares alpha below 128 -- pteff03's ramp never leaves [128,255]. The strip measured at 45 is the 1303-tall one, which the AABB geometry says is pteff03a for a completely different reason. Two identifications agreeing. Stated as limits rather than buried: this cannot separate the two declared slopes, which are 25 % apart against a quantisation of 6.4 px and one alpha level over 3-4 frames; and absolute phase is unchecked because the AABB-left to element-x mapping under rotation and pivot is not established. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Wuu56cE8vJGTBtn1ppsk8v |
||
|
|
088df913b2 |
re: T8aD +0x04 bit 0x02 predicts the MEASURED blend, 35/35 -- and a prediction to test it
REFUTED.md kills this claim: 'T8aD +0x04 bit 0x02 selects an additive blend -> mine, and refuted. Blending those sprites additively worsens every measure against the capture.' That refutation rests entirely on our renderer, which the corpus's own rule calls a hypothesis under test. The blend is now measured off the GPU, so the claim can be tested against the oracle. 35 elements over three screens, every label an RB_BLENDCONTROL0 value read from the command stream: 16 bit-set and additive, 19 bit-clear and alpha-over, zero false positives, zero false negatives. The control that makes it a decode rather than a coincidence: of every bit of the first 12 header words, EXACTLY ONE separates those 35 elements without error. Nothing ties with it. A perfect partition on a small sample is worthless if half the header partitions equally well, which is the mistake +0x08 = 0x8050 was. And the pair no confound survives: ptbtn00 = 0x0110, ptbtn00f = 0x0112 -- the PRESS (A) plate and its own highlight, same screen, differing in exactly this bit, drawn alpha-over and additive respectively. Committed alongside is a PREDICTION for GP_OPTIONS, written before the capture that tests it: a different archive, a different element set, and a MIXED prediction -- po_menu_eff01/02/03 additive, 592 elements alpha-over. Falsified if those three draw alpha-over or anything else draws additive. The developer splash was considered first and rejected as a test: both its elements predict alpha-over, so it can fail but cannot discriminate. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Wuu56cE8vJGTBtn1ppsk8v |
||
|
|
6267245920 |
method: a truncating instrument, and an unreachable stop condition
The UI draw capture printed 8 vertices = two quads per draw, so a batched draw dropped the rest silently. Four EXTRAS elements therefore appeared in no draw on any screen, which reads as 'the game does not draw these' -- and the port spent an iteration measuring them as the worst on the screen and asking about them. When an instrument says an element never appears, check its limits before believing the game. And 'press down until the cursor stops moving' is not a stop condition on a menu that WRAPS: it was unreachable, the loop only exited by exhausting its budget, and it landed on EXTRAS because a dropped press cancelled one lap. An earlier version of the same loop pressed (A) on NEW GAME after two identical readings caused by a dropped press. What held throughout is the part worth keeping: verify the state you measured, never the actions you took. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Wuu56cE8vJGTBtn1ppsk8v |
||
|
|
fa887b4e5f |
re: EXTRAS complete -- ptframe4, pteff21/22/23 and pteff10 are all ADDITIVE
The four elements the port measured as the worst on EXTRAS, and which appeared in no draw, were in a draw all along: the 24-index additive batch holds six quads and Canary printed the first two. Cap raised to 64, screen re-captured, all six named. Same draw as ptframe3, whose state was already measured -- the one-way implication doing real work. pteff10 is identified too, and it needed the resting SCALE: it ships as 409x144 and is drawn at 200 % x 500 % = 816x720. The matcher's 'try 1x and 2x' rule could not name it at any scale and reported a near miss against something else, which is a failure wearing the clothes of an answer. Candidates are now the declaration's pivot*2 scaled by the resting keyframe as well as the texture at 1x and 2x, and the tolerance is the log's own NDC print quantisation rather than a chosen number. Flagged rather than buried: pteff10 measuring additive is in tension with the port measuring it nearly exact under alpha-over. Both can be true for a dim semi-transparent glow over a dark background, and it is the one row a rendering check does not corroborate. Also stated: the three full-screen alpha-over draws are NOT individually identified -- four elements declare 1280x720 -- so the label on those rows is a candidate, not an identification. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Wuu56cE8vJGTBtn1ppsk8v |
||
|
|
f0b4f0ad5f |
re: correct the blend page's reach sentence -- five elements uncovered, not one
sylpheed-port checked the coverage claim element by element and it was wrong. The page said everything on the two screens was covered but for pteff10; on EXTRAS, ptframe4, pteff21, pteff22 and pteff23 were also in neither the per-draw log nor a prose row -- and they are exactly the four the port measures as the worst elements on that screen. The result rows were never wrong. The claim about what they covered was, and it is the kind that reads as reassurance. Also flagged, and fair: 'every button' is a class generalisation in the page whose own instruction is to read it as per-element facts. It came from one element on the main menu. Now stated as such. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Wuu56cE8vJGTBtn1ppsk8v |
||
|
|
529cf13f2a |
re: the TITLE's blend states, the menu replicated twice, and the sweeps are on screen
Two more emulator runs close two of the three reach limits on the blend page. THE TITLE (entries 4 + 2 composited). Everything alpha-over except the two rotated sweep strips and -- the finding -- ptbtn00f, the PRESS (A) plate's focused variant, which is ADDITIVE while its own base ptbtn00 is not. That is what the documented plate pulse is made of, and a port drawing both alpha-over cannot reach the pulse's peak by any pacing. And ptlogo_back2 / ptlogo_back2eff are ALPHA-OVER. They are frame-shaped, large, dark and 94 %/87 % transparent -- every surface property the menu's ptframe* have -- so 'frame-shaped and mostly transparent implies additive' is refuted on the one screen that could test it. THE MENU replicates draw for draw in two further sessions; the one-session caveat is retired. THE VERTEX CAP was 8 = two quads, so a batched draw reported its first two elements and dropped the rest. Raised to 64. This is why ptframe4, pteff21, pteff22 and pteff23 looked like elements the game never draws: EXTRAS' 24-index additive draw holds six quads and the log printed two. THE SWEEPS are on screen on the main menu in every captured frame, stepping ~0.03 NDC per frame in opposite directions with their vertex alpha ramping, at different phases in two sessions. The leaf group runs on the menu. What that does not say is how much they contribute. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Wuu56cE8vJGTBtn1ppsk8v |
||
|
|
020f456974 |
re: retract 'the game batches elements that share a mode' -- its own log refutes it
I wrote that yesterday in HANDOFF, the finding page and INDEX. It is false: in one main-menu frame, draws 5, 6 and 7 are three separate additive draws -- consecutive, identical blend state, not merged. Only the one-way implication holds: elements inside one draw share a blend state; sharing a state does not put elements in one draw. The wrong version would have licensed the port inferring a mode for an element nobody observed, which is the one thing that page must not do. The ptframe4 conclusion is unaffected -- it is in the same DRAW as ptframe3, not merely the same mode. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Wuu56cE8vJGTBtn1ppsk8v |
||
|
|
880a4d562b |
re: kind bit 0x2 is the FOCUSABLE flag -- decoded, 0 violations in 15493 entries
The declaration entry's kind word (+0x28) and its focus/nav index (+0x2C) are the same fact twice: kind & 0x2 is set iff the focus index is >= 0. Checked over 24 UI paks and every parseable build in each -- 1062 focusable elements, 14431 not, zero exceptions. The test is two-sided, so it would fail if any focusable element lacked the bit or any non-focusable element carried it. Consequence: kind == 0x3002 is not the test for a button. It catches 778 of 1062 and misses 284 (26.7 %) at 0x2, 0x2002, 0x3003, 0x73002, 0x73003 -- including ptbtn00.rat on GP_TITLE's PRESS (A) plate, which is 0x73002. And 0x3000, 817 elements, looks like a button and is not focusable. This is also the refutation attempt on sylpheed-port's kind census. Their claim -- every decoration 0x0, every button 0x3002 -- is exactly right on the two screens they checked, reproduced here independently, and fails one build over on the title they have not run yet. The other kind bits are reported as observed structure and explicitly not claimed. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Wuu56cE8vJGTBtn1ppsk8v |