Files
Sylpheed/docker/agent/AGENT.md
Sylpheed RE agent 965c3f70fd port: make the Godot menu shell the agent's primary objective
Sets a new mission: boot the real disc through developer splash -> intro video
-> title -> main menu -> submenus in Godot 4, interactively, with no gameplay,
no 3D and no emulator.

docs/port/MISSION.md defines it -- eight gated milestones, each finished by an
ARTIFACT rather than by compiling, plus the Ready Room as an explicitly gated
stretch goal with a one-iteration probe that decides go/no-go. GP_READY_ROOM is
1106 entries with 6 recoverable names and is ISL-scripted, so it is either a
week or a quarter, and the agent must not start it on its own authority.

Architecture, per the user's decision: the Godot project is INDEPENDENT of the
Rust viewer and never reads a disc format. An offline Rust exporter converts the
disc into open formats; Godot reads only those. No GDExtension, no Rust in the
Godot project, and sylpheed-viewer is off limits -- it stays the human's
verification tool with its static-data rule intact.

docs/port/FORMAT.md specifies the open format, versioned, because modding is the
port's second goal and that makes the layout a deliverable rather than a temp
directory: JSON over XML (Godot parses JSON natively; its XMLParser is SAX),
names never hashes, provenance in every generated file, and unknowns listed
rather than guessed.

The discipline the whole thing rests on is the derived/authored split. `export/`
is regenerated wholesale and never hand-edited; `authored/` is hand-written and
survives a re-export. Three things this milestone needs are NOT on the disc in
any decoded form -- which button does what, paint order, and menu sound cues --
so they live in `authored/` with a stated `why`. Deleting an authored entry
because the exporter can now emit it IS the measure of progress.

`export/` is gitignored: it is generated from the user's own disc and this stays
a clean-room repo.

Container: adds a pinned Godot 4 (windowed under Xvfb for screenshots, plus a
headless wrapper). ffmpeg already carries libtheora, which is the video target --
Godot 4 plays only Ogg Theora natively and the disc's ADV.wmv is WMV3/WMA Pro.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-28 17:11:35 +02:00

85 lines
4.2 KiB
Markdown

# 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
```bash
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.
## The Godot port
The primary objective — see `docs/port/MISSION.md`. Two binaries are installed:
```bash
godot-headless --path port/ --script res://tools/check.gd # no display needed
DISPLAY=:99 godot --path port/ # windowed, under Xvfb
screenshot ~/shots/godot.png # then capture it
```
* **Godot is pinned to one version** in the Dockerfile. An engine bump changes
rendering, and this project diffs Godot's output against a reference renderer —
so do not upgrade it to fix a bug without saying that is what you did.
* **`sylpheed-cli screen render` is the reference.** When Godot draws a screen,
render the same build with the CLI and compare. Where they disagree, one of
them is wrong; say which, and why, rather than tuning until they match.
* **ffmpeg has libtheora**, which is the transcode target for video. Keep the
exact command in the exporter config — a modder who dislikes the quality should
be able to re-run it, not reverse-engineer what you did.
* **Never commit anything under `export/`.** It is generated from the user's own
disc and gitignored. Code, schemas, `authored/` mappings and docs only.
## 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.