Commit Graph

6 Commits

Author SHA1 Message Date
sim
e909c7c133 chore: retire the last dead paths and names from the consolidation
Nothing here changes what a tool computes; it changes where tools look.

- tools/re-capture: 33 censuses globbed /work/sylph_extract, a path that has
  existed nowhere since /work became a clone, so they matched nothing and
  printed empty results. They now resolve the disc through a new disc.py
  from $SYLPHEED_DISC and exit loudly without it (the #44 fix, generalised).
  Nine scripts that imported siblings from the retired Reborn checkout or an
  old session scratchpad now import from their own directory. unitgroup.py
  only needs the variable when --pak is not given.
- sylpheed-xex: the loader only ever uses the XEX2 retail key. The dead
  devkit key and a doc comment claiming a devkit fallback that does not
  exist are gone; Project Sylpheed is a retail XEX2, so no XEX1 key either.
- sylpheed-viewer: real_font_rasterizes looked for /tmp/sylph_extract and so
  always skipped. It reads $SYLPHEED_DISC now, and passes against the disc.
- Comments and docs that named xenia-rs, the Reborn repository or /work/*.pe
  as places to look now name sylpheed.db, Canary's ppc_context.h and the
  flat .pe; docs/re/README.md no longer says the native Canary build does not
  run.

Historical records keep their original paths: findings that were measured
against /work/xenia-rs/sylpheed.db still say so.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-16 22:30:28 +02:00
sim
120621daca fix(tools): every sylpheed.db reader honours $SYLPHEED_DB, and none needs a retired checkout
`SYLPHEED_DB` is the documented contract for the static-analysis database —
`docker/decoder/sylph-decoder` sets it, and `docs/agents/CONTAINER-NOTES.md` and
`decoder-loop.md` list it — but no reader honoured it:

  isl_cmdtab.py, name_block_bases.py   hardcoded `/work/xenia-rs/sylpheed.db`, a
                                        path that has not existed anywhere since
                                        `/work` became a clone. Both failed on
                                        every machine, before and after the
                                        database moved.
  zq.py                                 used `$SYLPH_XEXDB`, a name invented in
                                        #39 without grepping for the existing one.

All three now resolve `$SYLPHEED_DB`, then `$SYLPH_XEXDB` (kept as an alias so
nothing already written against it breaks), then `<repo root>/sylpheed.db`, and
refuse with exit 1 naming both variables and the build command otherwise.

`grab_tutorial.sh` hardcoded its helpers into the retired `sylpheed-reborn`
checkout. That copy's `skip_intro.sh` still calls the removed `vgamepad` and
exits 0 having pressed nothing — the failure this repository's own copy was
rewritten to make loud. So the script was already running a silently broken
helper; it now resolves its helpers from its own directory. Nothing exists only
in reborn's `tools/re-capture` (checked: 0 reborn-only files).

Verified against the same database, output compared byte for byte with the
ORIGINAL scripts (path-substituted copies, sibling imports resolvable):

  resolution path    isl_cmdtab   name_block_bases
  default (root)     identical    identical
  $SYLPHEED_DB       identical    identical
  $SYLPH_XEXDB       identical    identical
  bad path           exit 1       exit 1          (zq.py: exit 1 too)

and `isl_cmdtab`'s output is byte-identical to the body of the committed
`docs/re/data/isl-command-table.txt`.

⚠️ `name_block_bases`'s output does NOT reproduce the committed
`docs/re/data/name-block-bases.txt` (2,609 lines differ, `strings in the image:
7366` vs `7140`). That is the database, not this change: the artefact was
generated from the agent box's older 586 MB database, and this machine's is the
current generator's. Two databases are in circulation. Not regenerated here.

⚠️ Also not fixed, because it is a different bug: `name_block_bases.py` globs
`/work/sylph_extract/**/*.pak`, another path that exists nowhere now; that part
of its report is silently empty. It should read `$SYLPHEED_DISC`.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-16 20:07:19 +02:00
5f623bf110 fix(zq): stop defaulting the database path into the repo being deleted
`zq.py` hardcoded one absolute path, and it pointed inside `xenia-rs` --
a repository CONSOLIDATION.md archives in Phase 5 and drops in Phase 7. It
resolved on exactly one machine, and on that machine it was days from becoming
a `duckdb` exception about a missing file, with nothing saying why.

Resolution order is now `$SYLPH_XEXDB`, else `<repo root>/sylpheed.db`, else a
refusal that names both. The repo-root path is taken relative to this script,
not the caller's cwd, because zq.py is run from wherever the investigation is.

No fallback beyond that, on purpose. The database is a build artefact of a few
hundred MB and is not tracked, so there is nothing to fall back *to*; a default
that silently resolves to the wrong database is worse than no default. That is
issue #16's lesson, which was about exactly this shape in the test suite.

Both failure paths say what to do and exit 1:

  $ zq.py fn 82000000            # nothing set, nothing at the repo root
  no database found.
    looked for: /…/Sylpheed/sylpheed.db
    set $SYLPH_XEXDB to an existing one, or build it with:
      sylph-xexdb dis <xex|iso> --db sylpheed.db --analyze sql

  $ SYLPH_XEXDB=/nope/missing.db zq.py fn 82000000
  $SYLPH_XEXDB is set but is not a file:
    /nope/missing.db

Also fixes the regeneration hint, which still named `xenia-rs dis` -- the
retired binary. It is `sylph-xexdb dis`.

Connecting is skipped when there is no subcommand, so `zq.py` still prints its
usage on a machine that has no database yet.

Verified: usage with no db (rc 0); missing db (rc 1); `$SYLPH_XEXDB` set to a
non-file (rc 1); and `$SYLPH_XEXDB` pointed at a real 336 MB database, where
`imp Rtl` returns its 1,280 `RtlLeaveCriticalSection` call sites. That database
turns out to have been generated from the uncommitted tree this branch ports:
it carries `import_address`, `import_role` and all 16 foreign keys -- an
independent confirmation of the schema the golden test now locks.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-14 20:49:49 +02:00
13c895abff feat(xexdb): port import-thunk naming + schema-wide foreign keys
Carries `xenia-rs` `harvest/import-thunk-naming` (b4f19f1) across into the
lifted crate. That work was found UNCOMMITTED in the retired repo's working
tree on 2026-09-14 and exists nowhere else: absent from `iterate-4A`, absent
from this crate as lifted. CONSOLIDATION.md Phase 5 ends with "delete the local
clone" and Phase 7 drops the emulator, so it had a deletion scheduled against
it.

Not a cherry-pick. The lift's base is exactly the harvest's parent (8401d4d),
so each file was merged three-way -- lifted vs base vs harvest -- which is what
made the port reviewable: 10 conflicts, 9 of them pure rustfmt reflow from the
lift's formatting pass, and 1 semantic.

The semantic one is insertion ORDER. `xdbf_achievements.image_id` is now a
foreign key onto `xdbf_images(id)`, so the image rows must be inserted before
the achievement rows. The merge moved that block; the conflict was the stale
copy left at the old position.

What arrives:

* **Import-thunk recognition** (`imports.rs`, 338 lines). An XEX import is not
  a PLT jump: the linker emits a four-word thunk whose first two words are
  import RECORDS that the loader rewrites at module load. On disc they are
  still records, so a PowerPC-only decoder prints two meaningless `.long`s in
  front of an indirect branch. This maps every word of every thunk, and every
  direct branch into one, back to its `imports` row. Shape-validated rather
  than trusted: an entry is indexed only when the four words it points at
  actually have the thunk shape.

  Adds `instructions.import_address` (FK onto `imports.address`) and
  `import_role` (`'record'` | `'thunk'` | `'call'`, NULL iff import_address is
  NULL), plus an index. `tools/zq.py` gains `imp` and `impcalls`, and `dis`
  now names imports instead of printing `.long 0x01010194`.

* **Sixteen schema-wide foreign keys**, declared wherever a column is derived
  from another table. CREATE TABLE and insertion order become load-bearing.

  `functions` is deliberately NOT an FK parent and the golden test now asserts
  zero inbound FKs onto it: DuckDB implements UPDATE as delete+insert, so one
  inbound FK would make `functions.name` un-updatable and break
  `apply_re_symbols.sql`, which re-applies RE symbol names after every
  regeneration.

The database path needed no change in the binary: `DbWriter` builds its own
index inside `ingest_instructions` from `info.import_libraries`. Only the two
output paths (`enrich_section` for JSONL, `write_asm`) take it as an argument.

Verified: `cargo test -p sylpheed-xexdb` = 10 passed / 0 failed, including
`db_schema_golden` (41s, builds a real DuckDB) which locks the 16-FK set and
the no-FK-onto-functions rule. `cargo clippy -p sylpheed-xexdb --all-targets
-- -D warnings` clean; `cargo fmt --all --check` clean.

Stacked on #32 -- it ports into a crate that only exists there.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-14 20:43:16 +02:00
MechaCat02
62b0f79590 wip: tool README, DuckDB wording, zq.py escape hatch 2026-09-13 19:42:26 +02:00
MechaCat02
86da451bfe wip: extract the xexdb tool closure 2026-09-13 19:31:49 +02:00