Commit Graph

70 Commits

Author SHA1 Message Date
Sylpheed RE agent
f160b416ff docs: close the focused-state question against the declaration table, and log a third freeze-free run
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01PMRJjbxLqZtsb5Vb7KunPE
2026-08-24 03:50:58 +00:00
Sylpheed RE agent
68a3fed554 docs: note that catching a freeze is a per-run lottery, and the watcher that waits for it
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01PMRJjbxLqZtsb5Vb7KunPE
2026-08-24 03:14:25 +00:00
Sylpheed RE agent
a58c8665e0 docs: the freeze item has an instrument and a control now
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01PMRJjbxLqZtsb5Vb7KunPE
2026-08-24 02:31:15 +00:00
Sylpheed RE agent
315b7e1561 docs: point the freeze item at the targeted log line rather than the global flag
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01PMRJjbxLqZtsb5Vb7KunPE
2026-08-24 01:49:18 +00:00
Sylpheed RE agent
cd2704c2ac docs: the freeze entry gets a measurement instead of a plan
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01PMRJjbxLqZtsb5Vb7KunPE
2026-08-24 01:13:13 +00:00
Sylpheed RE agent
6b3442ce8c docs: record the bit-level attempts and that run attrition is the real cost now
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01PMRJjbxLqZtsb5Vb7KunPE
2026-08-24 00:20:35 +00:00
Sylpheed RE agent
f6febd1bd6 docs: close the flag hypothesis in the backlog, and name the bit-level follow-on
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01PMRJjbxLqZtsb5Vb7KunPE
2026-08-23 23:21:23 +00:00
Sylpheed RE agent
e65b730af0 docs: the pilot fires - record it, and what it still does not do
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01PMRJjbxLqZtsb5Vb7KunPE
2026-08-23 22:39:46 +00:00
Sylpheed RE agent
dde23cac3c docs: record the dead-pad root cause and what it does not fix
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01PMRJjbxLqZtsb5Vb7KunPE
2026-08-23 22:09:51 +00:00
Sylpheed RE agent
d9cf899667 docs: record the pilot's proximal cause in the backlog
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01PMRJjbxLqZtsb5Vb7KunPE
2026-08-23 21:27:53 +00:00
Sylpheed RE agent
cc865cd9da docs: revise the OB-flag item - the blocker is the pilot's trigger, not the freeze
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01PMRJjbxLqZtsb5Vb7KunPE
2026-08-23 21:05:27 +00:00
Sylpheed RE agent
99be872d1c docs: correct the freeze entry - the lead is dead, the spin is the finding
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01PMRJjbxLqZtsb5Vb7KunPE
2026-08-23 20:03:53 +00:00
Sylpheed RE agent
15d240bffb docs: promote the in-mission freeze - it is now blocking the item behind it
Two more attempts at the OB-flag experiment, both stopped by it: one froze before
the counter could move, the next had the counter at a different address (the
tool refused to run rather than report nonsense) and then froze as well.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01PMRJjbxLqZtsb5Vb7KunPE
2026-08-23 19:36:20 +00:00
Sylpheed RE agent
639bedf68e docs: open the "what does REMAINING OB count" item, with the freeze noted as the blocker in front of it
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01PMRJjbxLqZtsb5Vb7KunPE
2026-08-23 19:10:57 +00:00
Sylpheed RE agent
2a844e6da9 docs: close the objective-counter address item in the backlog
Keeps the refutation next to the confirmation rather than replacing it, and
records the rule a future session actually needs: try 0xbdb59668, check it
against the HUD, re-scan when it reads 0.

What stays open under it is unchanged and is the part that matters for the
autopilot - what the counter counts, and whether an OB-badged entity carries a
flag in its entity object.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01PMRJjbxLqZtsb5Vb7KunPE
2026-08-23 18:39:40 +00:00
Sylpheed RE agent
7146aed1a5 docs: fold the launcher repair and the clean scan into the backlog
The launcher item closes: unattended boot to Stage 02 flight works again, and the
entry now names all three defects that were in the way, including the
wait_flight pixel that was outside the HUD.

The objective-counter item stays open but is sharper: a HUD-clean scan exists,
and the surviving candidate that is hard to dismiss is named with the odds
against it being chance. The blocker is now the pilot's survival, not the method.

