fix(decoder): give the container its database and its instrumented oracle #64

Merged
fabi merged 2 commits from fix/decoder-db-mount into main 2026-09-21 16:10:22 +00:00
Owner

The Decoder agent could not reach either of the two things a static-RE brief asks it for. Three separate defects, each of which fails quietly.

1. No database

SYLPHEED_DB=/xenia-rs/sylpheed.db named a path that no longer exists. The xenia-rs repo was retired by the consolidation, its clone was deleted, and the /xenia-rs mount was removed in #61 because it pointed at nothing — but the env var stayed. So zq.py and /sylph-dis could not run at all.

Now bind-mounted read-only at the container's repo root, which is where zq.py looks when $SYLPHEED_DB is unset — no variable left to drift out of step with the mount, which was the whole bug. Read-only is deliberate: DuckDB takes an exclusive write lock, and two agents plus the human sharing one file would corrupt it.

2. The wrong Canary

run-canary looked in Release/ then Debug/, never Checked/. Both of those exist on this box — Aug 28 and Jul 19 builds. They boot the game perfectly well and carry no audit_61 branch probe, so a probe run against either returns zero hits that read as a finding about the game rather than as a stale binary.

Configuration is now the outer loop and location the inner one, so a Checked build anywhere beats a Release build anywhere. $XENIA_BIN still overrides everything. The launcher also now names any missing instrumentation before the run rather than leaving an empty log to interpret afterwards.

Measured here with strings:

build date audit_61_branch_probe_pcs RE-DRAW
Checked Sep 20 8
Release Aug 28 0
Debug Jul 19 0

3. build-canary could not build one

It built $PROJECT_DIR/xenia-canary, which does not exist in this container — the source is bind-mounted at /canary and the launcher already exports XENIA_SRC=/canary. CONTAINER-NOTES.md has carried this since 2026-08-29 as a symlink workaround plus a warning to remember to delete the symlink afterwards. It reads $XENIA_SRC first now, so there is nothing to remember. Its default configuration moves ReleaseChecked to match what run-canary picks; the old default spent a full build on a binary nothing would run.

Two documented blockers refuted, not deleted

Kept with their history, because the sequence of wrong readings is what makes the right one checkable:

  • the CONTAINER-NOTES symlink dance — the warm build volume it was configured against is gone as well, removed in the 2026-09-18 cleanup, so the next build configures cleanly against /canary;
  • upstream-baseline.md's "version.h is never generated"CMakeLists.txt generates it at configure time now, with a stub fallback.

