Files
Sylpheed/docs/agents/CONTAINER-NOTES.md
MechaCat02 72b10e7d03
Some checks failed
CI / WASM — Web (push) Has been cancelled
CI / Formatting (push) Has been cancelled
CI / Native — macos-latest (push) Has been cancelled
CI / Native — windows-latest (push) Has been cancelled
CI / Native — ubuntu-latest (push) Has been cancelled
decoder: mount the disassembly DB and the flat VA image
The decoder had neither, and reported the gap precisely: four scripts in this
repo READ /work/xenia-rs/sylpheed.db and nothing produces it, so the whole static
PPC route was consumers with the producer missing.

Both exist on the host and are now mounted read-only: the 586 MB database (25 481
functions, 851 classes with RTTI, EH tables, imports, 1.8M indirect-dispatch
candidates) and the decompressed image.

The image is the more useful of the two. It is a FLAT VA DUMP -- file offset =
VA - 0x82000000 -- so reading a known address needs no XEX decrypt, no LZX, and
no booted emulator. The decoder had independently recovered the same bytes by
dumping /dev/shm/xenia_memory_* and validating against the GamePart table, which
is good work and a sound method, but it noted itself that needing a running
emulator is a bad dependency for something the entire static corpus rests on. It
does not need one.

Also recorded that an earlier claim the .pe was STALE was tested and refuted, so
nobody re-litigates it, and that instructions.raw is an INT rather than hex.

Written down as reference material, explicitly NOT a deliverable: they are
read-only, they come from outside the repository, and a fresh checkout elsewhere
has neither. Reimplementing the producer belongs in sylpheed-formats, and until
it exists every static finding rests on an artefact this project cannot rebuild.
2026-08-29 15:17:52 +02:00

5.0 KiB

Notes for an agent working inside this container

Read this before starting a dynamic-RE run. Everything here is something that already went wrong once.

The container fixes three old traps for you

  • The display outlives the turn. Xvfb and openbox are children of PID 1, not of your shell. The old "Xvfb dies on its own every few minutes" note is gone — you no longer have to wrap a whole session in one blocking foreground call to keep it alive.
  • The toolchain is real. tools/re-capture/rebuild_canary.sh exists because the old box had no cmake/ninja/clang and only runtime sonames, so it hand- relinked object files. Do not use it here. Use build-canary.
  • numpy and Pillow are installed. entities2.py, flight_probe.py and the image oracles work. Their absence used to look like a logic bug.

Method (the part that matters more than the tooling)

  • Measure the oracle; never infer it. A session with zero Canary runs is a red flag.
  • Trace upstream to where data first goes wrong, rather than patching the symptom you can see.
  • Try to refute before believing. Record demotions rather than editing them away — docs/re/README.md has the /🟡/ convention, and a withdrawn result is more useful than a quietly deleted one.
  • A probe that never performs the action will "prove" the action does not exist. The "targeting is automatic" conclusion came from a sweep that only ever tapped once; target select is Ⓐ pressed twice.
  • Do not poll faster than the guest updates — it manufactures a clean curve out of noise. rate-curve-aliased-BAD.csv is committed as the bad example.

Running the emulator

run-canary                       # correct audio/pad/display flags baked in
pad.py tap A ; pad.py dpad down  # scripted input (--hid=file, no uinput)
screenshot ~/shots/now.png       # cropped to the GAME surface, not the window
python3 tools/re-capture/gmem.py find hex:820af844 400
  • One emulator at a time. run-canary enforces it with a lockfile.
  • Boot is slow cold, ~25 s once the shader/code caches are warm — so a launch-and-dump fits in a single call.
  • Screens: classify by whole-image statistics (screen_id.py), not named pixels. Named-pixel oracles are only valid while the game image sits at a known place, and nothing errors when it moves.

Verifying your own work

  • Reborn's disc-gated tests self-skip without SYLPHEED_DISC. A green run with it unset means almost nothing. build-reborn test wires it up for you.
  • Prefer a headless self-verify over "it compiles": sylpheed-cli mesh render, screen render, save info all produce checkable artifacts.
  • A Bevy system-parameter conflict is invisible to the type checker and panics at startup. If you touch viewer systems, run the binary, don't just build it.

Reporting

State what you measured, what you assumed, and what you could not settle. If a result is withdrawn, say so and keep the reasoning — that is the corpus's whole convention, and the reason its numbers can be trusted.

The static-analysis corpus — mounted, not reproducible

Two things arrive read-only from the host because nothing in this repository can produce them yet:

path what env
/xenia-rs/sylpheed.db the disassembly database, 586 MB SYLPHEED_DB
/image/sylpheed.pe the decompressed image, flat VA dump SYLPHEED_PE

The .pe is a flat VA dump: file offset = VA - 0x82000000 (SYLPHEED_IMAGE_BASE). So reading 0x820A1630 is seek(0xA1630) — no XEX decrypt, no LZX, and no booted emulator. An earlier belief that this file was stale was tested and refuted; it is current.

Recovering the image by dumping /dev/shm/xenia_memory_* also works and self-validates, but it needs a running emulator — a poor dependency for something the whole static corpus rests on. Use the file.

The database is far richer than the four scripts that read it use:

functions                     25 481   address, name, end_address, frame_size,
                                       saved_gprs, is_leaf, pdata_validated, has_eh
classes                          851   name, vtable_address, rtti_present, base_classes_json
imports                          398   library, ordinal, name, address
eh_funcinfo / eh_try_blocks    2 588 / 315
function_pointer_arrays        1 526   + 8 568 entries
indirect_dispatch_candidates 1 827 297  dispatch_pc, vtable_address, method_address

instructions.raw is an INT, not hex — a trap this corpus has already paid for. Query with python3 -c 'import duckdb'; it is not SQLite.

These mounts are reference material, not a deliverable

They are read-only and they come from outside the repository, which means a fresh checkout on another machine has neither. Reimplementing the producer — XEX decrypt + LZX decompress, and the disassembly-to-database step — belongs in crates/sylpheed-formats. Until then, every static finding rests on an artefact this project cannot rebuild, and that is a real gap in the corpus rather than a convenience.