Also withdraws yesterday's claim that the "Auto-Save is active. OK?" dialog does
not return - the run that appeared to show that was tapping A every six seconds
while it waited, so it cannot distinguish "absent" from "dismissed unseen".

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01PMRJjbxLqZtsb5Vb7KunPE
2026-08-23 18:04:53 +00:00
Sylpheed RE agent
d412347c37 docs: the REMAINING OB address does not survive a run - refuted twice over
0xbdb59668 reads 0 in two independent Stage 02 runs while the HUD counts
004 -> 008 -> 012. Not an unmapped read: SEEK_DATA at that offset returns the
offset itself and the next hole is 5 MB later, so it is an allocated,
zero-filled word. The address was a per-run artefact, exactly as that file
already suspected it might be; the method is the durable result.

Re-finding it in the new run also failed, and both failures are recorded because
they are the instructive part. Two candidates were produced and both died on the
corpus's own rule -- verify across a transition you did not select on:
0xbc2377dc went 12 -> 18 while the HUD stayed 012 and read 3 two minutes later,
and 0xbd295b04 was plain noise.

One correction to the method note in that file: the scan is not slow. Over the
live /dev/shm image it takes 0.9 s. The real trap is that REMAINING OB climbs
004 -> 012 within about four minutes as waves spawn, so a scan is only valid if
the HUD is confirmed to hold the same value immediately before AND after it --
which is why the earlier 4-then-8 intersection came back empty.

What blocked finishing: with pilot.py retired at hull 340/1500 nothing was
killing objectives and the counter sat at 012 for five minutes, so there was no
later transition to filter on. What the counter counts, and whether an OB-badged
entity carries a flag, is untouched.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01PMRJjbxLqZtsb5Vb7KunPE
2026-08-23 17:16:07 +00:00
Sylpheed RE agent
ef739ea80d docs: correct the empty ship capture - nothing is broken, there was no ship on screen
The previous commit framed the empty capture as "the 3D draws never reach
CaptureShipDrawForRE" and proposed a static comparison to find out why. The
comparison was done and it refutes the framing.

The discriminator for ship geometry is stride=24 prim=4 with a large vcount -
xbg7-mesh.md records a real one as stride=24 vcount=10891 indices=18 prim=4. Not
"positions outside the screen rectangle", which is what I used and is a bad test:
a UI sprite placed at (137,308) passes it.

By the correct test this run's capture has exactly one prim=4 draw, a 6-vertex
full-screen quad, and the 2.9 MB file I was comparing against has NO prim=4 draws
at all. That file is a UI capture: 1303 of its 1582 draws are stride=24 prim=13,
which two other docs in this corpus already identify as the UI sprite shader. The
"1300 3D draws" it appeared to contain were UI sprite coordinates counted by the
bad test.

So the capture recorded exactly what was on screen. The tutorial's opening is an
empty starfield, the player's own ship and a HUD - no capital ship. And
ship-placement-runtime-capture.md has always stated the procedure: play into the
mission, frame the ship side-on, press F10.

What remains is therefore not a code question but a gameplay one: reach a real
mission and frame a capital ship. Worth stating that the original capture was
taken interactively on HW Vulkan, and this container runs lavapipe.
2026-08-19 13:02:48 +00:00
Sylpheed RE agent
9b17506c1f tools+docs: a crash-free mission run, a capture that caught no geometry, and a correction
ship_capture_window.sh polls for the flight screen and presses F10 the moment it
appears rather than after a fixed sleep. One run gave three results.

First, the mission ran with ZERO crashes through t+152s - the first clean mission
run, where the three before it ended at 13243 / 11898 / 11497 - and it renders
and plays: player ship, starfield, full HUD, no dialog.

Second, the capture armed and wrote its file, so the mechanism works in-mission.

Third, and against expectation, the file holds NO ship geometry. 329KB, 181
deduped draws: 180 of them share a single vertex shader, all stride=28 vcount=3
prim=8 at full-screen coordinates, plus one full-screen quad, and not one draw
has positions outside the 1280x720 rectangle. The budget is not the limit -
kShipCaptureBudget is 8000 and only 181 distinct (vbase, WVP) pairs were seen -
and the scene was definitely drawing. The known-good capture from an earlier
session is 2.9 MB.

