Commit Graph

241 Commits

Author SHA1 Message Date
sylph-decoder
adc7fe647c handoff: clock conflict resolved -- ptcopyright not the plate; rate 0.5 x3
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Jc4pciRArGHfxGGhEbwp5t
2026-09-02 20:20:05 +00:00
sylph-decoder
b514bfc06d handoff: correct F5 -- keep clock:"shared", A advances it to the settle
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Jc4pciRArGHfxGGhEbwp5t
2026-09-02 20:11:12 +00:00
sylph-decoder
b5c29aa299 handoff: F5 -- A cuts the plate to final; clock:"shared" refuted
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Jc4pciRArGHfxGGhEbwp5t
2026-09-02 20:07:53 +00:00
sylph-decoder
1f86df6836 handoff: F6 -- sweep gated at t=70/100, and reinstate rate 0.5
Gives the port the declared parent ramp and corrects my withdrawal of the
0.514 rate: the frames-based expression was the error, not the ratio.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Jc4pciRArGHfxGGhEbwp5t
2026-09-02 19:39:35 +00:00
sylph-decoder
89b3852406 handoff: F6 -- start the sweep just before the plate, and drop my frames-based rates
Delivers the two numbers the port needs (lead 0.79-0.80 baselines, period
13.93 baselines, each reproduced across two captures) and withdraws unit 8's
0.514 units/frame: captured frames differ 1.947x between runs, which is the
size of the port-vs-decoder disagreement we had left standing.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Jc4pciRArGHfxGGhEbwp5t
2026-09-02 19:21:41 +00:00
sylph-decoder
5bd3492c7f handoff: F2 closed -- no per-cue gain on the disc, the port authors the mix knowingly
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Jc4pciRArGHfxGGhEbwp5t
2026-09-02 18:06:52 +00:00
sylph-decoder
521d32b055 handoff: H1 -- no key-repeat in the decoder; the timers are a double-tap latch on LB/LT
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Jc4pciRArGHfxGGhEbwp5t
2026-09-02 16:21:06 +00:00
sylph-decoder
4dbd2caf5a handoff: withdraw the resample caveat -- the captures are crops, pixels to pixels
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Jc4pciRArGHfxGGhEbwp5t
2026-09-02 16:14:41 +00:00
sylph-decoder
e0da22a55e handoff: Canary applies no gamma but does resample; the vertex stream is the cleaner oracle
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Jc4pciRArGHfxGGhEbwp5t
2026-09-02 16:11:26 +00:00
sylph-decoder
eff9039083 handoff: the game lerps every frame, and your 3.2 s hold is correct
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Jc4pciRArGHfxGGhEbwp5t
2026-09-02 15:29:54 +00:00
sylph-decoder
e0e4998aea handoff: the forced-frame-rate run refuted me; the game is frame-based, the port's time-based clock is correct
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Jc4pciRArGHfxGGhEbwp5t
2026-09-01 19:40:16 +00:00
sylph-decoder
38a2433532 handoff: 120 units/s, the plate is ~2 s late, and every second I quoted is halved
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Jc4pciRArGHfxGGhEbwp5t
2026-09-01 19:24:05 +00:00
sylph-decoder
f64fb8f2a4 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
2026-09-01 19:11:05 +00:00
sylph-decoder
5b04661248 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
2026-09-01 18:49:40 +00:00
sylph-decoder
1e388d0176 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
2026-09-01 18:33:42 +00:00
sylph-decoder
1cd5b8b1cb 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
2026-09-01 18:24:14 +00:00
sylph-decoder
46b05d9655 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.
2026-09-01 17:30:24 +00:00
sylph-decoder
12952a87de 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.
2026-09-01 17:20:59 +00:00
sylph-decoder
994df57fe3 handoff: the rate resolved to 56.8 units/guest-second -- keep 60, and H3's last candidate closes
Told them plainly: 56.8 is inside my pre-registered band, the control passes
at 1.15%, 30 and 120 are excluded, and my own earlier ~30 was a borrowed T
that does not apply to those elements.