decoder-loop.md claimed the oracle lived at Linux/Release/ and that the probe was on two side branches. Both were true when written; neither is now (fork PR #2 brought the probe onto sylpheed-re).

What to look at

Pass: run-canary in the decoder container picks Checked/, prints no ⚠ instrumentation warning, and zq.py fn 0x824609C8 returns Pak_FindEntryByName.
Fail: it picks an August binary, or warns that audit_61_branch_probe_pcs is absent.

Verification

  • zq.py against the real agent image: DB mounted, no env var set, fn 0x824609C8Pak_FindEntryByName, classes lists RTTI.
  • strings on all three real binaries (table above).
  • Five pick_bin cases run against the function body extracted from the script, so the test cannot drift from it: stale-container-Release-vs-fresh-repo-Checked, container Checked winning within its config, fallback to Release, fallback to repo Debug, and $XENIA_BIN override.

Not verified: no Canary was actually launched. Judging an emulator run started from a shell here is against the standing rule, so the first real probe run is a human's.

🤖 Generated with Claude Code

The Decoder agent could not reach either of the two things a static-RE brief asks it for. Three separate defects, each of which fails quietly. ### 1. No database `SYLPHEED_DB=/xenia-rs/sylpheed.db` named a path that no longer exists. The `xenia-rs` repo was retired by the consolidation, its clone was deleted, and the `/xenia-rs` mount was removed in #61 *because it pointed at nothing* — but the env var stayed. So `zq.py` and `/sylph-dis` could not run at all. Now bind-mounted read-only at the container's repo root, which is where `zq.py` looks when `$SYLPHEED_DB` is unset — no variable left to drift out of step with the mount, which was the whole bug. Read-only is deliberate: DuckDB takes an exclusive write lock, and two agents plus the human sharing one file would corrupt it. ### 2. The wrong Canary `run-canary` looked in `Release/` then `Debug/`, never `Checked/`. Both of those exist on this box — **Aug 28** and **Jul 19** builds. They boot the game perfectly well and carry **no `audit_61` branch probe**, so a probe run against either returns zero hits that read as *a finding about the game* rather than as a stale binary. Configuration is now the outer loop and location the inner one, so a `Checked` build anywhere beats a `Release` build anywhere. `$XENIA_BIN` still overrides everything. The launcher also now names any missing instrumentation **before** the run rather than leaving an empty log to interpret afterwards. Measured here with `strings`: | build | date | `audit_61_branch_probe_pcs` | `RE-DRAW` | |---|---|---|---| | `Checked` | Sep 20 | **8** | ✅ | | `Release` | Aug 28 | **0** | ✅ | | `Debug` | Jul 19 | **0** | ✅ | ### 3. `build-canary` could not build one It built `$PROJECT_DIR/xenia-canary`, which does not exist in this container — the source is bind-mounted at `/canary` and the launcher already exports `XENIA_SRC=/canary`. `CONTAINER-NOTES.md` has carried this since **2026-08-29** as a symlink workaround plus a warning to remember to delete the symlink afterwards. It reads `$XENIA_SRC` first now, so there is nothing to remember. Its default configuration moves `Release` → `Checked` to match what `run-canary` picks; the old default spent a full build on a binary nothing would run. ### Two documented blockers refuted, not deleted Kept with their history, because the sequence of wrong readings is what makes the right one checkable: * the CONTAINER-NOTES symlink dance — the warm build volume it was configured against is gone as well, removed in the 2026-09-18 cleanup, so the next build configures cleanly against `/canary`; * `upstream-baseline.md`'s *"`version.h` is never generated"* — `CMakeLists.txt` generates it at configure time now, with a stub fallback. `decoder-loop.md` claimed the oracle lived at `Linux/Release/` and that the probe was on two side branches. Both were true when written; neither is now (fork PR #2 brought the probe onto `sylpheed-re`). ### What to look at **Pass:** `run-canary` in the decoder container picks `Checked/`, prints no ⚠ instrumentation warning, and `zq.py fn 0x824609C8` returns `Pak_FindEntryByName`. **Fail:** it picks an August binary, or warns that `audit_61_branch_probe_pcs` is absent. ### Verification * `zq.py` against the real agent image: DB mounted, no env var set, `fn 0x824609C8` → `Pak_FindEntryByName`, `classes` lists RTTI. * `strings` on all three real binaries (table above). * Five `pick_bin` cases run against the function body **extracted from the script**, so the test cannot drift from it: stale-container-`Release`-vs-fresh-repo-`Checked`, container `Checked` winning within its config, fallback to `Release`, fallback to repo `Debug`, and `$XENIA_BIN` override. **Not verified:** no Canary was actually launched. Judging an emulator run started from a shell here is against the standing rule, so the first real probe run is a human's. 🤖 Generated with [Claude Code](https://claude.com/claude-code)
fabi added 2 commits 2026-09-21 16:08:59 +00:00
`SYLPHEED_DB=/xenia-rs/sylpheed.db` named a path that no longer exists. The
xenia-rs repo was retired by the consolidation, its local clone was deleted, and
the `/xenia-rs` mount that served the database was removed in #61 because it
pointed at nothing. The env var stayed. So the decoder had NO database: `zq.py`
and `/sylph-dis` -- most of what a static-RE brief asks for -- could not run.

Mounted read-only at the container's repo root instead, which is where `zq.py`
looks when `$SYLPHEED_DB` is unset, so there is no variable left to drift out of
step with the mount. That drift is the whole bug: a path in an env var and a
path in a mount, maintained separately.

Read-only is deliberate. The host owns the file, DuckDB takes an exclusive lock
to write, and two agents plus the human sharing one database would corrupt it.
Regenerating means writing elsewhere and pointing $SYLPHEED_DB at it.

Missing-file cases now say so and print the command that builds one, rather than
starting an agent that discovers it mid-iteration.

Verified in the real agent image: DB mounted, no env var set,
`zq.py fn 0x824609C8` -> `Pak_FindEntryByName`, `zq.py classes` lists RTTI.

The brief's tooling table also claimed the old path, and said nothing about the
oracle binary; both corrected. It now records that the built Canary carries
RE-INPUT/RE-DRAW but NOT the audit_61 branch probe -- measured with `strings`
on both built binaries, zero hits; it is on two other branches (fork issue #1).

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
fix(decoder): give the container the Canary it is supposed to run
Some checks failed
CI / Native — linux (pull_request) Failing after 1h1m35s
CI / WASM — Web (pull_request) Successful in 24m37s
CI / Formatting (pull_request) Successful in 26s
1fdbb5f197
The database mount below was one of three ways the decoder could not reach its
own oracle. The other two are here.

`run-canary` never looked in `Checked/`. It tried `Release/` then `Debug/`, and
both of those exist on this box -- an Aug 28 binary and a Jul 19 one. They boot
the game perfectly well and carry NO `audit_61` branch probe, so a probe run
against either returns zero hits that read as a finding about the game rather
than as a stale binary. Configuration is now the outer loop and location the
inner one, so a `Checked` build anywhere beats a `Release` build anywhere;
`$XENIA_BIN` still overrides everything. Measured here: `Checked` has
`audit_61_branch_probe_pcs`, `Release` and `Debug` do not.

The launcher also now says which instrumentation is missing BEFORE the run,
because the alternative is reading an empty log afterwards and guessing.

`build-canary` built `$PROJECT_DIR/xenia-canary`, which does not exist in this
container -- the source is bind-mounted at `/canary` and the launcher already
exports `XENIA_SRC=/canary`. CONTAINER-NOTES has carried that defect since
2026-08-29 with a symlink workaround and a warning to remember to delete the
symlink afterwards. It now reads `$XENIA_SRC` first, so there is nothing to
remember. Its default configuration moves Release -> Checked to match what
`run-canary` picks; the old default spent a full build on a binary nothing ran.

Two documented blockers are refuted rather than deleted, since the sequence of
wrong readings is what makes the right one checkable: the CONTAINER-NOTES
symlink dance (the warm build volume it was configured against is gone too,
removed in the 2026-09-18 cleanup, so the next build configures cleanly against
`/canary`), and `upstream-baseline.md`'s "`version.h` is never generated" --
`CMakeLists.txt` generates it at configure time now, with a stub fallback.

`decoder-loop.md` claimed the oracle was at `Linux/Release/` and that the probe
was on two side branches; both were true when written and neither is now.

Verified: five pick_bin cases against the extracted function body, and `strings`
on all three real binaries.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
fabi merged commit f732b5ac1a into main 2026-09-21 16:10:22 +00:00
Sign in to join this conversation.