Fourth, a correction to the previous commit. It said the cache is "REFUTED as the
cure". Too strong: this run used the IDENTICAL complete cache as tut4 and
produced 0 crashes against tut4's 11497. What four runs support is that a
complete cache is not SUFFICIENT to prevent the storm and that run-to-run
variance dominates a 3-run comparison - not that the cache does nothing.

Next step is static: compare this capture's shape against the known-good one to
find why the 3D draws never reach CaptureShipDrawForRE.
2026-08-19 12:56:35 +00:00
Sylpheed RE agent
e85f6ac955 docs: the cache is refuted as the mission-crash cure, and a usable window found
This page's own reproduction - move the cache aside, get a throw; restore it, get
none - made "the cache is incomplete" the obvious explanation for the mission
crash. Three tutorial runs say otherwise.

  tut2  subdir 6 MISSING              641 crashes by t+24s   13243 total
  tut3  missing -> gained 6 in-run      2 crashes to t+80s   11898 total
  tut4  6 present from the start        2 crashes to t+56s   11497 total

The missing entry was real: \aab216c3\6 was requested and absent, and the game
wrote it during tut3 (11 -> 12 files). tut4 then ran with a complete cache and
stormed anyway. Every dump across all three runs is PC 0x82307128, one address,
no others. So the cache may gate the boot-time throw this page documents; it does
not gate the mission one.

What the runs did give is an opening. Both post-cache runs show the same shape -
exactly 2 crashes, then nothing, for 56-80 seconds of rendering, advancing
mission - where the first run was already at 641 by t+24s. That is where the
second capital-ship capture has to happen: F10 armed INSIDE the window. Not a
guarantee, since the storm began at t+24s, ~t+96s and ~t+56s across the three
runs, but two of three offered most of a minute.
2026-08-19 12:37:50 +00:00
Sylpheed RE agent
f9e6209308 docs: withdraw the resume-refused lead - kHighFrequency waits are simply unlogged
The 1663 refused resumes on thread F80001D8 looked like a second lost resume of
the kind fixed earlier today. They are not.

That thread DID execute - the log carries its XThread::Execute line, guest entry
82FFE6C0 - and then 137000 lines of silence. The silence proves nothing:
KeWaitForSingleObject and NtWaitForSingleObjectEx are declared kBlocking,
kHighFrequency, and PrintKernelCall skips every kHighFrequency export unless
--log_high_frequency_kernel_calls=true, which defaults to false. A thread parked
in a wait is invisible in these logs.

So the boring reading is the right one: the guest kicks a worker that is blocked
ON AN OBJECT, and Resume returns false because the thread is not SUSPENDED. That
is what a refused resume means, exactly as suspected before the count made it
look interesting.

Method note kept in the doc, because it is the reason one conclusion survives and
the other does not: the title-loader finding rested on 00:00:00 host CPU time
from ps -L and on the fix changing behaviour 5/5 against 1/5 - not on log
silence. In this codebase log silence alone is never sufficient evidence that a
thread is idle.

Also records a grep error of mine that briefly produced "zero kernel calls,
ever": the pattern ^[dikwF!]> missed the K> kernel prefix. Caught before it was
written down, and it changed the conclusion.
2026-08-19 12:12:40 +00:00
Sylpheed RE agent
402ee1dce4 docs: the mission path is reachable now - it freezes there instead of dying earlier
The backlog has said a second capital-ship capture needs the 0x82307128 crash
dealt with first, because the run died at SELECT DATA before any mission
existed. That is no longer where it stops. With the Canary threading fix making
the menu dependable, tutorial_launch.sh drives boot -> title -> menu -> TUTORIAL
and the mission LOADS AND RENDERS: flight HUD, "Go to the box on your screen",
warship counters, controller diagram.

It then freezes. 13243 crash dumps, every one at PC 0x82307128, guest thread 9,
Access Violation read at 0x10000000C, preceded by exactly ONE
RtlRaiseException(E06D7363) right after a HostPathDevice::ResolvePath() with
empty arguments - the cache-flush shape. Two screenshots 6s apart are identical
(RMSE 0), no new dumps accumulate, and the process still burns 400% CPU.