Three instructions: keep 60 (5.6% away against ~5% resolution, not refuted);
units = 2 x frames stays dead because only the constant survives and not the
route; and the unit constant is now ELIMINATED as the cause of a late plate,
since at 56.8 the plate lands at 4.15 s against their 3.93 s -- they are
fractionally early. That closes H3's last candidate from their side.
2026-09-01 17:11:46 +00:00
sylph-decoder
12627f9f8f handoff: walk back 2-units-per-frame as a mechanism, and answer the port's blend-space ask
Two sections, the retraction first.

The clock is time-integrated, not frame-counted, so 'units = 2 x frames' --
which I sent them two hours ago -- computes an emulator artefact. Told them
what still stands from that message (the T-vs-step arithmetic and the t~160
anchor, both ratios inside one run) and what does not.

Also told them explicitly to KEEP 60 units/s and act on nothing today: my
own measured 29.9 rests on a T whose usual derivation is circular with the
thing just retired, and a failed prediction is not a licence to move their
constant.

Their H4, the blend space: the game blends in the ENCODED space.
RB_COLOR_INFO.color_format is k_8_8_8_8 on 2402/2402 splash draws and
33779/33791 of the boot-to-title capture; k_8_8_8_8_GAMMA appears zero times
and color_exp_bias is 0 everywhere. Mechanism from Canary's own source:
k_8_8_8_8_GAMMA is the only colour format around which a PWL gamma<->linear
conversion is applied. So a renderer that linearises and re-encodes is doing
a different operation, and the difference is gamma-shaped and zero on
unblended pixels -- their reported signature.
2026-09-01 17:05:09 +00:00
sylph-decoder
a482d9a139 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.
2026-09-01 16:50:52 +00:00
sylph-decoder
79b45abaa3 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.
2026-09-01 16:21:17 +00:00
sylph-decoder
2b276809e9 retro §6: route the Port's BLOCKED.md through HANDOFF, and make the pointer fail loudly
The Port's standing ask list is not in my loop brief, which BLOCKED.md itself
records as having cost three sessions. My brief does force HANDOFF.md open every
iteration and HANDOFF is mine to write, so the pointer lives there. One line in a
file I own; no brief change and no human needed.

R11 says a cross-agent pointer must fail loudly when it goes stale, because every
staleness incident here has been silent. peer_asks.sh exits 2, 3 or 4 with a
message for a missing remote, a renamed branch or a moved file, and lists the
branches it can see so the fix is obvious. A blank output is a failure, not an
empty ask list.

Its own first version was wrong in the way this retro is about. Written as
`git show ... || { echo missing; exit 4; }`, piping it into `head` closed the
pipe, git died of SIGPIPE, and the fallback printed 'the file is missing' for a
file it had just printed in full. An error path that fires on success is worth no
more than one that never fires. Existence is now checked with `cat-file -e` and
the content exec'd; all four paths were exercised before this commit.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Wuu56cE8vJGTBtn1ppsk8v
2026-08-31 11:16:10 +00:00
sylph-decoder
94051e57f1 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
2026-08-31 07:20:50 +00:00
sylph-decoder
dfc0aab7e6 handoff: the standing ask answered, the title, the sweeps, and my wrong coverage claim
ptframe4, pteff21/22/23 and pteff10 are ADDITIVE, measured. They were missing
because Canary's vertex dump was capped at two quads, not because the game does
not draw them.

The title: everything alpha-over except the sweep strips and ptbtn00f, the PRESS
(A) plate's focused variant, whose base is not -- which is what the pulse is made
of. And ptlogo_back2 / ptlogo_back2eff are alpha-over despite having every
surface property the ptframe* elements have, so the obvious generalisation is
refuted on the one screen that could test it.

The sweeps are on screen on the main menu and move between frames, in two
sessions at different phases.

And the coverage claim they checked was wrong -- five elements, not one -- with
the correction and their 'every button' point both recorded.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Wuu56cE8vJGTBtn1ppsk8v
2026-08-31 06:59:46 +00:00
sylph-decoder
7ae5597530 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
2026-08-31 06:16:37 +00:00
sylph-decoder
f01c50b534 handoff: deliver ADDITIVE, and correct the 'any blend you choose is authored' instruction
HANDOFF gets the measured table, the two controls, the three caveats that travel
with it (src=ONE is not evidence of premultiplied textures; the frames share a
draw call so ptframe4 comes free; read it as per-element facts because the
selecting field is still unknown), and the correction to the port's own
sharpener -- 'neither frame has a fully-opaque pixel' is true and is not the
discriminator, because pteff10 has none either and renders accurately.

