The port put two of my pages against each other: settle->plate 2.135 s and one
focus-ring revolution 2.177 s, both a declared 120 units during a static hold,
2% apart against a 6 ms run-to-run agreement. Fair challenge.
The resolution is that the question assumes a stable wall clock. Same interval,
same container, same day: 2.138, 2.132, and 2.549 s -- a 19% swing, caused by
adding --log_ui_draws=true. The 2% is a fifth of that. The two pages were never
in conflict about the game; they are three readings of one declared quantity
through a clock that moves. What settles the quantity is the disc.
Wall clock cannot separate the hypotheses, so I tried to measure frames instead.
Both instruments are recorded as failures rather than published as numbers:
* Canary's own [UI-CAP] counter -- the one that produced the corpus's 28.5 fps
-- costs a third of the frame rate. 300 frames in 16.567 s = 18.11 fps on a
screen that gives ~28 without it. That reclassifies 28.5 as a load-dependent
lower bound; it does not overturn it.
* A distinct-frame counter over the spinning ring FAILED its decisive control:
15.88 fps against the game's own 17.59 in the same window, 10% low, so the
ring does not change on every presented frame. Its static control also read
2.63 instead of ~0. Dead, not tuneable, per METHOD.md.
The rule that follows, and it applies to everything I hand the port: a measured
interval landing near a round number of declared units almost certainly IS that
number of units. Ship the units.
Also recovered here, because the same question needed it: the static PPC route.
Four tools open /work/xenia-rs/sylpheed.db and nothing in this repository builds
it -- no disassembler, no PPC decoder, and default.xex is encrypted (zero
plaintext "GamePart"). Xenia decompresses the image at load, so dump_image.py
reads it out of guest memory and validates it against the corpus's own landmarks:
the 29-entry GamePart id table at 0x820A1630 and the Xbox 360 D3D runtime
strings. String search and table dumps work again; instruction-level work does
not, and the present interval I wanted is an immediate, not a string.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_014voBspJ6kFncNErZJuZcLw
4.5 KiB
🟡 The static PPC route was lost with the container migration — the image is back, the disassembly is not
Status: ✅ the image is recovered and validated; 🔴 the disassembly database it is analysed with does not exist in this repository at all, and never did. 2026-08-29.
What broke
Four tools in tools/re-capture/ open a DuckDB database at
/work/xenia-rs/sylpheed.db — name_block_bases.py, archive_naming.py,
isl_cmdtab.py and the census work that produced most of the sub_82xxxxxx
findings in INDEX.md. In this container:
$ ls /work/xenia-rs
ls: cannot access '/work/xenia-rs': No such file or directory
🔴 And nothing in the repository builds it. A grep for duckdb finds only
consumers; there is no disassembler, no PPC decoder vendored, and capstone is
not installed (and pip install is refused here by PEP 668). So the static route
is four read-only clients of a producer that is not in the tree.
⚠️ This is not a small gap. Every finding that cites a function address —
the GamePart registry, the challenge gate, the ISL command table, PlayerParams,
the boot sequencer — is currently unre-checkable in this container. They are
not wrong; they are unverifiable, which is a different and quieter problem.
default.xex is not a substitute
The disc's executable is encrypted and LZX-compressed:
$ xxd -l 16 /disc/default.xex
00000000: 5845 5832 0000 0001 0000 3000 ... XEX2......0.
$ strings -a /disc/default.xex | grep -c GamePart
0
The header is intact — XEX2, media id 535107D4, original PE name
default.pe — and everything after it is noise. No decrypt/decompress exists in
the tree either.
✅ What is recovered, and how it is validated
Xenia decrypts, decompresses and relocates the image at load, so a running
guest holds the flat VA image the corpus calls the .pe
(VA = 0x82000000 + offset). tools/re-capture/dump_image.py reads it straight
out of /dev/shm/xenia_memory_* — no debugger, no emulator patch, no pause.
$ tools/re-capture/dump_image.py /sylph-home/re/sylpheed-image.pe
wrote ... 4194304 bytes VA 0x82000000..0x82400000
validated: GamePart id table + D3D runtime strings; 1013/1024 non-empty 4K pages
The validation is the corpus's own landmarks, not the tool's. A mis-based or partial dump fails both:
0x820A1630holds the GamePart id table — 29.rdatapointers resolving toGP_TITLE(0) …GP_TEST(28), withGP_CHALLENGEat 26, exactly aschallenge-mission-gate.mdrecords;- the image carries the Xbox 360 D3D runtime's own error strings
(
ERR[D3D]: Unanticipated CPU_INTERRUPT,D3D9D.LIB), which only the real loaded executable has.
So string search, table dumps and pointer chasing work again today. What does
not is anything needing decoded instructions: no mnemonic/operands, so no
xref search, no base solving, no call graphs.
⚠️ It also depends on a booted emulator, which is a bad dependency for the foundation of the static corpus. Dump once and keep the file.
🔵 For the human — what is actually needed
Not the image; that is solved. What is missing is the producer of the database, and its schema, which the four consumers pin exactly:
| table | columns used |
|---|---|
functions |
address, end_address, name |
instructions |
address, mnemonic, operands |
strings |
address, content |
An XEX unpacker would also be worth having on its own, so the static route stops needing a running emulator to bootstrap.
What it blocks right now
The one open question this iteration wanted it for: the game's present interval, i.e. the step from one submitted frame to 1/30 s of real time.
"2 units per submitted frame" is already grounded and emulator-independent — it
was read off a frame-indexed draw capture
(ui-keyframe-time-unit.md). The remaining link is
D3DPRESENT_PARAMETERS.PresentationInterval at device creation: _ONE means the
game runs at the console's 60 Hz vblank, _TWO at 30. That is a constant loaded
into a register, so finding it needs disassembly, not string search — the
image contains the D3D runtime but the interval is an immediate, not a string.
Settling it would move Q1's seconds-per-unit from measured to decoded,
and it is the only part of the UI clock still resting on a wall clock this
container has now been shown to move by 19 %
(present-rate-instrument-failed.md).