So: reachable, renders, unusable for a capture. The blocker moved rather than
lifted, which is worth recording precisely because the entry's stated reason is
now wrong.

One new lead, deliberately not claimed as a cause: the resume-refused diagnostic
added with the threading fix fires 1671 times on this path and 1663 of them are
the SAME thread, F80001D8, with 152 before the first crash - against about 7 on
the menu path. Resuming a non-suspended thread legitimately returns false and
"Resume to kick a worker" would produce exactly this, so it is a lead, not a bug.
It is cheap to settle: check whether that thread makes kernel calls between
refusals.

Cheapest next test named: this page already shows a COMPLETE on-disc cache
produces no throw at all, and the cache is 40MB with .partial/.cold-rebuilt
leftovers beside it. One boot to warm, one to re-test.
2026-08-19 12:05:23 +00:00
Sylpheed RE agent
ebc4e08b89 formats: two more measured paint orders, and the first independent confirmation
The three orders the derived rule was built from all live in GP_TITLE.pak, so
they cannot confirm it - the rule was fitted to them. These two are from
GP_SAVE_LOAD.pak, read off the running game now that the Canary threading fix
makes the main menu dependable.

The 9-element slot-list header composites EXACTLY as the sort predicts, on all 6
instances of it, and nothing about this screen was fed into the rule:

    measured  7 8 0 1 2 3 4 5 6
    derived   7 8 0 1 2 3 4 5 6

including TWO tied groups (0xb102 x2 and 0xb210 x5) that both come out in
declaration order, and the unkeyed pfeff00.prm fade quad last.

The 13-element save/load frame differs in exactly the two open questions and no
new ones: two unkeyed pfbase.tbm backgrounds paint FIRST where the sort puts the
keyless last - the splash's palogo_eff0.prm behaviour in a different file type,
so implied_layer_key now covers it - and the 0xb100 group of four paints
10,11,8,12 where declaration order is 8,10,11,12.

That second point is a SECOND screen with a mis-ordered tie, which is what the
question needed, and it immediately kills a candidate: 10 and 11 are kind=0x2002
while 8 and 12 are 0x0000, so "descending kind then declaration index"
reproduces 10,11,8,12 exactly - and then fails both title groups, where every
element of 0x8083 is kind 0 and where 0x80a0 would predict 2,3,4,5,0,1,7 against
a measured 0,2,4,7,1,3,5. Seven candidates refuted now.

16 disc tests green.
2026-08-19 11:46:09 +00:00
Sylpheed RE agent
ae3f37d3ec tools+docs: locate the lost resume, and a title test that is neither too narrow nor too loose
The stalled loader thread is a lost wakeup in Xenia's POSIX threading, fixed on
the canary branch as a60fe7d11 and written up here. A thread created suspended
publishes state_ and suspend_count_ in two separate lock scopes, and Resume()
waits only for state_ before testing suspend_count_ == 0 - so a resumer in the
gap drops the resume and the thread waits forever. The Linux XThread::Resume
discards that false, which is why the guest saw success.

On the first clean boot after the fix the loader thread is the CALLER on 20
kernel-call lines and issues 4 ResolvePath reads. Every failed boot before it had
exactly zero of both.

Stated plainly as not shown: that boots now reach the menu RELIABLY. One post-fix
boot, and it is confounded by the harness.

Which is the second half. skip_intro.sh's title test has now been wrong twice in
opposite directions: originally one absolute pixel (625,618) - a 1280x720
coordinate against the 1279x675 game surface, so it read the copyright line and
timed out with the title on screen - and then my replacement, screen_id.py, which
is too loose and called the SQUARE ENIX publisher logo "title" 151s into a boot,
spending the script's single press there. is_title.py now counts the green (A)
glyph over the whole frame: geometry-independent and specific, measured at 0
pixels on the logo and 1520 on a real title.
2026-08-19 10:41:43 +00:00
Sylpheed RE agent
24c1c940e6 tools+docs: the title's loader thread is created and never runs
Two findings, the second only visible because of the first.