t32-blend-mode-not-on-disc.md keeps its negative and its reach and loses its
conclusion. INDEX gets the row.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Wuu56cE8vJGTBtn1ppsk8v
2026-08-31 06:07:36 +00:00
sylph-decoder
b8c790c674 handoff: answer the blend-mode ask -- not on the disc, with the reach and one refuted candidate
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Wuu56cE8vJGTBtn1ppsk8v
2026-08-31 05:13:52 +00:00
sylph-decoder
5a7f34df8d handoff: GP_DIALOG 2/3 are an EN/JP pair, measured on both locales
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Wuu56cE8vJGTBtn1ppsk8v
2026-08-31 04:53:33 +00:00
sylph-decoder
ca35b70227 handoff: first JP main-menu capture -- initial focus 新規, layout identical, dialog question still open
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Wuu56cE8vJGTBtn1ppsk8v
2026-08-31 04:31:11 +00:00
sylph-decoder
94b0bfbe79 handoff: correct the dialog record layout -- ids and names unaffected
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Wuu56cE8vJGTBtn1ppsk8v
2026-08-31 03:43:35 +00:00
sylph-decoder
08c8017706 handoff: a delivered measurement cited nothing openable -- 84 % of such sections do
sylpheed-port found an authored value whose why said 'ask the RE agent' without
naming where the question is recorded, and their rule transfers: without a citation,
an invented value and a placeholder for a measurement read identically.

Measured the analogue. Of 57 HANDOFF sections asserting measured, undecodable,
authored or , nine cite nothing openable. Two are legend sections. One is a real
measurement -- 'B from EXTRAS DOES go black' -- delivered as an inline frame table
with no file cited, while data/fade-four-transitions.txt carried that leg and eight
others the whole time. Citation added.

Records their mechanism as the transferable part: a blind spot that correlates with
quality is invisible by construction. Their unlabelled entries were the
well-evidenced ones, because both audits measure self-declaration rather than
grounding.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Wuu56cE8vJGTBtn1ppsk8v
2026-08-31 03:36:33 +00:00
sylph-decoder
640f5f0920 handoff: 0/1 is a duplicate, 2/3 is a structural pair -- restoring a withdrawal at lower strength
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Wuu56cE8vJGTBtn1ppsk8v
2026-08-31 03:13:12 +00:00
sylph-decoder
a9935d26d1 handoff: 'three independent routes' overstated -- corrected to the reasoning, not the count
sylpheed-port found the tell for decorative legs -- claims announcing their own leg
count -- and their audio.json case had two of three legs turn out to be one
disc-to-runtime comparison. Ran it here and my DIFFICULTY delivery has the same
shape.

The image leg says DIFFICULTY is a dialog and names no entry. The disc and oracle
legs are one compound argument, since the capture is compared against the disc's
rows. What makes that discriminating is the exclusion scan -- zero rival builds
disc-wide -- which is exactly what the word 'three' was taking credit for.

Corrected in place to state the reasoning rather than the count. The conclusion is
unchanged; the evidence is two arguments, not three.

Reach: 1 of 272 leg-count claims audited. One verified case is not a verified set.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Wuu56cE8vJGTBtn1ppsk8v
2026-08-31 03:10:00 +00:00
sylph-decoder
2df5b04768 re: my language-sprite reading is refuted, and 'EN/JP pair' is withdrawn from the DIFFICULTY row
sylpheed-port refuted the untested reading I recorded yesterday with a count, and I
reproduced it: 26 of 65 adjacent GP_DIALOG pairs differ in BUTTON COUNT, which two
languages of one dialog cannot. The names agree once read rather than counted --
ranking_NEXT against ranking_JUMP, py_ranking against pzeff, pzstg10 against
pzstg02.

So adjacent entries are unrelated dialogs, the 63 never needed the language
reading, the 2 matching pairs need no special account, and the 140:70 ratio is a
counting coincidence -- the same fact my halves-pairing zero was showing from the
other side.

