ed9a7d702dfc44259653d0fbd7e78f4a21bef395
177 Commits
| Author | SHA1 | Message | Date | |
|---|---|---|---|---|
|
|
7b3c83858d |
re: index F6 unit 9, which closes the sweeps' unmeasured period
ui-clock-freezes-at-settle.md left the sweep period ❔ because a validated estimator disagreed between two dwells (515 vs 452 frames). The cause is now measured: captured frame counts are not comparable across runs at all -- 1.947x between two captures of the same animation, with the baseline moving 1.953x alongside. As a ratio the period reproduces to 0.35%. 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
|
||
|
|
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 |
||
|
|
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. |
||
|
|
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. |
||
|
|
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. |
||
|
|
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. |
||
|
|
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. |
||
|
|
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
|
||
|
|
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 |
||
|
|
0af81d7549 |
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 |
||
|
|
0ea2b8e00d |
re: first audit of INDEX against the pages it links -- 3 of 8 rows were stale
INDEX is read every iteration and is the first thing a new reader meets, and I had admitted three times to never auditing it. Found by accident: I was about to spend a boot measuring whether A skips a movie because INDEX said 🟡, when movie-binding.md had it settled since 2026-08-28 with a three-boot baseline and a delivery counter, and HANDOFF carried it correctly. The staleness was in the index alone. Three stale rows fixed: movie skippability, SE audio extractability, and B leaving the main menu. Five other hits read and left alone -- index and page were talking about different clauses. One of the three should have been caught by check_refuted.py: REFUTED holds the same dead claim with a different second clause, and the register matches exact wording. Its docstring documents that weakness; this is the first live instance. Also flags a within-page contradiction not fixed here: menu-audio-cues.md line 81 still heads a section saying SE audio is not extractable, which its own line 189 refutes. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Wuu56cE8vJGTBtn1ppsk8v |
||
|
|
c5d685ba15 |
re: the sweep IS drawn on the JP title -- and my gate was phase-locking the shutter
The occlusion hypothesis is refuted: build 7 draws the same three ROT strips at higher alpha than English, so there was never an absence to explain. The 0.32-vs-11.9 tension that motivated it was an artefact of my own instrument. Both JP captures were shuttered on the plate pulse, and the plate's pulse is part of the animation -- so the gate synchronises the shutter to the animation's phase. Measured at the shutter instant, the sweep sits 25-26 px apart across two runs in different locales and different sessions: 1.6 % of a ~1600 px traverse. So the 0.32 I recorded as between-session capture noise measures my trigger's repeatability, and I read it as evidence the title is still when it is evidence the gate works. The era adjudication is unaffected -- margin 16.72 clears even the un-locked 11.9 -- and unaffected for the reason that file already gave: correlated noise cancels in a margin. Refutation attempt on sylpheed-port's positional-mechanism rejection: FAILED, the claim stands. Its residual sits inside lit logos, and the logo ROI is byte-identical across five differently-phased frames in two sessions. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Wuu56cE8vJGTBtn1ppsk8v |
||
|
|
c364cde476 |
re: sweep the disc for the ordinal foot-gun -- GP_TITLE was the mildest case
Last iteration I retracted three claims because `--build 10/11` on GP_TITLE are entries 12/15, and named the untested remainder in my own report: how much else in the corpus used a build ordinal as an entry index. This is that sweep. `screen --build N` indexes a predicate-filtered list, so every rejected entry shifts every later ordinal. Disc-wide: 21 of 24 build-bearing archives diverge, 18 of them at ordinal 0 -- `--build 0` is entry 108 in each GP_MAIN_GAME_*2D, 24/26 in GP_HANGAR_ARSENAL/GP_READY_ROOM. GP_TITLE is the ONLY archive whose first ten ordinals are the identity, which is the sole reason 207 of the corpus's 226 build citations are safe. Second foot-gun: `--all` swaps the predicate and renumbers 18 archives, so `--build N` and `--build N --all` are not the same object. The instrument failed its control first. A version using parse_build as the predicate reported GP_TITLE as 16 builds, ordinal == entry throughout -- it would have certified the exact bug it was built to find. The shipped version uses the same predicates screen_builds() uses and reproduces `screen list` on GP_TITLE exactly. Audited all 226 citations. One real defect: a five-row table in ui-keyframe-time-unit.md headed "declared element (build 11)" spans builds 10 and 11 -- palogo_sqex is in 10. All five placements re-verified and correct, so the linear-ramp measurement is untouched; only the label was wrong. Fixed with a per-row bundle column. GP_DIALOG --build 0 and GP_DEBRIEFING_PILOTLOG --build 10 re-run and reproduce. Refutation attempted: sylpheed-port's corrected mid-ramp test rests on ptlogo_all_eff holding a=127 from t=112 to t=246. Their quote is exact and it is a plateau. The refutation fails; their correction stands. METHOD already carried the rule I broke, and ui-splash-addressing already said the splashes need --all. The failure was not missing knowledge -- it was addressing a bundle by index without grepping for the index first. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Wuu56cE8vJGTBtn1ppsk8v |
||
|
|
dc0b84c87f |
handoff+index: a .tbm draws, and screen render omits it silently
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Wuu56cE8vJGTBtn1ppsk8v |
||
|
|
3c004845fa |
re: the PRESS A plate PULSES -- measured, and it keeps an authored entry
Answers the port's ask #1, which it had flagged as the only one of its four that could delete an authored entry rather than confirm one. It confirms one. Held at the title with no input, the plate oscillates continuously: two windows in one boot, 58 s and 57 s, ~23 cycles each, no decay. Periods 2.530 and 2.540 s by upward mid-crossings -- 0.4 % apart. It never goes off. The plate-absent floor is 159 green pixels, measured on the committed live-title-build4-no-plate.png; the pulse bottoms at 714, 4.5x that. So the port's 'flash and nothing after', reasoned from ptbtn00 expiring at t=244, is wrong on the boot's end state -- ptbtn00f's 120-unit cycle is what runs. Instrument controls were run before it was pointed at anything unknown: the glyph counter reproduces the documented 753 on live-title-press-a.png and 327 on live-main-menu.png exactly. Two estimators, and only one replicates. Mid-crossings agree across the two windows to 0.4 %; a single-sinusoid least-squares fit does not (2.553 vs 2.413), because the waveform is fast-rise/slow-decay rather than sinusoidal -- its own r2 of 0.468 and 0.228 is the tell. Both were controlled on synthetic sinusoids at 2.24/2.55/3.10 s laid on the ACTUAL timestamps and recovered every one exactly, so neither is broken; one is misspecified. Recorded as such. The wall-clock is 13 % longer than the corpus's earlier 2.24 s mean. Same declared 120 units, different emulator pacing (x1.27 here against x1.12), so this corroborates 'author the units' rather than disturbing it. Reach stated: one boot; does not distinguish the boot title from an attract-loop title; and the glyph count is a thresholded pixel count, so 714/1520 is not an alpha ratio and no duty cycle can be read off it. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Wuu56cE8vJGTBtn1ppsk8v |
||
|
|
e94e203a71 |
re: the A-press fault is SOLVED -- Xenia swallows input, the guest pump is unbounded
The 326 MB log from the failing run was still on disk, so this needed no emulator time at all. Mechanism: Xenia's XamInputGetKeystrokeEx returns X_ERROR_SUCCESS with a zeroed keystroke on every call while a XAM dialog is up (xam_input.cc:197, upstream Canary). The game's keystroke pump -- sub_82457038, read out of the image -- is an unbounded 'while (GetKeystrokeEx() == SUCCESS) queue.push_back()'. It queued 8 388 608 empty keystrokes, grew its vector to 64 MB, asked for 128 MB, got a failed allocation back unchecked, and copied off the top of the guest stack. Two independent instruments agree to within 7: the Canary counter's last report before the crash says 8 388 601 swallowed calls; the crash dump's r29 says the vector held 8 388 608. The reporting granularity is 600. Retracts this page's own 'r9 is a wild pointer above 4 GB'. Xenia prints si_addr, a host address; the guest is mapped at 0x100000000, so the fault address is guest 0x701D0000 -- which is exactly r9 in the register dump. Also refutes nothing of the port's, but answers its ask #3: the two press-a captures are different frames (40.84 % of the band's pixels differ at the best alignment, which has a sharp minimum), so its 0.301 % is not an instrument floor. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Wuu56cE8vJGTBtn1ppsk8v |
||
|
|
6d7bc87b0f |
re: diagnose the A-press fault -- a wild pointer, and a third failure mode
The blocker on all menu-side dynamic RE in this container, measured over four runs and traced to an instruction. A single A press on the title produces a Xenia CRASH DUMP with PC 0x824578A0 and "Access Violation: write at 0x00000001701D0000", repeating 32 356 times and writing 326 MB of register dump in about ten seconds. Four A runs faulted; four no-input runs in the same sessions completed. REFUTED, my own hypothesis: it is not an unimplemented instruction. The config carries break_on_unimplemented_instructions = true and Xenia's own message reads "to skip, disable break_on_unimplemented_instructions", so the flag looked like the fix. Booting with it false faults identically, and no "Unimplemented instr" line is ever logged on stdout or stderr in any run -- and since that path emits its XELOGE BEFORE the guarded DebugBreak, the absence rules the mechanism out rather than leaving it open. The dump comes from Emulator::ExceptionCallback, a genuine guest exception. The instruction, read from the image rather than the database: b0c90000 is sth r6, 0(r9), the first of four halfword stores at offsets 0/2/4/6 through r9 inside a bne- loop -- code filling an array of 8-byte records with four u16 fields each. So r9 is a wild pointer, and 0x1701D0000 is above 4 GB, outside the guest's 32-bit address space entirely: not a null dereference and not a small overrun, but a base that was never a guest address. The database agrees on the containing function, sub_82457780 at +0x120. It is a THIRD failure mode. Not the cache-flush crash at 0x82307128, and not the loader stall documented in canary-scripted-input-traps.md, which logs ZERO crash dumps. Unlike the stall it reproduced 4 of 4, so that page's "retry whole boots" does not obviously apply. It does not explain how Q4 and Q5 pressed A successfully; what differs between those runs and these has not been found. frame_clock.sh's 300 MB guard killed the run as designed -- the session log's "EMULATOR GONE at 56s" is the guard, not the crash. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01QsEPXWVaEpyfudtR6re1Pd |
||
|
|
29c99e1b3e |
re: primitive blend mode -- undecodable with reach, and no longer a risk
Looked in four places. The bundle has no field: a primitive has no RATC child at all and the declaration words are constant across every element of three measured screens -- the two grounds ui-prm-primitives.md already used to refute a bundle-side LAYER key, and they apply identically to blend. The colour census: every full-screen *eff00* primitive on the disc carries pure black at its various alphas, and the only non-black primitive anywhere is pbafc.prm, RGB 00e8e0 cyan. The occlusion constraint cannot reach that one. pbafc.prm looked alarming at a declared 844x600 and alpha ff; it is a small moving glint. It strobes between alpha 255 and 124 every 2 units, travels from x=178 to x=291, and is scaled 2%x3%, so it draws about 17x18 pixels. At that size it occludes essentially nothing. The oracle is unavailable: GP_READY_ROOM is a recorded no-go and gameplay needs the A press that faults the guest in this container. But the consequence closes even though the question does not. For a BLACK quad -- which is every primitive forced_backdrop touches -- the hypotheses differ only in whether it hides what is beneath. Drawn first it is correct under both; drawn last it is correct only under additive. So the rule's verdict is robust to the open question, and the port's original "layerless sorts last" was wrong under alpha-over and merely pointless under additive. This is explicitly NOT evidence for alpha-over. The investigation also found forced_backdrop judging coverage from the pivot alone, ignoring scale -- pbafc.prm is the disc's own proof that a nominally 844x600 element can draw at 2%. Checked before changing anything: all 80 forced instances are at scale 100% on every opaque instant, so no verdict moved. The guard now requires scale >= 100 at the instants it counts as opaque. Defensive, not a fix. 4 + 13 disc tests green either side. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01QsEPXWVaEpyfudtR6re1Pd |
||
|
|
1f6e07598e |
re: the primitive colour census -- and it refutes 38 of my own 80 forced verdicts
A disc-wide census of the ARGB that keyless elements carry. Every full-screen *eff00* PRIMITIVE is pure black at its various alphas (ff000000, 7f000000, 40000000, b2000000, cc000000, d4000000, 00000000). Black at alpha a over content is exactly an alpha-over dim or fade, and an additive black quad would be a no-op nobody would author -- so this narrows the open blend question a long way. The only non-black primitive on the disc is pbafc.prm, RGB 00e8e0 cyan at alphas up to ff, and it is 844x600, NOT full-screen, so it sits outside forced_backdrop's geometry guard. It is now the sole additive candidate. The census also refutes my own argument for nearly half its verdicts. Of the 80 forced-first instances only 42 are .prm; 38 are .tbm carrying fade ffffffff. A SOLID white quad at alpha 255 painted first would make the screen white, and no screen is white -- so a .tbm is a white modulation on a texture, and element alpha does not establish its coverage. That is the .t32 error one file extension further out. I guarded that with el.sprite.is_some(), which fixed the symptom and not the cause: an element's alpha is not its texture's opacity, and only an untextured primitive makes the two the same fact. So 42 verdicts stay decoded and 38 drop to inferred -- still almost certainly right, since all are named *base*, all are full-screen, and pfbase.tbm's first position is measured in the running game, but that is a name-and-role argument which this page elsewhere calls the weaker kind. The code is deliberately unchanged. Restricting forced_backdrop to .prm would send eleven screens' backgrounds back to u32::MAX -- last -- which is the blank-screen bug the rule was written to fix. Downgrading the status is honest; reverting the position would be wrong. The 42/38 split is pinned by a test so anyone tightening the rule sees what it costs. Separately, on the port's black_hold_units ask: four more no-input boots yielded one usable log, which armed late and missed the publisher splash, so the sample is still two runs spanning 3 and 4 frames. Their 6.5-9.2 range stands. And a reason it may not be resolvable this way: the draw log DROPS frame numbers -- in the 3-frame run, frames 121 and 124 are absent entirely, so "frames with no sprite" and "span of frame numbers" are different quantities. Their statistical correction is taken: at n=3 the sample SD (3.893) is the estimator, not the population SD (3.179), making my run 1.88 sigma from the corpus mean rather than 2.31. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01QsEPXWVaEpyfudtR6re1Pd |
||
|
|
acaacc36e0 |
re: the boot splash dwells are declared -- and wall clock is the wrong unit
The port asked for two wall-clock timestamps across the boot splashes. Measured, and the measurement's own result is that timestamps are not the invariant. The dwells are the bundles' own declared timelines: publisher t=0..255 = 4.250 s at 60 units/s, developer t=0..210 = 3.500 s. The corpus's independent screenshot timing over three cold boots gives 4.30/4.60/4.37 and 3.51/3.50/3.37 -- the developer agreeing to 1.1%, two of its three runs to 0.3%. A fresh no-input boot with a frame->wall-clock map puts the same two dwells at 5.10-5.61 s and 3.83-4.30 s, 15-20% longer than both the declared values and the corpus's runs, on the same disc and the same declared timeline. So the wall-clock dwell is an emulator-pacing artefact that varies run to run, and a port authoring seconds is authoring one run's pacing. Boundaries from the draw stream, read per quad: publisher glow frame 1, wordmark 6-119, three frames with NO sprite drawn, developer glows 123, wordmarks 140-209, intro video 216. The 3-frame gap replicates the earlier 4-frame measurement within the +-1 both are quantised to. New tool frame_clock.sh, and its limitation found by its own control: it resolves to one BUFFER FLUSH, not one frame. The capture writes through a C++ ofstream, so tail sees the log in bursts -- 69 of 125 samples showed no advance and the rest jumped 7-15 frames. Naive interpolation inside a burst made the apparent rate swing between 0.0164 and 0.0316 s/frame, which is the flush and not the guest. Frames 119 and 123 fall in one burst, so the inter-splash gap is not separable by this clock at all. Everything is quoted as brackets and the point estimates were withdrawn before being reported. palogo_anima never appears in the log and is NOT reported as undrawn: the developer bundle batches 7 elements into one draw and only the first two quads are logged. That is the trap that produced the eff3 false negative, so it is named rather than claimed. Also records the port's correction: ptcopyright has 105 instants with alpha >= 1 (t=139..243) against 105.89 units of span; I had quoted the rounded span. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01QsEPXWVaEpyfudtR6re1Pd |
||
|
|
78328c5022 |
re: the top-level clock freezes at the settle point -- closing the 114-vs-120 gap
Measured in the title draw capture, re-read with the per-quad parser. GP_TITLE build 4 declares t = 0..269, about 120 presented frames at this run's pacing. The title dwell lasted ~1100. ptcopyright declares alpha >= 1 for 106 units (t=138..244) and is drawn for 1050 frames; ptlogo1 declares an exit at t=264 and is drawn for 1095. Both vanish within three frames of the dwell ending. So the top-level clock advances through the build-in, stops inside the settle window [160,236], and holds. The exit ramp is not played on a timer -- it plays when something makes the screen leave. That is ui-settle-time.md's decode seen from the other side and observed in the running game rather than inferred from the file. A nested record keeps looping on its own clock throughout. This closes the 114-vs-120 gap, and it was my arithmetic rather than a discrepancy in the decode. The 2.231 units/frame was regressed over BUILD-IN events -- the only stretch in which the top-level clock advances -- and applied to a period measured over the settled dwell, where that clock is frozen and only the plate's own record is running. Two different clocks. The declared 120 was never in doubt from the calibration-free dark-fraction test. The 51.158-frame period is now confirmed by a second independent estimator: autocorrelation returns lag 51 with clean harmonics at 102 and 154. Its FIRST version failed its control, returning 48 for a period known to be 51.158, because it indexed by sample position where the log's frame numbers have gaps. Recorded, because the failure is the reason the second version can be trusted. Not settled: the sweeps' period. The same validated estimator disagrees between two dwells of one screen -- 515 vs 452 frames for the same family -- and a 14% disagreement within one screen is not a period. The +0x08 field cannot settle it either, since ptloop01/ptloop02 have zero slack. Blocker recorded in CONTAINER-NOTES: a single A press on the title faults the guest. Three menu-capture attempts, two ending in register dumps of 223 MB and 519 MB, against three no-input runs in the same session that all completed. And a guest fault writes an UNBOUNDED register dump to stdout on a filesystem at 91%, so any scripted button press needs a size guard. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01QsEPXWVaEpyfudtR6re1Pd |
||
|
|
cf91ad1dcc |
re: the forced-backdrop span -- 256 vs 211 is a bundle mismatch, and the hold
decides 55% of verdicts The port implemented the forced-backdrop rule and reported a discrepancy: palogo_eff0.prm at 256 opaque instants against this corpus's 211. There is no discrepancy. palogo_eff0.prm appears on BOTH splashes -- the publisher (entries 10, 13) runs to t=255, giving 256 instants; the developer (11, 14) runs to t=210, giving 211. Same definition, different bundle. The page now names the entries so it cannot recur. The definition, stated: the span is 0..=max keyframe time over every element in the build, and an element HOLDS its final pose past its own last keyframe -- which is what pose_at does, and which is decoded rather than assumed (a group holds at its last keyframe rather than looping; the declared +0x08 never falls short of the last keyframe, the slack being that hold). The port's instinct that the hold was load-bearing was right. Over the 130 keyless full-screen primitives with an opaque interval: * span = the header's declared +0x08 -> 0 verdicts change * span = the primitive's own last keyframe -> 72 change * elements GONE after their last keyframe -> 72 change So the hold decides 55% of verdicts -- and dropping it is REFUTED by a measured order. palogo_eff0.prm is a single keyframe at t=0: without the hold it is opaque for one instant, no other element is up yet, and the rule calls it free, against a game measured painting it first. Pinned by a new test that spells out the counterfactual rather than importing it. The verdicts that matter are convention-independent: pgloading_eff00.prm is FIRST under all four conventions and pteff00.prm FREE under all four. And the header length is interchangeable with the elements' maximum -- zero disagreements disc-wide. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01QsEPXWVaEpyfudtR6re1Pd |
||
|
|
cfcda5501c |
formats: a keyless primitive that would hide the screen is forced to paint first
Partly closes ui-prm-primitives.md's standing blocker, "where an UNMEASURED
primitive paints". Raised by the port: build_12/build_15 composite to solid
black at every instant of their declared life, because pgloading_eff00.prm -- a
full-screen opaque quad -- sorts last.
The rule is a constraint read off the file, not a preference: an element that
covers the screen and is fully opaque at some instant cannot paint above
anything visible at that instant. Where the elements visible during its opaque
span are ALL of them, its position is forced to first.
pgloading_eff00.prm is opaque for 39 instants and all 9 other elements are
visible inside that span -> forced first, 4/4 instances.
Two controls, both measured orders from the running game, and the rule has to
survive both:
* palogo_eff0.prm is measured painting FIRST -- opaque 211 instants, forced
below 6 of 6. It is NAMED like an overlay, so a name-based rule sorts it
wrong against a measured order. Occlusion gets it right.
* pteff00.prm is measured painting LAST -- opaque for 2 instants at its
screen's entry and exit, forced below only 3 of 23, so the constraint
permits it on top where it belongs.
Disc-wide: 80 instances forced first, 50 constrained but not forced, 0
unconstrained. The split runs almost exactly along the names -- every *base* is
forced, every *eff00* is not -- with three families crossing it, which is
exactly why the name is not the rule.
It also explains 36 builds the corpus had recorded as "coming out one colour"
with no cause: pzeff00.prm is forced first in 32 of 32 instances, so they were
wiped by our own sort rather than by the game.
The rule's real limit was found by its own disc-wide test failing. Applied to
any element it claimed 22 .t32 SPRITES must sort first against their own layer
keys -- pneff01.t32 (key 0xd850, #8 of 13) and pbfriendly.t32 (0x9230, #17 of
49). A sprite's ELEMENT alpha says nothing about whether its TEXTURE covers the
screen, so forced_backdrop is now restricted to untextured primitives, which is
also the only case derived_paint_order consults it for.
Reach stated: assumes straight alpha-over (blend mode is still open, and an
additive quad at alpha 255 would not occlude); it is a lower bound, not an
ordering; and there is no new oracle measurement -- both controls are prior
ones, and a loading screen is not reachable from the title path.
3 new disc tests; the 13 paint-order tests are green, including
the_derived_order_matches_the_measured_ones_up_to_ties.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01QsEPXWVaEpyfudtR6re1Pd
|
||
|
|
47faeaa7a9 |
re: RETRACT "the game never draws eff3" -- a batched draw merged two quads
The console draws all five title flashes. My claim that ptlogo_back2eff3 is never drawn was an instrument artefact, and I had reported it to the port with three alternative explanations "ruled out". A GPU draw can batch several quads -- indices=4 is one, indices=8 two, indices=24 six -- and the UI draw log dumps only the first 8 vertices. Taking min/max over a line's whole vertex list merges quads into one box. eff3 is batched with eff4, and because the wipe family is right-aligned, eff3 (788..1196) lies ENTIRELY INSIDE eff4 (447..1196). The union is exactly eff4's own extent, so the merged box matched eff4 to 1 px, eff3 vanished, and nothing looked wrong. Parsed per quad, all five fire in both title entries in the declared stagger: eff1 130-131, eff2 133, eff3 133-134, eff4 133-135, eff/eff5 134+, back2 136+; and 5953-5955 / 5955-5957 / 5957-5958 / 5957-5959 / 5958+ / 5962+ in entry 2. Frames 133 and 134 are t=60.1 and 62.3, inside eff3's declared t in (58,64). Also retracts "the developer splash is one composited quad" -- the same bug, which the port refuted by arithmetic first (a 259-tall box cannot contain three logos spanning y 164..585). It draws three logos and three glows as separate quads in one indices=24 call; the 525x259 was gamearts_eff merged with seta_eff. The 9-unit black hold is unaffected: those glows are the developer splash's first draw. The three "ruled out" explanations were all aimed at the wrong failure. In particular the invisible-draw check counted draws with NO geometry line, when the hiding place was draws with PARTIAL geometry. Refuting three wrong hypotheses is not evidence for a fourth, and a list of failure modes written by whoever built the instrument is the least likely to contain its blind spot. Recorded in METHOD.md, along with the tell that was present and explained away: a merged box carries the first quad's colour, which made one element's alpha read 255/127/254 on consecutive frames. New tool: tools/re-capture/quads_per_frame.py parses vertices in groups of four and warns when the logged quad count falls short of indices/4. Also guards a double-A-tap in ui_draw_capture.sh: the movie branch ignored that TARGET=menu had already tapped, so a run tapped A on the title at t=23s and again at t=27s on the transition; the guest faulted and Xenia dumped registers to stdout until the file reached 519 MB. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01QsEPXWVaEpyfudtR6re1Pd |
||
|
|
1a2f4fdc2d |
re: the boot splash black gap is ~9 units, measured in draws not luminance
The port found its boot had no black frame between the publisher and developer splashes and authored 12 units by analogy with the menus' transition quad. On the boot path that analogy has nothing behind it -- palogo_eff0.prm is a single static keyframe, so the splash bundles declare no fade quad. I had agreed with the dismissal that hid the defect: told the residual was 0.03 s against a bound built from two measured ranges plus jitter slack, I said it said more about the bound than the game. The real gap was 0.2 s. Measured in the draw stream, which separates true black from a fade tail where luminance cannot: palogo_sqex is drawn to frame 125 at alpha 7, frames 126-129 submit NO sprite quad at all, and the developer fades in at frame 130 from alpha 34. Four presented frames, the only such run in the sequence. Converted with the disc as its own clock rather than a frame rate -- this run presented at 13.1 fps against 28 elsewhere -- palogo_sqex declares alpha >= 1 for 239.8 units and is drawn in 105 frames, giving 2.284 units per presented frame, which the title capture independently corroborates at 2.231. So the gap is ~9.1 units (0.152 s), against the 12 authored; +-1 frame is 6.9-11.4. And the true black is SHORTER, since both boundary frames still carry picture. Second finding: the developer splash is ONE composited 525x259 quad at the bounding box of its three declared logos, none of whose individual sizes is ever submitted. That is why an earlier pass reported "developer splash: 0 frames". Declaration sites ruled out: the splash bundles (no fade quad) and the top-level +0x08 (a family constant, 300/60, slack 12-226 units). The executable is NOT looked at and is named as the next place rather than claimed. Also answers the port's sweep question: +0x08 canNOT settle it, because ptloop01/ptloop02 have zero slack and a zero-slack record cannot distinguish "loops" from "runs once and stops". The oracle settles it for the TITLE -- the sweep oscillates over its whole range and resets hard to the same start, once in dwell 1 and twice in dwell 2, so it does not park. The MENU is unmeasured and stays open. Tooling: GRACE and NOTAP knobs for ui_draw_capture.sh. The script taps A on "the screen changed a lot", which is also true of a fading splash -- a first run tapped through the publisher and the developer never appeared. The instrument was perturbing what it measured. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01QsEPXWVaEpyfudtR6re1Pd |
||
|
|
69bc4cd1cd |
re: the game never draws ptlogo_back2eff3 -- reproduced, with three explanations
ruled out
Last iteration I recorded eff3's absence as unexplained after withdrawing a bad
explanation for it. The previous capture survived on disk with 6907 frames, and
the attract loop returns to the title, so it contains a SECOND build-in at
frames 5942..7025. eff3 is absent there too.
Three alternative explanations tested and failed:
* sampling phase -- eff3 is non-zero for t in (58,64), SIX units, against a
2.23-unit step. A window wider than the step cannot be missed; frames 133
(t=60.1) and 134 (t=62.3) sit inside it and draw eff2 and eff4 instead.
* a draw the log cannot see -- exactly 2 draws per frame carry no geometry,
on all 932 settled title frames, always the same full-screen-triangle
shader, and present on frames where no wipe element is active.
* a bad position guess -- dropping position entirely, ZERO quads anywhere on
screen in either build-in window have a width within +-30 of 408. The width
spectrum jumps straight from 262 to 748.
Draw counts across both entries: eff1 4, eff2 3, eff3 0, eff4 6, against ~5
expected each. The four are a right-aligned wipe (938+258, 788+408, 447+749,
64+1133, all ending at x~1196) -- a left-growing reveal in four widths, of
which the game draws three.
Why is NOT established: nothing in eff3's element record differs from its
neighbours. Classified measured, not decoded, and the port is told that
dropping eff3 means authoring a behaviour I cannot derive from the file.
Two further corrections, both to my own earlier claims:
* "frame 107 is the title composited once" was an over-read. It binds NO
texture and only 4 of its 27 draws log geometry. The second title entry
has no such frame.
* the two build-ins are NOT frame-identical. I had that from a coincidentally
aligned pair of rows; aligned properly only 4 of 46 frames match. They are
the same animation at different sampling phases -- which is precisely what
makes the eff3 result robust.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01QsEPXWVaEpyfudtR6re1Pd
|
||
|
|
311bd16ad8 |
re: withdraw the eff3 explanation and the flash advice; add a calibration-free
test that refutes 105 Two claims shipped this morning are withdrawn, and the port had already acted on one of them. WITHDRAWN 1: "eff3 was never drawn because a 2-unit flash peak is sub-frame." eff3's alpha is non-zero for t in (58,64), and the capture's frames 133 and 134 sit at t = 60.0 and 62.2 -- squarely inside that window, with eff2 and eff4 both drawn in the same frames. It should have been submitted and was not. The absence is real and UNEXPLAINED; it is not sampling phase. WITHDRAWN 2: "a port drawing all five flashes shows more sweep than the console". No evidence behind it. The port checked against its own renderer and found it draws them sequentially at their declared times, never more than two at once -- which is exactly what frames 131-135 show the game doing. The pile-up worth warning about was the rest() bug, now fixed. Kept, at the port's request: a frame-by-frame comparison of the build-in WILL disagree about which flash lands in which frame -- 2 units per submitted frame against this run's 2.231 units per presented frame -- and neither side is wrong. Without that stated, the discrepancy reads as a port defect. Added, and stronger than the argument it replaces: a calibration-free test of 105 vs 120. The glow's draw is omitted when its alpha reaches zero, and the smallest alpha actually submitted across 807 drawn frames is 1, so the culling threshold is read off the data rather than assumed. Measured dark fraction 17.7% (173 of 980 settled frames); a 120-unit cycle with its declared 15-unit hold predicts 14.4%; a 105-unit cycle predicts 2.2%. 105 is out by 8x and would need a threshold of alpha 11 out of a peak of 80, while the capture contains submitted draws at alpha 1..12. No frame rate, no pacing factor, no wall clock. Also recorded: a regression of five build-in events against their declared times (residuals <=0.9 frames) recovers t=0 at frame 106.1 when the composite spike, not in the fit, is frame 107 -- and that same slope makes the glow's period imply a 114-unit cycle against a declared 120, which is unexplained. And the vertex-alpha identity holds for the glow but does NOT generalise: eff4 reads 255/127/254 on consecutive frames. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01QsEPXWVaEpyfudtR6re1Pd |
||
|
|
d98c8214cc |
re: the title's build-in measured in the guest's draw stream -- the flashes are real
The settle-time decode was confirmed only against a SETTLED frame, which shows the end state is right and says nothing about whether the five flashes ever happen. This runs the oracle: a draw capture armed before the title exists, so the window contains the frames in which the screen is built. The flashes fire in a six-frame window and are absent from all 155 other sampled frames. `ptlogo_back2eff1` is drawn in exactly two frames at t = 54.0 against a decoded peak of t54-56; `ptlogo1` first appears at t = 42.2 against a decoded t42. Units-per-frame was taken from the GLOW's period alone, a different element, so the timings are not circular. The two holders are continuous from frame 134. The plate glow's quad carries a per-vertex colour whose alpha IS the element's fade alpha, so the ramp is read straight out of the guest: observed range 0..80 against a decoded peak of 80, exact and unfitted; period 51.158 presented frames over 20 cycle starts. Fitting the decoded ramp gives RMS 13.16 alpha levels against 38.18 for the same ramp REVERSED -- if the shape carried no information those would be equal, so the asymmetry is real and correctly directed. Further controls: symmetric triangle 15.73, flat 31.13. `ptlogo_back2eff3` was never drawn, and that is expected rather than a miss: a 2-unit flash peak is 0.85 of a presented frame, so catching one is a matter of phase. A port drawing all five every time shows more sweep than the console. METHOD.md gains the trap this cost: a 2D draw's identity is its vertex geometry, not its bound texture. These sprites sample shared pages, and matching texture dimensions produced a false negative (no flash is ever drawn) and a false positive (the intro movie's 640x360 YUV planes read as `ptbase2`) in the same pass. Also records the top-level restriction on the settle window, which the port raised and which is verified here: top-level [160,236] width 76, including the `ptloop` leaves [269,540] width 271 -- an instant past the end of every top-level element's timeline. Evidence committed as a derived per-frame series, not the 7 MB raw log. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01QsEPXWVaEpyfudtR6re1Pd |
||
|
|
4c74e579a0 |
re: 210 focus records pulse, not 2 -- and 8 of them fail in a way that looks right
The port censused focus-record alpha over its own export -- 34 elements, 2 varying, both `ptbtn00f` -- and concluded there is nothing to fix. That is correct and correctly scoped. This asks the same question of the whole disc. 1 130 focus records, 2 664 timed elements, 210 with a varying alpha. 202 have `rest()` returning the PEAK, the `ui-settle-time` pathology. By pak: PILOTLOG 116, MOVIE_THEATER 54, HANGAR_ARSENAL 30, LEADERBOARD 8, GP_TITLE 2. So the port's 2 is right because GP_TITLE has 2. The scope was load-bearing and was not stated as a limit -- "only 2 have a varying alpha" reads as a fact about the format and is a fact about one pak. The pathology is concentrated in exactly the screens a wider port reaches next. The 8 LEADERBOARD ones are the worse mode. `py_ranking_btn01f` swings 255->127->255 with no two adjacent keyframes equal, so `rest()` falls through to its longest-dwell rule and returns 244 -- neither the peak nor the trough. A glow stuck at its peak is visibly wrong; one stuck at 244 of a 127..255 range looks entirely plausible and nothing reports it. Verified rather than asserted: two hits dumped keyframe by keyframe, and a control on `ptbtn01f`, which is genuinely constant across its cycle and is correctly NOT flagged. `py_ranking_btn01f` also confirms the loop-length decode independently -- its ramp ends at t=90 inside a declared 120-unit cycle, holding bright for 30 units. Reach stated: 210 is a floor. Focus records are matched by the `Xf.rat` name rule, and elements with constant alpha but varying scale, rotation or position have the same problem and are not counted. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01QsEPXWVaEpyfudtR6re1Pd |
||
|
|
d4a08ad194 |
re: a nested record's +0x08 is its loop length -- the plate's period is 120, not 105
Answers the question the port agent asked: does the `PRESS A` plate's pulse group loop from its start, or hold at alpha 0 between cycles? It holds. A nested record is itself a RATC bundle with its own header, and that header's `+0x08` is the loop length -- the same field ui_header_time_disc already tests as an animation length at the top level. Its keyframes need not fill it, and the slack is a hold at the final pose. `ptbtn00f` is 105 units of ramp inside a 120-unit cycle, so the glow rests dark for 15 units between pulses. The five main-menu focus records fill their 120 exactly, which is what shows the slack belongs to this record rather than to the format. Disc-wide over 1 781 timed nested records: 92.3% declare exactly their last keyframe time, 7.7% declare more, and 0 declare less. That last row is the falsifier -- a cycle cannot restart before its own last pose -- and it never fires; the 7.7% is what keeps the reading from being an unfalsifiable relabelling of the keyframes. Falsification against the running game, using a pacing factor measured INDEPENDENTLY on the main menu's focus ring (declared 120 units, measured 2.177 s, factor 1.0885): to reach the corpus's four measurements of the plate pulse (2.12/2.19/2.34/2.31 s), a 105-unit period needs a factor of 1.211-1.337, which EXCLUDES the ring's; a 120-unit period needs 1.060-1.170, which CONTAINS it. Predicted 2.177 s against a measured 2.12-2.34. The two elements are in different bundles and were measured in separate runs; the only thing tying them together is that both declare 120. So the port should stop shipping 105. Its 123-vs-129 ambiguity straddled the right answer without containing it, and 129 only fitted because it was 105 + the exit_ramp_units constant it has since correctly deleted. Reach is stated: this says where a cycle ends, not which records cycle, and the TOP-level +0x08 is a different field left untouched -- every GP_TITLE entry declares 300 while its elements end at 244-269. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01QsEPXWVaEpyfudtR6re1Pd |
||
|
|
7b5a4aa041 |
re: the paint-order tie-break costs one pixel, on one screen we do not ship
Closes the open half of Q3. `ui-paint-order-derived-check.md` bounded WHERE a wrong tie-break could show -- overlapping same-key pairs -- and said outright that nobody had measured how many change a pixel. At the instant the player sees, the answer is: at most 1 px at max channel difference 1, on the JAPANESE title only (`ptlogo2` x `ptlogo_tm`, 5 px of shared ink). Exactly 0 px on all five port screens. The earlier 24-pair bound was counted at `rest()`, and 10 of the title's 11 overlapping tied pairs are between `ptlogo_back2eff1`..`eff5` -- the five transient flashes from the settle-time finding, transparent on the settled screen. A tie between two invisible elements cannot cost a pixel. Not a knife-edge. Sweeping every keyframe time and every midpoint between keyframe times, the live-pair count is flat across the ENTIRE settle window: 1 on the EN title, 2 on the JP title, 0 on all four loading bundles -- whose tie is live only at t17..t33, during the build-in, which matters because their settle windows are narrow enough to deserve little trust otherwise. Controls: every entry reporting zero also swaps an overlapping DIFFERENT-key pair, which must and does move pixels (25 310 / 268 698 / ~765 000 px). Zeros are explained by shared-ink counts rather than asserted -- the `ptframe` pairs overlap by bounding box and share 0 px of ink. Entries 0/1/12/15 have NO live control and their zeros rest on keyframe data rather than a render; recorded as the weaker claim it is. Refutation attempt on the corpus's "24 overlapping pairs": it SURVIVES as a rest-pose count -- an independent recount reproduces entry 7's 16 exactly. What is overturned is its interpretation as the risk surface. `tie_break_pixel_cost` gains a settle-time case and an alpha/scale filter on its rect test; `tie_cost_over_time` is new. Also strips 611 bytes of captured cargo warnings from the head of the committed tie census. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01QsEPXWVaEpyfudtR6re1Pd |
||
|
|
38b80302b7 |
re: the title's light arc is five transient flashes, not a tone or rotation error
Records the settle-time decode, and corrects two claims it overturns.
docs/re/structures/ui-settle-time.md is the finding: a settled screen is one
instant every element is posed at, the disc names it (the midpoint of the
longest keyframe-free interval), and the title's arc closes from 33.22 to
11.79 with the clipped-pixel count landing on the console's 1459 within 0.5%.
Includes the disc-wide reach -- only 30% of bundles have a window wide enough
to trust -- and a three-way figure.
Withdrawn in ui-rotation-implemented.md:
* "Flat. No minimum." was not a property of rotation. `at` posed LEAVES ONLY,
so the scan moved the light sweeps and never touched the top-level flashes.
* "our renderer does not draw ptlogo1/ptlogo2 at all" is wrong. Both are
drawn; the four elements the diagnostic named are kind-0x4 ghosts sharing
their template's name. Hiding the real ones makes the error WORSE by
+5.20 and +7.47.
* Its 10.92 baseline is not reproducible -- 14.07 at its own pre-change tag
and 14.07 today -- so the "1.7% better" verdict rests on an unrecorded
recipe. Flagged in title-residual-tone-vs-geometry.md too.
METHOD.md gains two traps: a shared CARGO_TARGET_DIR makes a `git worktree`
build silently replace the binary you run next (it cost three renders here,
caught only because a missing flag was a hard error rather than a wrong
number); and an aggregate computed per-element is not a state of the system.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01QsEPXWVaEpyfudtR6re1Pd
|
||
|
|
d71a74f938 | re: index and cross-references for the record layout and the loading screens | ||
|
|
f24304248c |
re: the plate delay was on the disc all along -- my instruction is refuted
The port caught this with arithmetic off the disc, and it was right: build 2 has a keyframe group of its own, so "when build 4 has settled, wait 2.13 s, then composite build 2" puts the plate at settle + 2.13 + 3.97 s. Confirmed build 2's group here independently of their message: `ptbtn00.t32` reaches a=255 at t=238. The reconciliation needs no free parameter. Both builds run on ONE clock, started together, and the premise that fails is `rest.t`: rest.t is NOT when a screen settles. It is the last HOLD keyframe before the exit. ptlogo1 rests at t=251 and stops moving at t=42. The title's visible build-in ends at t=118, where pteff01, pteff02.prm and ptlogoall_eff end their ramps together. 238 - 118 = 120 units = 2.000 s, against a measured 2.138 and 2.132. So the interval the two runs agreed on to 6 ms was a DECLARED one and I handed over a wall-clock reading of it. That reading is 6.7% long, and the corpus already knew why: 120 units in 2.135 s is the game presenting at 28.06 / 28.14 fps against a nominal 30, and the idle title was independently measured at 28.5 fps before these runs. Corroborated from inside the same two runs -- first pixels -> settle is 1.643 s and 2.131 s, a 30% spread, while settle -> plate is 2.138 and 2.132. Frames are dropped during the build-in, not during the hold, which a change in the game's own timing could not do. So the port authors nothing here. What is unchanged: ScreenView still has to draw two builds at once and the boot's end state is still not plate-free. Not settled, and said so on the page: which reading of the keyframe times is right (it moves the plate by 2 units and I cannot separate them from these traces), and my settle landmark to better than +/-5 units. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_014voBspJ6kFncNErZJuZcLw |
||
|
|
f34d24941d |
formats: a music bank's third sub-wave was its own header
The port hit `sound_bank_riffs("BGM_103.slb")` returning three against a census
that says two, and refused to guess which to drop. It was our reader.
`to_xma_riffs`'s hybrid branch derives a leading packet stream's start as
`first_riff % XMA1_PACKET`. That is right only when the bank header is smaller
than one 2048-byte packet -- true of the voice banks the branch was written for
(1392/1468/1600/1728), false of a music bank, whose header is exactly five
packets. The modulus returned 0 and the whole 10 240-byte header was emitted as
sub-wave 0.
The header states its own length, so the guard needs no threshold: BE u32 0x800
at +0x18 with the bank id repeated at +0x00 and +0x20, header length in blocks at
+0x24. Disc-wide over sound.pak's 9 519 entries, 28 match at offset 0 -- every
music bank, ids 1001-1023 and 1101-1105 -- and on 28/28 the declared header ends
EXACTLY at the first RIFF. Zero have a gap, so a header and a leading packet
stream never coexist here; zero false positives among the other 9 491.
Controlled rather than argued: decoding the emitted region through the same
chain, on the same bank, in the same run gives 0.009 s of PCM where the bank's
real wave 0 gives 87.744 s against a declared 87.75. The region is also 99.1%
zero bytes. And the oracle had already said two -- the XMA probe at the main menu
saw exactly two streams, at BGM_103's two declared wave sizes.
BGM_106-109 are deliberately NOT in the 28: their entries start mid-bank, so they
have no header at offset 0 and their leading region is real audio. The
VOICE_D_453 recovery is untouched and its tests still pass, 10/10 green.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_014voBspJ6kFncNErZJuZcLw
|
||
|
|
5fcc89be55 |
re: the PRESS-A plate arrives 2.13 s after the title settles, measured twice
The one number the port said decides a structural question on its side: whether
`ScreenView` has to draw two builds at once. It does. The boot title shows
build 4 alone, and 2.13 s after build 4 stops animating it composites build 2
over it. Two independent boots agree to 6 ms (2.138 / 2.132), which is under one
sample interval.
Measure from SETTLED, not from first pixels. "First drawn -> plate" is 3.78 s in
one run and 4.26 s in the other, because the build-in animation itself ran 1.64 s
and 2.13 s -- that spread is the emulator's frame pacing, and it is exactly the
kind of number that looks like a measurement.
Ruled out before believing it: that the plate was pulsing all along, too dim for
a thresholded glyph counter. The counter reads EXACTLY 154 -- the committed
no-plate title's own value -- for every frame of a plateau nearly one full pulse
period long, with zero variation, and the surface mean is flat to +/-0.03 across
it. A cycling overlay moves both.
Also settled, and also not:
* the black hold between two screens is 0.14-0.30 s, which brackets the port's
authored 0.17-0.23 s and the file's declared 12 units. Their constant stands.
* the (A)->menu latency is STILL not available, and now the reason is known.
Both runs freeze one frame for ~1.4 s at surface mean 26.626 -- agreeing
between runs to six decimals, and reproduced in run 2 with stream restarts
disabled, so it is not the capture path. It is a guest load stall: the (B)
path, which loads nothing, has no freeze at all. Any figure from it would be
an emulator load time.
Refutation attempt, recorded whether or not it survived: navigation.md's "the
title is not input-ready for about ten seconds, and even then (A) registers
roughly half the time". At 7.29 s and 7.28 s after the title settled, (A) was
accepted first press in both runs, as was (B) on the menu. n=2 only makes "half
the time" unlikely (p ~ 0.25); it contradicts the ten seconds outright.
And the standing red banner is withdrawn: the interactive title IS reachable in
this container, twice, with no pad input, in ~3.5 minutes. Why it changed is NOT
established -- this container came up with no Xenia storage root at all, so run 1
created a profile -- and that is written as a correlation for the next session to
test rather than as a cause.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_014voBspJ6kFncNErZJuZcLw
|
||
|
|
7a4a74f8d7 |
re: the main menu has no idle self-return -- and four of my own durations were a backlog
Two results and one retraction, all from the same session. REFUTED: 'an ~8-10 s idle returns to the title' does not apply to the main menu. Held untouched it stayed put for >= 60 s, correlation never leaving 0.9245-0.9249. That timer is real but belongs to the TITLE. It was the only reason 'B leaves the main menu' was classed as authored, so Q5's B rule is upgraded to measured-ordering: B is delivered (canary logs vk=5801) and is the only input in >= 100 s before the return. The PRESS (A) plate: the boot title presents build 4 WITHOUT the plate first -- green-glyph 154, against 159 on the committed no-plate capture and 753/977/1493 on plate titles -- and the plate arrives after. That is the port's third option. RETRACTED: four durations taken the same day. classify_array costs 1503 ms per frame; running it per frame against an 8 fps x11grab drained the pipe at 0.64 fps, so every classified frame was stale and increasingly so. It manufactured 'plate 24.66 s after the title art', 'B->title 15.58 s', 'B->title 25.60 s' and 'A->menu 20.26 s'. The tell: a transition, a press and a fade do not share a duration, and the two B figures GREW across a longer run. A backlog preserves ordering and destroys durations, which is why the sequence results above stand and every timing does not. The ring's period is unaffected and that was checked, not assumed -- ring_period ran at 15.03 fps against a requested 15. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01KNR5Y79D1T4bBr6gJQaWFP |
||
|
|
3db09a3806 |
re: the decoder container has no disc -- root-caused to the volume migration
find / -xdev turns up no ISO, no default.xex and no GP_TITLE.pak; /exchange is empty; SYLPHEED_DISC is unset; sylph-doctor agrees. Everything else in the container is healthy -- xenia_canary is built, :98 is up, screenshot works, Vulkan enumerates. There is simply no game to boot. The cause is in the launcher. Before |
||
|
|
1a82ade187 |
re(ui): the 60 nameless RATC children are frames, not children -- .tan decoded
Closes the reach caveat the `opt ` name fix left behind: 60 of 18 002 RATC children carry no `opt ` block, and it was not established whether they lack one or sit past our 128-byte window. Neither. They are not children. `examples/ratc_optless_children.rs` re-runs `ratc::parse`'s own guards over the disc and reports which one fired: all 60 are "tag beyond the window", none is rejected by length, gap or charset, none is child #0, and all 60 live in six bundles of one archive. Within a bundle the distances back to the nearest tag are an exact arithmetic progression, step 60 600 -- ten different records finding the SAME tag, because there is only one. Reading a bundle directly: children 1..10 are equal-size T8aD blocks under a single `opt ` name, `pb_f15_eg_anm.tan`. `.tan` is a FRAME SEQUENCE. One block declares the resource; its payload is a run of T8aD frames. Disc-wide, over all 18 718 `opt ` names in all 33 paks: a RATC bundle names exactly six kinds of resource -- `.t32` 14 756, `.rat` 3 311, `.prm` 367, `.tbm` 224, `.sbo` 54, `.tan` 6. Six `.tan`, ten frames each = 60, the entire population with nothing left over. The negative is closed, not narrowed. Consequence recorded but deliberately not fixed: `ratc::parse` over-reports there, listing a `.tan`'s frames as anonymous children. Nothing in the menu milestone reads a `.tan` -- it occurs only in GP_READY_ROOM, which S1 ruled out -- so no screen the port draws changes. Also a METHOD entry for this container OOM-killing `slb_leading_segment_disc` under default test parallelism (SIGKILL, no assertion; 8/8 pass with --test-threads=1). |
||
|
|
0ed33bcd38 |
re(ui): a RATC child's name is stated, not inferred -- and it was hiding every menu background
`ratc::parse` named each child by scanning backwards for the last printable run of bytes before its magic. The format states the name explicitly instead, in an `opt ` block: `"opt " | BE32 len | name | NUL | 3 bytes | magic` -- the same block `ui_layout::opt_link` already read for a button's focus link. The scan agrees with it 17 918 times out of 17 942 and is wrong 24 times, every one the same failure: the 3 trailing payload bytes are themselves printable and beat the real name. For `pteff05.t32` those bytes are `38 41 58` = `8AX`, so the full-resolution background of all five menu screens registered under a name no element declares, resolved to no sprite, and `compose` dropped it through an early `continue` that -- unlike the two arms above it -- records nothing. The screen lost its background and `screen render` still reported "all resolved". `8AX` was never a name. Docs that treated it as one are corrected here. Disc-wide, and the control is the 17 918 the scan already got right: the `opt ` reading reproduces every one of them. Effect on the five screens is the signature of the same art at twice the resolution -- mean brightness unmoved, high-frequency detail x1.15..x1.30 -- which is what the separately-measured `ui-8ax-fullres-background` result said the game draws. Also closes a long-standing dangling reference: `pmbase.t32`, recorded as "on the disc nowhere", is the `GP_STAGE_CLEAR` child the scan called `8AX`. RATC sibling references now resolve 10 148 of 10 148. Verified: 114/114 sylpheed-formats unit tests (including two new ones pinning the `8AX` case byte for byte and the no-block fallback), and every disc-gated integration suite in sylpheed-formats/sylpheed-cli. |
||
|
|
969947e0e6 |
re(ui): put a number on the render-vs-capture tone difference
Closes an observation I left dangling last iteration ("the capture is ~4x
darker than the render") and puts a figure on the ❔ INDEX's texture row
already carried: exact gamma/sRGB fidelity untested because a hue
comparison cannot see it.
Geometry first: cross-correlating the main-menu capture against our
render over +/-6 px puts the best alignment at exactly dy=0 dx=0,
correlation 0.9466. Only the tone differs.
Two methods failed before one worked, and both failures are recorded.
Three dark patches gave "4x darker" -- the whole-frame best linear scale
is 0.914, so three patches from one region are not a transfer curve. A
pixel-wise fit over 854,685 pixels then produced a NON-MONOTONIC transfer
(render 96-127 mapping brighter than render 128-159) with mean abs error
10-14 for every candidate model. That is edge misalignment, not a tone
curve: at correlation 0.947 a bright pixel routinely lands on a dark one.
Flat patches fix it -- 16x16 blocks with std < 8 in BOTH images, a
threshold chosen from the counts (0/83/404/1055/1788 at std<3/5/8/12/20):
main menu 404 patches gamma 1.491 err 0.28 (best linear 0.276, 0.34)
EXTRAS 382 patches gamma 1.493 err 0.22 (best linear 0.273, 0.28)
title 506 patches gamma 1.338 err 1.08 (best linear 0.842, 9.02)
Reach, stated because it is narrow: those patches span only render values
~0-60, where gamma and a plain scale are nearly indistinguishable -- the
two menus decide nothing (0.28 vs 0.34, 0.22 vs 0.28) and only the title
separates them. Nothing constrains midtones or highlights.
The held-out control FAILED TO DISCRIMINATE and is reported as such: the
splash's 2918 flat patches are pure black (render 0-4), so every model
scores ~0.00. That is a test with no power, not corroboration.
Confound left open: this compares our composite to what canary DISPLAYS,
and canary applies kernel_display_gamma_type = 2 (BT.709). The exponent
may be its output stage. The discriminating run -- set it to 0, recapture,
refit -- needs one emulator session reaching the main menu and was not
done.
Classified measured, not decoded; HANDOFF says plainly that a port
applying it is authoring.
|
||
|
|
ffd1a30ba7 |
re(ui): decode keyframe +12 as screen-plane rotation in degrees
The rotated quads on the title screen come from the keyframe block after all. The earlier negative -- "every GP_TITLE build 4 element has all three angle words at zero" -- read the right bytes over too small a region: it walked the top-level declaration table, and the rotated elements are the nested leaf records ptloop01.rat / ptloop02.rat. Confirmed against the framebuffer rather than against our own renderer. The two records declare +12 = 30 and -45; the GPU capture submits their quads at +30.26 and -45.28 degrees -- magnitude and sign, two different values. Corroborated by shape in GP_BUNK 117ca14f, where +12 ramps 0 -> 360 with position, scale and alpha constant: a spin in place. Identifying which draw it was needed edge lengths, not bounding boxes: 400x1076 and 400x1444 against pteff03/pteff03a 399x180 at the elements' two different declared scales, 600% (1080) and 800% (1440). The same test names three known-positives in the capture (ptlogo1, ptcopyright, ptbtn00), so it passes its own control. Keyframe gains rotation_deg plus unknown_4/unknown_8, carried rather than dropped. NOT rendered -- ui_layout::blit is axis-aligned only, so the reference renderer and the port will both draw these upright until a rotating blit exists. The census tool ships with the trap that broke its first version: nested RATC blobs are not 4-byte aligned, so an aligned scan found 0/3 of its own control blocks and missed 16 341 blocks. Disc-wide +12 is non-zero in 14.50 % of 83 862 blocks. sylpheed-formats tests, SYLPHEED_DISC set: 131 passed, 0 failed across the 6 suites finished at commit time; the run had not yet completed. |
||
|
|
a4fc129ba3 |
re: what the game actually reads at boot -- config.ini, and which
GameParts exist at all Q6's second half, advanced but not closed, and the negative is the point. config.ini is the disc's ONLY config file -- one find over the whole extract -- and its own Shift-JIS header calls it the "Application / GamePart initial settings table". Its [SYSTEM] section, which that same comment says holds what the game and every game part share, is EMPTY. So the boot order is not in disc-side configuration at all, and that search space is now closed rather than merely unexplored. What the file DOES carry is the language: XC_LANGUAGE_* -> eng/jpn/deu/ fra/esp/ita, defaulting to eng. That is the mechanism behind the EN/JP build pairs in GP_TITLE and the <lang>.pak families -- a question the corpus had described but never traced to its input. Then the registry. Pulling every RegisterToFactory diagnostic string binds 24 of the 29 GamePart ids to a C++ class, and five ids have no registration site: 1, 2, 16, 18, 28. Id 1 is GP_ADVERTISE_DEMO, which agrees with what I measured two iterations ago -- the attract loop is the TITLE replaying ADV.wmv, not a transition into an advertise part. Marked amber, not green: it is an argument from an error message, not from code. Two things fall out for Q4: ids 3 and 4 are the same class (GamePart_SaveLoad, one part with two ids), and the menu buttons' ids now match the executable's own class names rather than a list of table names. Still a name match, one level closer to the code. What is still missing is the transitions themselves, and I say so: the manifest gives the boot-side assets, config.ini the language, the registry which parts exist. What decides to advance is in GamePart_Title's code and that dig has not been started. |
||
|
|
c5fb6682c7 |
re: the menu's sound events are named on the disc; the binding to them is
not Q8. The cheapest thing nobody had tried was to look at the SE cue names, and they are semantic: SE_UI_CURSOR (2), SE_UI_DECIDE (3), SE_UI_CANSEL (4), SE_UI_IMPOSI (5, the error buzz), SE_UI_SUB_WIN_OPN/CLS, and SE_UI_SPLASH_IN/OUT. That is exactly the move/confirm/back/error vocabulary the question asks for, named by the authors after the EVENT rather than the sound. 322 SE cues committed as reference data. They all live in one bank: BANK_SE is a single field reading Static.slb, and the disc-wide check agrees -- 0 of the 322 has an entry in FILES, the 5135-path list that names every voice, briefing and BGM bank. I am calling the binding a NAME MATCH, not a measurement, and the page says so in the same breath as it gives the table. It is a stronger name match than Q4's GamePart ids -- these are the authors' own event names -- but nobody has watched the game emit cue 2 on a d-pad press, and this container is muted against a dummy device so there is no audio path to watch either. One new negative, with its reach. Static.slb's 8 353 472 readable bytes contain zero RIFF, zero seek and zero WAVE, scanned over the whole buffer. The boundary marker that works for all 7 620 other banks is absent, so the cue is named, the bank is named, and the wave inside it is not locatable. The UI sound effects cannot be exported yet, and that is a gap in the assets rather than in the naming. The named next step is Pj_Silph.xgs -- the XACT project SETTINGS points at, which IS in sound.pak at TOC 9454, though its 533 bytes carry no XGSF magic and its region's phase says they are probably the previous bank's tail. |
||
|
|
d69272e53f |
re: the boot intro and the attract loop are the same video, and the
new-game intro has a name Q9, answered twice over -- once from the disc and once from frames I had already captured and not used. The movie manifest's first eight slots are the whole boot-side flow, and the slot key is the role: LOGO1-4 -> logo1-4.wmv (not on the disc, which is why the splash is a screen), ADVERTISE_MOVIE -> ADV.wmv, STAFF_ROLL -> the credits reel, MS00A -> S00A.wmv, MS01A -> S01A.wmv. So the new-game intro is S00A.wmv, decoded -- which is the half I could not test at runtime, because A on NEW GAME hangs the emulator. And there is no separate boot-intro slot: ADV.wmv IS the advertise movie, the boot just plays it first. Confirmed independently by matching 19 attract frames against five candidates -- 15 hit ADV with a playhead that advances monotonically at the sampling rate and ends at 137 s, its full length, with the title back on the next sample. So the attract movie plays to its end; nothing cuts it short. That corrects me. Two iterations ago I recorded the attract movie as "~85 s, so probably not ADV.wmv" -- arithmetic on a start I never observed, since sampling began 39 s in. REFUTED and METHOD both take it, along with the matcher's real failure mode: a near-black frame has no signature, and its runner-up is not evidence. Skippability I did NOT settle, and the corpus contradicts itself: one page says A skips a movie every time, while the boot harness deliberately never taps during one because it breaks the title. Named the one-boot test rather than picking a side. |
||
|
|
4820865835 |
re: S1 -- the Ready Room probe is a no-go, and not for the reason the
question expected One iteration, as the mission gates it, and no Ready Room work started. The two criteria it named both pass. It is NOT 3D: the corpus already holds a capture of the running screen and it is a flat six-item menu in the same visual language as the title. And unrecoverable paths do not mean unrenderable screens -- content enumeration finds 60 builds in the 1106 entries. What kills it is something the question did not ask. GP_READY_ROOM.pak does not appear to hold the Ready Room's own menu at all. Two signals agree: the four largest builds composite to briefing panels -- a planet readout, unit markers, direction arrows -- and, much harder, the 902 bundles declare 317 distinct element names of which NONE matches any of the six labels on the screen (takeoff, brief, hangar, pilot, option, mission, ready all return nothing). The pak is the briefing / tactical-map content behind the BRIEFINGS item. If this is ever picked up, the first job is finding where the menu lives -- GP_BUNK.pak is the obvious place -- not naming this pak's keys. The probe also reaches back into something already delivered: kind == 0x3002 finds ZERO buttons across all 902 bundles here, while GP_TITLE has 16. 0x3002 is one member of a 0x3000 family with sub-bits, and this pak uses 0x3000/0x3004/0x300c/0x3008. Nothing in the milestone changes -- every screen in scope is GP_TITLE -- but the handoff now says not to ship that equality as a general button test. |
||
|
|
c848668b1f |
re: a music bank is two stems that play together -- not intro+loop, and
not something to concatenate Q10, and it starts by withdrawing the question's own premise. BGM_001 is not three sub-waves of 10 KB / 4.47 MB / 4.67 MB: the 10 KB is the bank header. A bank is exactly TWO waves, and across all 32 BGM banks on the disc the two always have the SAME duration -- equal to 0.01 s over lengths from 37 s to 277 s. That alone kills intro+loop and kills two halves of one piece, both of which require unequal lengths. Four banks appear to break the rule and do not: BGM_106-109 are the known leading-region straddle, and the giveaway is that the entry named BGM_107.slb contains BANK id=1108. The seek packet counts pin each join exactly, so they realign to the same two-equal-waves shape rather than being dropped as noise. That trap goes in METHOD. Then the roles, by decoding both waves to PCM. They are sample-synchronous: transient-envelope correlation searched over +/-5 s peaks at lag +0.00 s, and both waves stop at the same millisecond, 167.663 s. Two stems of one performance, meant to sound at once. Wave 1 is quieter, has almost no bass and is far more L/R-decorrelated, which reads as a surround-rear pair or a second intensity layer -- I cannot separate those two from the file, and say so: ChannelMask is 0x0002 on both, and this game's channel metadata is already documented as meaningless. Two things the port needs that are NOT on the disc, both marked as authored: the track is not a seamless loop (BGM_001 fades out and is followed by 6.15 s of silence, no loop-point field found), and nothing names which bank the menu plays -- all 32 BGM cues are numeric. |