1. The harness has always had kernel logging switched off. log_mask DISABLES
   categories (Kernel=1, Apu=2, Cpu=4, Gpu=8), so the long-standing --log_mask=13
   meant Kernel+Cpu+Gpu off; kernel calls also log at Debug while log_level
   defaults to Info. Seeing one needs BOTH LOG_MASK=12 and LOG_LEVEL=3, and no
   boot log this project has taken ever contained a kernel call. boot_menu.sh now
   takes LOG_MASK / LOG_LEVEL / EXTRA_FLAGS. A whole boot at Debug with Kernel on
   is 23 MB, so the default was costing far more than it saved.

2. With that on, a captured failure shows the (A) handler doing everything right:

     XamUserGetXUID(0, 7, ...)
     NtCreateEvent(...)
     ExCreateThread(..., entry=821748F0, ..., 00000001)
     ExCreateThread Active: Thread Initially Suspended,
     XThreadF80000CC (1F) Stack: 70880000-70900000
     NtResumeThread(F80000CC, ...)

   and the thread then never executing. Measured two independent ways: it makes
   ZERO kernel calls - it appears 13 times in the log and every one is as an
   ARGUMENT, never as the calling thread, while five other threads make 31905
   calls after the resume - and its host thread has 00:00:00 CPU time while the
   process sits at 546% and has burned 37 minutes of CPU in 6:46 wall.

   A spinning thread burns CPU. This one has not run at all.

So the chain is: press delivered -> handler runs -> thread created suspended ->
resumed -> never scheduled. Input, the cache-flush crash and the game's own logic
are all excluded. A lost resume is a race, which is the first explanation that
fits the ~1-in-3 success rate.

Not settled: where the resume is lost, and no successful boot has been captured
with kernel logging to compare against.
2026-08-19 10:19:06 +00:00
Sylpheed RE agent
723022f15c docs: the title does act on (A) - the loader thread it spawns is what stalls
"The title screen ignores (A)" is withdrawn. First-divergence across three boots
of the same binary says otherwise.

A slot-(1F) guest thread is spawned BY the press: exactly once per run,
immediately after the keydown, same stack base 70880000-70900000 in both runs
that got one, and never at all in the run that never accepted a press - which
rules out a periodic worker starting around the same time.

  prm6, reached the menu:      (A) at line 6498, (1F) at 6500, 6 ResolvePath after
  opt2, stuck on the title:    (A) at line 1287, (1F) at 1288, 0 ResolvePath after
  opt,  stalled before title:  no (A) ever, no (1F) thread at all

In the successful run the loader immediately reads six paths out of the on-disc
cache and the menu appears. In the failed run the same thread starts and performs
no file I/O ever again. Total ResolvePath for the three boots is 90/84/78 - the
successful run's extra six are exactly the ones after the press, so the boots are
otherwise identical in I/O.

Refuted as the cause: the cache-flush std::out_of_range. All four of today's runs
have zero GUEST-THROW, zero CRASH DUMP and zero Access Violation, and the guest
stays alive throughout with its keystroke-poll counter climbing past 15000.

Next probe is neither input nor the crash: what the (1F) thread waits on.
2026-08-19 10:03:41 +00:00
Sylpheed RE agent
63011eb9ed docs: a fourth paint order attempted; the title is intermittent, not input-bound
The tie-break needs a fourth measured screen with a tied group, and OPTIONS is
three d-pad steps from the main menu, avoiding the NEW GAME hang. It was not
reached.

Advancing past the title is intermittent: 1 success in 3 attempts today with the
same binary, profile and procedure.

Attempt 1 stalled before the title existed. The guest was alive - RSS steady at
598MB and the keystroke poll counter climbing past 15000 - but the screen was
black and screen_children.py found ONLY the splash object resident. So that
failure is not a presentation problem: the game never constructed the title.
Being able to separate "stalled before building the screen" from "built but not
presenting" is new, and it is what the reader is for.

Attempt 2 reached the title at 265s and refused four presses - (A) at 0.25s,
0.25s and 0.5s, START at 0.3s - every one of them logged as DELIVERED to the
guest. Third independent confirmation that input delivery is fine and the game
simply does not act on the press. Waiting longer does not help either: presses
were spread from 10s to about 4 minutes after the title appeared, while the
earlier successful run's press landed within seconds.