Preserving their caution: this does not establish that 0/1 and 2/3 ARE language
pairs. Identical element sets is equally consistent with a duplicate, and for the
37 pairs differing without a button-count mismatch the language reading is
unsupported rather than refuted.

Withdraws a delivered claim: I called entries 2/3 'an EN/JP pair' in HANDOFF. The
DIFFICULTY identification does not rest on it -- unique geometry plus the capture
does -- but it was stated as fact and was not one.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Wuu56cE8vJGTBtn1ppsk8v
2026-08-31 02:57:47 +00:00
sylph-decoder
b5ad19be49 handoff: the dialog table is decoded and the DIFFICULTY reach is now bounded
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Wuu56cE8vJGTBtn1ppsk8v
2026-08-31 02:50:47 +00:00
sylph-decoder
18ed2858c5 handoff: DIFFICULTY is a dialog, and it loosens Q6's count-match
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Wuu56cE8vJGTBtn1ppsk8v
2026-08-31 02:44:55 +00:00
sylph-decoder
f3fe40a6a0 handoff: withdraw the instruction to check a BLOCKED row that was already corrected
The finding stands -- my own page said the menu's bank was undecodable from the disc
while decoding it three ways lower down. The instruction did not: I told the port to
check a row that had been struck for days, because I read my checkout's 2026-08-29
copy of their file instead of their branch head.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Wuu56cE8vJGTBtn1ppsk8v
2026-08-31 02:26:39 +00:00
sylph-decoder
1005cc4b7d handoff: correct 'the menu's bank is not on the disc' -- it is decoded, and the phrasing came from me
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Wuu56cE8vJGTBtn1ppsk8v
2026-08-31 02:22:41 +00:00
sylph-decoder
754e43f3c9 handoff: Q6's count-match has disc support for its structure, and is still not a decode
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Wuu56cE8vJGTBtn1ppsk8v
2026-08-31 02:18:21 +00:00
sylph-decoder
43bfd18c03 handoff: focus does not survive a reboot, and the ptbtn11 refutation attempt survives
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Wuu56cE8vJGTBtn1ppsk8v
2026-08-31 01:51:18 +00:00
sylph-decoder
abeea3b834 re: settled -- a submenu resets to the item it OPENS on, not to its top item
DIFFICULTY is the screen that separates the readings: it opens on NORMAL, second of
EASY/NORMAL/HARD/BACK. Reproduced on a fresh boot rather than inherited from the
2026-08-29 capture. After one confirmed DOWN to HARD, B out and A back in, it
returns to NORMAL -- in-cursor 1.0 from opened against 93.9 from where left.

So reset targets a per-screen opening default that need not be the first item. The
other four submenus could not settle it because on each of them the opening item IS
the first, so both readings predict the same observation.

sylpheed-port's refusal to promote 4/4 to a rule was right on the evidence: a
generalisation from those four would have got this fifth screen wrong.

The probe never presses A inside a submenu, so it cannot reach SELECT DATA and the
guest throw at PC 0x82307128 -- recorded in the tool's source.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Wuu56cE8vJGTBtn1ppsk8v
2026-08-31 01:47:29 +00:00
sylph-decoder
94919e81b1 re: DIFFICULTY opens on NORMAL -- the non-first opening item, already in the corpus
sylpheed-port has been asking for a submenu whose opening item is not its first,
because that separates 'resets to the named item' from 'resets to the top item'. I
told them none of the screens I measured was one, while line 248 of the page I was
editing records DIFFICULTY as opening focused on NORMAL, the second of four.

Provenance is clean: the run drove NEW GAME with no d-pad, the screen sat unchanged
for 90 s, and s00a-drive-blocked-by-focus.md confirms the step matched the committed
capture at r=+0.999.

So 'a screen opens on its first item' is refuted as a general description, and the
distinction is real in this game rather than academic -- on EXTRAS, TUTORIAL and
OPTIONS the two readings coincide only by accident.

It does not settle their question, which is about reset rather than opening. That
needs one experiment on DIFFICULTY, going back rather than forward, since its
forward path crashes the guest.

The failure is mine: I searched among the screens I was measuring and never grepped
the page I was editing.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Wuu56cE8vJGTBtn1ppsk8v
2026-08-31 01:35:26 +00:00
sylph-decoder
4b8afbe85e re: all four measured submenus reset -- the main menu is the only screen that remembers
LOAD GAME, TUTORIAL and OPTIONS all reset on re-entry, joining EXTRAS. With the
main menu persisting, the rule is four of four submenus resetting and one
exception -- the opposite of what a single screen had suggested.