Records the log as evidence and states the next probe: it has to be guest-side
now, on whatever consumes the keystroke, since the input path is excluded.
2026-08-19 09:56:32 +00:00
Sylpheed RE agent
2efc0b7c59 docs: backlog — tie-break refuted six ways; residual is one blend on one screen 2026-08-19 09:34:29 +00:00
Sylpheed RE agent
6c93d43446 docs: backlog — primitive layers tabled; the tie-break is now the only gap 2026-08-19 09:16:13 +00:00
Sylpheed RE agent
a1624af24e docs: input was never the blocker; the third permutation came from the main menu
The game receives the (A) press - measured, vk=5800 flags=0001, out of ~6500
polls. Input delivery was never broken; four harness bugs were, and with those
fixed the boot goes title -> one (A) -> main menu.

GP_DIALOG DIFFICULTY is still unreached (NEW GAME hits the standing black-screen
hang), but the main menu carries two primitives, which is what the question
needed. Records the slip in the instrumentation too: logging on XSUCCEEDED
counts X_ERROR_EMPTY as success and buried the two real keystrokes under 6499
empty polls.

Next step is now STATIC: a primitive's position is stable by role across three
measured screens but nothing in the file predicts it, so dump the full 60-byte
declaration entries - four words unread - and look for a word that sorts like
the measured orders.
2026-08-19 08:57:01 +00:00
Sylpheed RE agent
20b0edc2c2 docs: backlog — the keystroke swallow is fixed and refuted as the cause 2026-08-19 08:21:27 +00:00
Sylpheed RE agent
efee309d8f docs+tools: screen_children.py, validated; the third paint order is blocked on input
screen_children.py walks every resident screen object (vtable 0x820b30b4), reads
the element array at +0x08 and the child array at +0x30, and prints the paint
permutation with each pivot. Validated in one run off the live title: it
reproduces BOTH previously measured orders character-for-character - the splash
[0,2,4,6,1,3,5] and the 24-element title permutation - so the next screen it is
pointed at can be trusted.

The screen that matters was not reached. GP_DIALOG DIFFICULTY carries exactly
one primitive and would say whether the game paints it first or last, which is
the bit that decides where primitives belong. But (A) does not advance the title
screen at holds of 0.10, 0.25 or 0.40s, and neither does START, with the pad
verified end to end: pad.py writes /tmp/xenia_pad.txt, the emulator runs with
--hid=file --pad_file pointing at it, and the mtime updates on every press. The
title is unambiguously the interactive one - PRESS (A) BUTTON is rendered.

Recorded as a blocker rather than worked around. Next step is specific: boot with
the emulator stdout kept and read the [RE-INPUT] IsUIActive log already present
on the canary branch, which would say whether the keystroke is being swallowed
emulator-side.
2026-08-19 07:48:58 +00:00
Sylpheed RE agent
71d9b73afe docs: backlog — primitives drawn opt-in; their paint order needs a runtime read 2026-08-19 07:21:48 +00:00
Sylpheed RE agent
6b65f7ea91 docs: backlog — fade alpha applied; drawing the .prm quads is unblocked 2026-08-19 06:56:56 +00:00
Sylpheed RE agent
2d2c281805 docs: backlog — resting pose settled; the unapplied fade alpha is next 2026-08-19 06:41:41 +00:00
Sylpheed RE agent
eb61368d23 docs: backlog — .prm decoded; the resting rule is the new blocker 2026-08-19 06:30:23 +00:00
Sylpheed RE agent
a87d5b5255 docs: backlog — two items solved, four opened by them 2026-08-19 06:04:10 +00:00
Sylpheed RE agent
fb4f035f08 docs: record the paint-order key as landed, with what it left unsettled 2026-08-19 05:43:29 +00:00
Sylpheed RE agent
aa1f49633e docs/re: point the paint-order item at the derivation
The entry said deriving the order from the bundle was open. A key has been found
— the T8aD header word at +0x08 — so the entry now says that, what it does not
cover (ties, bit meanings), and that it is not wired into the compositor yet.
2026-08-19 05:17:44 +00:00
Sylpheed RE agent
a290791a30 docs/re: point the ship item at the end-to-end mission-path measurement
The entry said the crash blocks it; it now also says how far a run gets (past
SELECT DATA, into a cinematic) and that the crash's firing point moves, so nobody
goes looking for a menu route around it.
2026-08-19 05:08:59 +00:00
Sylpheed RE agent
10b89c77a3 docs/re: restate the ship item's blocker as the crash, not navigation
Navigation is solved and scripted as far as the save-slot screen; what stops the
second capital-ship capture is the cache-flush crash firing at SELECT DATA. The
backlog entry now says that, so the next person does not re-solve navigation.
2026-08-19 04:01:09 +00:00
Sylpheed RE agent
0b4dcc6e8f tools/docs: the second-capital-ship blocker is stale; retry boots, not presses
BACKLOG said the per-class ship generalisation needs "the capture-ship-placement
build of Canary". Checked: the ship capture is in the CURRENT build —
RequestShipCaptureFrame and CaptureShipDrawForRE are in command_processor.cc on
auto/re-ui-draw-order, and F10 wrote a 2.9 MB ship capture from this session's
binary. No separate build is needed.

What actually blocks it is navigation: a mission is behind the main menu, and (A)
at the title is accepted on about half of boots with nothing observable
predicting which. tutorial_launch.sh drives boot -> title -> menu -> TUTORIAL and
retries the WHOLE BOOT on refusal, because re-pressing the same title never
works — measured, not assumed.

First run of it: (A) refused, so it rebooted. That is the expected shape rather
than a failure of the harness.
2026-08-19 03:24:40 +00:00
Sylpheed RE agent
343864cc2f docs/re: note that the viewer shares the compositor path
Checked rather than assumed: the Bevy viewer's UI Screens browser calls the same
ui_layout::compose, so the measured paint order and the ghost skip reach the
window a person looks at, not just the CLI's screen render. Its element table
stays in declaration order, so the per-element visibility toggles still index
correctly.
2026-08-19 03:13:37 +00:00
Sylpheed RE agent
f66e9de430 docs/re: the paint-order item now has a landed fix, not just a finding
BACKLOG said the viewer paints in declaration order and the title composites
wrongly. That is no longer true for the two builds with measured orders, so the
entry says what landed, what it exposed (the kind=0x4 ghosts), and what is still
open: deriving the order for screens nobody has captured. The order is
deterministic, so a rule exists; it is not in any decoded structure, and the
loader is what is left to read.
2026-08-19 02:32:31 +00:00
Sylpheed RE agent
069165c03d docs/re: mark the paint-order item solved, and say what is left
The item that has been open through this whole run is answered: the paint order
is the screen object's reordered child array at +0x30, not any table in the file.
BACKLOG and INDEX now lead with that, and the investigation behind it is kept in
full underneath — most of it refutations, which is what made the answer findable.

What is left is stated in the same breath, because it is what the port needs:
deriving that order from the bundle without running the game. Until then the
viewer paints in declaration order and the title screen composites wrongly, which
is now a documented defect rather than a mystery.
2026-08-19 01:46:20 +00:00
Sylpheed RE agent
2483b7c3c9 docs/re: my own flag hypothesis fails its test, and the input path is mapped
With the capture cvar gone from the launch line entirely, a fresh run reached the
boot title and (A) still did nothing. The flag is therefore not necessary for the
failure, and 0-of-7-with vs 4-of-6-without does not survive as an explanation.

The conclusion is the plain one: (A) at the title succeeds about half the time
and nothing measurable from outside predicts which. Five candidates are now
eliminated — Xenia UI swallowing the keystroke, the driver filter, a sign-in or
content call on the press, the age of the title, and the capture cvar.

So the guest side was traced instead. XamInputGetKeystrokeEx has exactly one
caller in the title, and that has one caller: entry_point -> main loop
(sub_8216EA68) -> per-frame input update (sub_822F1AA8) -> the pad poll
(sub_82457038). The poller's layout is readable and matches the runtime trace
(keystroke queue at +68/+72 drained with flags=3; current state at +36 compared
field-by-field against the previous at +52), and nothing in it is state-gated.
Whatever ignores (A) is a consumer further up — a real RE job, and that is where
the thread now stands, stated rather than guessed at again.
2026-08-19 00:47:53 +00:00
Sylpheed RE agent
a04c133edc docs/re: boot time refuted as the gate on (A); the flag correlates with no mechanism
An interleaved A/B (arms alternating in one series, so cache warming cannot pose
as either variable) breaks the confound the last entry flagged — and not in the
direction the first table suggested. The LATEST title of every run recorded,
268 s, accepted (A); a 232 s title refused. "The title arrived late" is dead.