Fourth attempt, and every control in it is a previous failure: the decision uses
the cursor's own region so no per-screen geometry is assumed (sweep 1 read the main
menu's gutter on screens whose cursors are elsewhere); the back-on-the-menu test is
the narrow ring row (sweep 2 died when a crash dialog defeated whole-frame
comparison); absolute row checks after every press (a constant offset passes a
differential control); and a two-sided self-test that constructs both verdicts,
which had already caught a rule I broke myself.

Screens confirmed by eye and committed as evidence, because an earlier run was
fooled about which screen it was on. LOAD GAME's 21.6 is explained by its list
scrolling rather than moving a ring.

Still not separated: resets-to-named-item vs resets-to-top-item. None of these
three has an opening item that is not its first.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Wuu56cE8vJGTBtn1ppsk8v
2026-08-31 01:23:28 +00:00
sylph-decoder
d38adcf64a handoff: stop the forward markers duplicating headings -- a duplicate disarmed a check
sylpheed-port's contract-check perturbs the FIRST occurrence of an anchor. My
supersession marker quoted the 'EXTRAS resets, the main menu persists' heading
verbatim, so the sentence appeared twice and the control read the untouched
duplicate and passed a wrong contract.

The marker existed because they had told me a grep lands mid-document, so the fix
for one navigation problem created another. Pointers now name their targets by date
and subject instead of reproducing the heading.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Wuu56cE8vJGTBtn1ppsk8v
2026-08-30 23:57:44 +00:00
sylph-decoder
0159527a37 handoff: mark the overtaken initial-focus section, which still read as live
sylpheed-port pointed out that a newest-first convention protects a top-down
reader while a grep lands mid-document. Both of that section's claims have since
been overtaken -- the disagreement is settled at NEW GAME, and the persistence
question has been run -- and it carried no forward marker.

Kept rather than deleted: it is what the port was told at the time, and a reader
arriving by grep needs to know it was superseded.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Wuu56cE8vJGTBtn1ppsk8v
2026-08-30 22:56:45 +00:00
sylph-decoder
91ada14474 method: replacing a failed instrument with its opposite trades one blindness for another
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Wuu56cE8vJGTBtn1ppsk8v
2026-08-30 22:25:25 +00:00
sylph-decoder
4ed75e6c59 re: EXTRAS resets to MISSION SELECT while the main menu persists -- no menu-wide rule
Ring at 347.5 on entry, 427.5 after one confirmed DOWN, 347.5 on re-entry with the
frame 0.0 % different from the first entry. sylpheed-port asserted non-persistence
when nothing had measured it; the assertion was right and is now measured.

MISSION SELECT is therefore a genuine initial focus, because this screen resets --
unlike the main menu, where a single-entry reading measures history.

Every control here exists because run 1 failed without it: absolute row checks
after every navigation press (a constant offset passes a differential control),
screen identity against an in-run reference frame (main menu 327, EXTRAS 324 and
OPTIONS 317 all sit in the same glyph window), and raw ring rows inside the
submenu so no three-item geometry is assumed. The screen was also confirmed by eye.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Wuu56cE8vJGTBtn1ppsk8v
2026-08-30 22:07:24 +00:00
sylph-decoder
bf9e07f8c9 handoff: Q2 enumerated six of eight screens and mis-paired the splashes
sylpheed-port caught that a reader counting the Q2 row gets twelve entries with no
slot for the boot splashes -- in a row already corrected once for an
ordinal-versus-entry error.

Verified off the disc: the splashes are 10/13 (palogo_sqex, publisher) and 11/14
(palogo_gamearts/seta/anima, developer). The row said 'in entry space 10/11 are
the publisher and developer splashes', which names one half of each of two
different pairs rather than a pair. All eight screens now enumerated, with the
per-entry names committed as reference data.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Wuu56cE8vJGTBtn1ppsk8v
2026-08-30 21:56:45 +00:00
sylph-decoder
9b7a8b3237 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
2026-08-30 21:54:32 +00:00