That leaves --log_ui_draws correlating at 0 of 7 against 4 of 5, with no
mechanism available: the cvar is read only when F10 arms a capture, F10 was never
pressed in those runs, the per-draw hook is one relaxed atomic load, and the two
arms' startup config dumps are byte-identical across 246 settings. A correlation
with no mechanism — and an arm that failed once — is not a finding; it is a
variable to remove. Removed: F10 now arms the capture unconditionally.

Also recorded: three boots this session ended on a permanent black screen, two of
them with no input at all. Not the pad, not the cache-flush crash, about one boot
in five.

Five candidate explanations for the (A) gate are now eliminated or refuted. The
next step is the guest's own state machine in sylpheed.db, not another guess from
outside.
2026-08-19 00:37:03 +00:00
Sylpheed RE agent
4990cf6eb3 docs/re: the boot-title recipe is 3/3 without my capture flag and 0/5 with it — and confounded
Using last iteration's recipe (first title, one (A)) four more times, it failed
every time. The nine-run table splits perfectly on --log_ui_draws: 3 of 3
successes without it, 0 of 5 with it. That would indict my own instrumentation
cvar, which is the one that captures paint order.

It is also perfectly confounded and the entry says so rather than picking the
exciting reading: every success had its title inside 147 s, every failure at
177 s or later. Flag and boot-time move together across all nine runs. A
mechanism is hard to see for the flag (it is read only when F10 arms a capture;
the per-draw hook is one relaxed atomic load), which argues for the boot-time
story — but "I cannot see how" is not evidence.

The separating experiment is named: ON runs with a fast boot. One that accepts
(A) exonerates the flag.

Also recorded: widening the menu signature last commit made screen_id classify
some boot frames as "menu", twice in one run before any menu existed. A dark-blue
movie frame and this menu are not separable from a single grab — navigation
scripts need the classification to hold across two grabs, which is a caller-side
fix, not a classifier one.
2026-08-19 00:00:43 +00:00
Sylpheed RE agent
b9062ea3bc tools: a working route to the menu, and the classifier that could not see it
screen_id.py called the main menu "other". Its menu rule required a near-white
fraction above 1.5%, measured in 2026-07; the menu reached from the boot title
measures 0.03% (mean 13,26,59 — dark, strongly blue, essentially green-free).
That is worse than a cosmetic miss: a script that waits for "menu" and never
sees it reports the navigation as failed while the menu is on screen, which is
exactly what happened here. Both measured signatures are now documented in the
code and both classify.

menu_draw_capture.sh now taps ONCE on the first title rather than up to 40 times:
repeating was measured to be useless (the attract title accepts nothing) and the
first title accepts a single press.

title_states_capture.sh is new — it captures the draw list in both title states
in one run, which is what refuted the "the attract title omits the button plate"
theory.
2026-08-18 23:10:29 +00:00
Sylpheed RE agent
4b0263b80f docs/re: the scripted route to the menu does not work — measured, not assumed
The previous entry named the next step: "tap (A) once per second and see whether
the success rate goes to 1". It was run. The answer is no.

40 presses at 1/s on the title change nothing, and neither does one each of
START, B, BACK, X and Y. Every press was delivered (the driver logs down/up for
each) and the new [RE-INPUT] diagnostic never fired, so nothing was swallowed —
the guest received them and ignored them.

Also recorded, because it destroys a run rather than merely wasting it: tapping
(A) through the boot (88 presses over the intro) ends on a permanent black
screen with no crash and no throw.

What is left is a difference in STATE, not in input: the one success came on a
title that appeared ~83 s into a warm boot, the failures on titles that appeared
after a full attract cycle. "The attract-loop title is a non-interactive
presentation" is written down as a hypothesis with the experiment that would
settle it — a log_ui_draws capture in each state, looking for ptbtn00.
2026-08-18 22:45:08 +00:00