Commit Graph

1693 Commits

Author SHA1 Message Date
1cbbfd90cb Merge pull request 'docs(re): adopt the homeless disc-contents page, re-measured' (#56) from docs/adopt-disc-contents into main
Reviewed-on: #56
2026-09-19 18:48:14 +00:00
e82d7bff6f Merge pull request 'chore: hand the workspace over — the gated launchers, and the state of play' (#55) from chore/handoff-2026-09-18 into main
Reviewed-on: #55
2026-09-19 18:48:08 +00:00
00585952a9 Merge pull request 'ci: pin the toolchain to 1.98.1 in all three jobs' (#54) from fix/ci-pin-toolchain into main
Reviewed-on: #54
2026-09-19 18:48:00 +00:00
cd3c1a2f73 Merge pull request 'test: one disc resolver, no machine-specific defaults, and all three corpora in the CI container' (#53) from fix/corpus-mounts-and-paths into main
Reviewed-on: #53
2026-09-19 18:47:53 +00:00
06601c2a48 docs(re): adopt the homeless disc-contents page, re-measured
`GAME_CONTENTS.md` sat in the workspace root through the whole consolidation,
adopted by neither repo -- the corpus documents formats in depth but never said
what files the disc holds or where they sit.

Re-measured rather than transcribed, and that caught a real error: the source
placed `resource3d/`, `DefTables` and `MiscBin` under `dat/`. All three are in
`hidden/` -- which is why `SYLPHEED_RES3D` points at `hidden/resource3d`.
Counts, the language table and `media_id` (0x2D2E2EEB, from the XEX header)
re-verified against the retail extract.

Half the source was pre-RE speculation phrased as status -- `dat/*.pak` marked
"Unknown, magic bytes TBD" when the container is decoded disc-wide, plus a table
guessing each archive's contents from its name. Carrying that forward would put
claims into the corpus the corpus has already refuted, so it is dropped and the
page says what was dropped and why. INDEX.md stays the single authority on
format status.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-18 21:07:03 +02:00
sim
e45a56ad83 chore: hand the workspace over — the gated launchers, and the state of play
Resuming happens on the other machine, so anything that lived only in this
workspace either comes into the repo or gets named as something to carry.

**The launchers come in.** `run-canary-safe.sh` (Wine) and
`run-canary-native-safe.sh` (native) are the ONLY sanctioned way to start Canary
from the editor — they force software Vulkan and refuse to launch while a
hardware Vulkan device is visible, because Canary on the AMD GPU takes VS Code
with it. They sat in the workspace root, outside git, hardcoding one machine's
absolute paths, which is exactly why they could not be checked in. They now
derive the workspace from their own location and honour `$SYLPHEED_ISO` and
`$CANARY_BIN`, so the layout is a default rather than a requirement. Same for
`run-canary-native.sh` (interactive, hardware Vulkan — not from the IDE),
`diagnose-freeze.sh`, `live-guest-state.sh`, `heaptrack-wrap.sh` and the
`asound-null.conf` the native launcher needs beside it.

Both safe launchers were run from `tools/` before this commit: the native one
reached content in 20 s (`VERDICT: HEALTHY`, title + 25,398 XMA lines, no
faults), the Wine one ran 25 s and logged 4 `ADV.wmv` hits.

**`docs/agents/HANDOFF-2026-09-18.md`** records what changed since 2026-09-16,
what is on the server, what cannot travel through git, and the traps this machine
paid for — chiefly that the guest-PC branch probe exists only on the fork's
snapshot branch, so a rebuild from `sylpheed-re` silently loses it.

**`HANDOFF-2026-09-06.md`** gets a correction note rather than an edit: a plain
clone works again now that the 545 MB branch is gone, and its baselines are two
baselines old.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-18 07:17:36 +02:00
sim
c88391b68c ci: pin the toolchain to 1.98.1 in all three jobs
All three jobs used `dtolnay/rust-toolchain@stable`, so the gate resolved to
whatever stable was on the day it ran. A floating lint gate is not a gate: the
same tree goes green or red by date, and that already produced a disagreement
between two people reading the same commit — `collapsible_else_if` is `warn` on
1.92.0 and `allow`-by-default pedantic on 1.98.1, so both readings were correct.

1.98.1 is what run 206 resolved and what `docker/ci/Dockerfile` already pins, so
`docker/ci/run cargo clippy …` on a desktop becomes a true stand-in for this
workflow instead of an approximation. The header says how to bump: the three
refs here and the Dockerfile's `FROM` in one commit, in a PR of its own, where
the lints the new version turns on are the diff.

Also: the corpus-report step's comment quoted `207/0/14`, a tally two baselines
old. It now describes the shape of the problem without pinning a number that
decays.

Closes #15.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-17 22:21:27 +02:00
sim
cc9392bde4 test: one disc resolver, no machine-specific defaults, all three corpora in the container
Finishes #16 in the three places its earlier remedies missed.

`tests/`: the last four local `disc_root()` copies now use `tests/common`, and
with them goes the one real hardcoded fallback — `ui_keyframe_record_disc.rs`
fell back to an absolute path on one machine, which made `unset SYLPHEED_DISC`
a no-op there. Control: with the corpus absent that suite now finishes in 0.00s
instead of 57.55s, so it skips rather than finding a disc of its own.

`examples/`: seventeen examples defaulted to `/disc`, the mount point inside the
CI container. Redundant there — `docker/ci/run` sets `SYLPHEED_DISC=/disc` — and
wrong everywhere else, where a missing corpus turned into a file-not-found
against a path that has never existed on the host. They now name the variable to
set, like the other hundred examples already did.

`docker/ci/run`: mount `$SYLPHEED_RES3D` and `$SYLPHEED_ISO` alongside the disc.
Only the disc was mounted, so an in-container run sat out the res3d and iso
suites while looking like a full one — the defect this issue is about, in the
runner itself.

Measured in the container on this desktop with all three corpora present:
45 suites / 377 passed / 0 failed / 14 ignored, and `sylpheed-corpus-report.txt`
now reports PRESENT for all three rather than for the disc alone.

Refs #16.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-17 22:18:59 +02:00
4efd9f5936 Merge pull request 'fix(ppc-manual): 543 dead links, from two generator bugs and wrong relative paths' (#48) from fix/ppc-manual-dead-links into main
Reviewed-on: #48
2026-09-17 05:11:45 +00:00
080cae410d Merge pull request 'chore: retire the last dead paths and names from the consolidation' (#47) from chore/retire-leftover-names into main
Reviewed-on: #47
2026-09-17 05:11:31 +00:00
5f01fc9cf8 Merge pull request 'docs(reference): adopt the last reference files from the project root' (#46) from docs/adopt-root-reference into main
Reviewed-on: #46
2026-09-17 05:11:09 +00:00
sim
09b2a4871d docs(consolidation): record that the devkit and XEX1 keys are not needed
Project Sylpheed ships as a retail XEX2 (human decision, 2026-09-16), so
Phase 2's key harvest is closed rather than left looking unfinished.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-16 22:38:06 +02:00
sim
9bfe96e44d fix(ppc-manual): 543 dead links, from two generator bugs and wrong relative paths
- Category pages linked each family as `<slug>.md`, relative to categories/,
  where no family page lives. They now link `../<category>/<slug>.md`.
- Form pages linked a member into its *own* category directory, so every
  VMX128 sibling (`vsldoi128`) pointed at vmx128/ although its family page is
  under vmx/. They now link into the family's directory.
- Hand-written "Related" and sibling mentions linked other categories' pages
  as if they were in the same directory. 109 are retargeted through the page
  index; 29 that pointed a family page at itself (`vrefp128` on vrefp.md) and
  6 naming instructions the manual has no page for are plain text now.

Regenerated at the existing Canary pin (f21ebd49e): upstream has moved on, and
re-pinning belongs in its own change. The generator reports 0 family pages
changed and is idempotent; the only dead links left are TEMPLATE.md's
placeholders.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-16 22:37:12 +02:00
sim
cf7e02c51d docs(consolidation): close the plan — phases 5 and 7 are done
Record the end state at the top of the page: four repositories archived, their
clones gone from this machine, the Phase 7 drops done or never present here, and
Canary's default branch moved off `xenia-rs`. The retention question and the
history rewrite stay open for the human.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-16 22:35:03 +02:00
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
6dcdea1cf1 docs(reference): adopt the last reference files from the project root
Three untracked files in the project root had no home in either repository:

- the Xbox 360 technical reference report (a research compilation) becomes
  docs/reference/xbox360-re-technical-reference.md, unchanged;
- XBOX360_ARCHITECTURE.md becomes docs/reference/xbox360-architecture.md,
  trimmed to its platform facts. Its format "status" sections (PAK unknown,
  mesh unknown, audio TODO) and the `just sniff` workflow predate every
  decoder in this repo and were wrong;
- generate_export_docs.py becomes tools/generate_export_docs.py, the path the
  committed xbox360-exports.* already name as their generator. It lived
  inside a Canary checkout, so it now takes --canary and --out and fails
  loudly on a tree that is not Canary.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-16 22:19:54 +02:00
591527439d Merge pull request 'docs(ppc-manual): check every xenia-rs claim against Canary's source' (#45) from docs/ppc-manual-canary-claims into main
Reviewed-on: #45
2026-09-16 20:03:03 +00:00
49d1b861fa Merge pull request 'fix(re-capture): name_block_bases reads the disc from $SYLPHEED_DISC, loudly' (#44) from fix/name-block-bases-disc into main
Reviewed-on: #44
2026-09-16 20:02:52 +00:00
sim
f3c512f2ab docs(ppc-manual): check every xenia-rs claim against Canary's source
The hand-written parts of the manual still described how the retired
xenia-rs interpreter behaved: its snapshots, Rust casts and helpers. Each of
those 490 statements is now either restated as what Canary's emitters and
x64 backend actually do (at the pinned canary_experimental commit), or
dropped where it only made sense for xenia-rs.

Checking them turned up claims that were wrong, not just outdated:

- VSCR[SAT] is never modelled in Canary (DID_SATURATE is a stub and mfvscr
  cannot see it); the pages said saturating ops set it stickily.
- Canary does not implement lswi/lswx/stswi/stswx, dcbi, mtfsb0/mtfsb1,
  vmsum*, vmhaddshs, vupkhpx/vupklpx, and most SPRs; pages described them
  as working.
- Traps evaluate TO in Canary; stvebx/stvehx/stvewx store one element, not
  16 bytes; mtmsrd writes only EE; fres/frsqrte/vrsqrtefp precision claims
  and the stfs "rounds under RN / sets FPSCR" claim contradicted the spec.
- Reservations are a 64 KiB block bitmap plus a value compare, not
  per-address tracking.

Claims that neither Canary's source nor a public spec settles are marked
unverified (NI at boot, vmaddcfp128 operand order, estimate bit-exactness).

Generated regions are untouched; re-running the generator changes nothing.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-16 21:52:38 +02:00
sim
8b7d9f9d71 fix(re-capture): name_block_bases reads the disc from $SYLPHEED_DISC, loudly
Its data-table section globbed `/work/sylph_extract/**/*.pak`, a path that has
existed nowhere since `/work` became a clone. The glob matched nothing, so the
section reported "0 disc names" and an empty table with no error — while the
committed `docs/re/data/name-block-bases.txt`, generated back when the path
existed, records 13 450. The disc is required for that section, so a missing or
non-disc `$SYLPHEED_DISC` is now an error (exit 1), not an empty result.

Verified: without the disc, exit 1 with the message; with
`SYLPHEED_DISC=…/sylph_extract` (the original /work/sylph_extract), the section
reproduces the committed figures exactly — 13 450 distinct disc names,
50 / 261 data-table rows, `sub_82341A20 r30 0x82088F94 217 names 89% disc`.

⚠️ The artefact itself is deliberately NOT regenerated. Rebuilt from the current
database it changes findings — solved bases move, three 15/15 rows vanish, −280
lines — and the cause is the database, not this script: the string extractor's
Shift-JIS path requires kana, so kanji-only Japanese (e.g. the allocator's
`32B  未開放 %4d : 最大…使用量 %4d / %4d` debug lines) is not in `strings`, and
the bases those names pinned no longer resolve (sub_8285F2C8 r5 @ 0x820AE7AC:
15/15 before, 7 now). Regenerating would bake that regression into a cited
research artefact (`docs/re/structures/player-tuning-tables.md`).

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-16 21:08:55 +02:00
781da7047a Merge pull request 'docs: stop telling people to use the retired xenia-rs' (#43) from docs/retire-xenia-rs-instructions into main
Reviewed-on: #43
2026-09-16 18:55:48 +00:00
328c122ce4 Merge pull request 'docs(ppc-manual): quote Canary and our own decoder, not the retired xenia-rs' (#42) from docs/ppc-manual-canary into main
Reviewed-on: #42
2026-09-16 18:55:41 +00:00
41133c9d2d Merge pull request 'fix(tools): every sylpheed.db reader honours $SYLPHEED_DB, and none needs a retired checkout' (#41) from fix/sylpheed-db-contract into main
Reviewed-on: #41
2026-09-16 18:55:32 +00:00
sim
2f838040ca docs: stop telling people to use the retired xenia-rs
Instructions and generated text that still sent readers to `xenia-rs`, which is
archived and deleted locally. Provenance and dated research records are left as
they are — "lifted from xenia-rs", or a finding stating what database it was
measured against, is still true, and rewriting it would falsify the record.

Changed, because each one tells someone what to do today or writes stale text:

  docs/re/README.md          the RE toolchain guide queried `xenia-rs/sylpheed.db`
                             with `xenia-rs/zq.py`, and its "Dynamic" bullet said
                             to prefer xenia-rs's probe suite OVER Canary. Now:
                             `sylpheed.db` at the repo root (how to build it and
                             re-stamp names), `tools/zq.py`, dynamic = Canary, and
                             `.rdata` reads from the `.pe` (offset = VA - 0x82000000)
                             in place of `--dump-addr`.
  challenge-mission-gate.md, structures/achievements.md
                             reproduction commands `python3 xenia-rs/zq.py dis …`
  crates/sylpheed-xexdb/SCHEMA.md
                             titled after the retired `xenia-analysis` crate,
                             citing `xenia-rs dis`, pointing at a `xenia-analysis`
                             source path
  sylpheed-xexdb/src/formatter.rs
                             WROTE "generated by xenia-rs" into every disassembly
                             it produced (no test pins the banner)
  sylph-xexdb.rs, db.rs      "SQLite" / "DuckDB writer for xenia-rs"
  sylpheed-formats/src/hash.rs
                             pointed at `xenia-rs/RE_SYMBOLS.md`, now at
                             `docs/re/RE_SYMBOLS.md`

Verified: every rewritten reproduction command was extracted from the doc and
run as written against the regenerated database — all 5 exit 0 and return the
disassembly they describe. The README's function count (25 676) is the database's
own. `cargo fmt --all -- --check` clean.

Not changed, deliberately: the README's Oracle bullet says Canary's native Linux
ELF "crashes / does not run". That is about Canary, not xenia-rs, and it conflicts
with a July note that the native build works — unverified either way here.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-16 20:37:08 +02:00
sim
dedcf37867 docs(ppc-manual): quote Canary and our own decoder, not the retired xenia-rs
The generator had not been able to run correctly since the manual moved into
`tools/ppc-manual/`: it computed the repository root as `HERE.parent.parent`,
which now names `tools/`, so the XML, Canary's emitters and xenia-rs all stopped
resolving — silently, because both scrapers skipped what they could not find.
Every page's references had been pointing at paths that exist nowhere.

What each source contributed, measured on the 350 pages before this change:

  Operation (pseudocode)  251 pages: fixed boilerplate "derives from the xenia-rs
                          interpreter"; 99 carry real hand-written seeds
  C translation           337 pages: the same kind of boilerplate
  xenia-rs snapshot       336 pages: the interpreter arm, pasted in — the only
                          per-instruction semantics on unseeded pages
  links                   xenia-rs opcode/decoder/interpreter + Canary emitter

Now:

  * semantics come from **Xenia Canary**, the reference emulator, read through
    `git show` at a pinned upstream commit (`origin/canary_experimental`,
    f21ebd49e9). Not our checkout: it carries instrumentation and lacked
    upstream's `mcrf` fix, so it would have published probes and a wrong `mcrf`.
    Each page embeds the emitter (`InstrEmit_<mnem>`), and for the 128 pure
    one-line delegations also the helper that holds the semantics.
  * decode references point at `crates/sylpheed-ppc` — the decoder that
    produces `sylpheed.db` — as in-repo relative links.
  * the boilerplate now says what is true, and the C translation guide maps
    Canary's actual HIR calls, checked against `ppc_hir_builder.h` (including
    that `UpdateCR(n, v)` truncates to 32 bits).
  * `rust_scraper.py` -> `decoder_scraper.py` (interpreter half dropped);
    missing sources are now errors, not empty results.

Verified:

  consistency checks        455 XML entries, 350 families, 598 index keys
  hand-written tails        386/386 byte-identical after regeneration
  xenia-rs in generated     0
  pages with a snapshot     349/350 (was 336) — `dcbi` has no Canary emitter at all
  in-repo decoder links     910/910 resolve to a line holding the identifier
  emitter boundaries        brace counter == column-0 `}` rule on 521/521;
                            preprocessor model unit-tested (#if 0/#else/#elif)
  idempotency               re-run: 0 pages updated, 0 working-tree changes

Hand-written notes (outside the generated regions) are not rewritten here:

  * 110 links into `../../xenia-rs/...` were dead; they now point at the file in
    the archived repository (git.mc02.dev/fabi/xenia-rs @ 8401d4d). Line anchors
    were dropped because the notes predate that commit — 0 of 441 old line
    ranges match it — and a precise-looking wrong anchor is worse than none. The
    link text, which carries the author's line numbers, is unchanged.
  * 140 prose claims about xenia-rs's behaviour remain. 23 are verified to hold
    for Canary too (the 32-bit CR0 truncation, OE left unimplemented); the other
    114 need checking one by one, and some invert — e.g. `divdx` notes a correct
    64-bit CR0 update in xenia-rs where Canary's `UpdateCR` truncates. Left for
    a deliberate pass rather than a blind substitution.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-16 20:34:34 +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
ad30352384 Merge pull request 'test(formats): invert the primitives tripwire to pin the fix (#38, option A)' (#40) from fix/38-invert-primitives-tripwire into main
Reviewed-on: #40
2026-09-16 17:02:31 +00:00
sim
26c3d304e9 test(formats): invert the primitives tripwire to pin the fix (#38, option A)
`the_derived_order_puts_primitives_last_and_that_wipes_screens` asserted that
switching primitives on still flattened at least one screen (`wiped_on > 0`),
and said to turn `include_primitives` on by default the day it stopped.
`cfcda55` made that day arrive — a keyless primitive that would hide the screen
is now forced to paint first — and the wire had been red since 2026-08-29,
invisible to CI because the runner has no corpus and the suite self-skips.

#38 chose option A: keep the default off, and pin the fix instead. The flatness
proxy stood in for "paint order is solved", and the fix's own record says that
is only partly true — "This does **not** make `include_primitives` safe by
default" (docs/re/structures/ui-prm-primitives.md). So:

  * renamed to `no_build_is_wiped_with_primitives_on` — the old name asserted
    the bug; it survives in the doc comment for anyone searching from #38;
  * `wiped_on > 0`  ->  `assert_eq!(wiped_on, 0)`, with a message saying what a
    failure now means (`forced_backdrop` regressed) and that it must not be
    "fixed" by turning primitives off in the test;
  * `include_primitives` stays `false`; no library code changes.

It is the only end-to-end check of the rule: the four tests in
`ui_forced_backdrop_disc.rs` pin its mechanics, and none composes with
primitives on.

Verified with the corpus present, including that it can fail:

  fix                        3 passed   125 builds draw a primitive, 0 wiped
  forced_backdrop disabled   FAILED     36 of 125 wiped — the new message fired
  restored                   3 passed   125 builds, 0 wiped

The control's 36 is exactly the "36 builds ... wiped by our own sort" that
`cfcda55` and `ui-forced-backdrop.md` report — the guard independently
reproduces the fix's own number, so it measures precisely what was repaired.
The control was a one-line `return false;` in a scratch copy; the working tree
was restored and `git diff` showed only this test file before committing.

Closes #38

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-16 19:01:13 +02:00
cb731f2e96 Merge pull request 'feat(xexdb): re-land #35 onto main — import-thunk naming, FKs, zq.py fixes, RE symbols' (#39) from feat/xexdb-import-naming into main
Reviewed-on: #39
2026-09-16 05:09:15 +00:00
f33a2ff646 Merge pull request 'feat(port): adopt the measured held-direction repeat rate (F1)' (#27) from feat/f1-held-repeat into main
Reviewed-on: #27
2026-09-15 19:47:28 +00:00
523a2aa94b Merge pull request 'chore(tools): adopt the PPC manual and a canary launcher that works anywhere' (#34) from chore/adopt-orphan-assets into main
Reviewed-on: #34
2026-09-15 19:46:48 +00:00
cea680b24d Merge pull request 'docs(agents): the gate that cannot see a working tree, and the Phase 5/7 checks re-run' (#36) from docs/consolidation-dirty-tree-finding into main
Reviewed-on: #36
2026-09-15 19:46:37 +00:00
d3011ea8e2 Merge pull request 'docs(agents): the plan to consolidate six repositories into two' (#29) from plan/consolidation into main
Reviewed-on: #29
2026-09-15 19:46:19 +00:00
bc9f6bd49b Merge pull request 'fix(re): the capture checker counted its own selftest fixture as a citation' (#37) from fix/capture-citations-selfscan into main
Reviewed-on: #37
2026-09-15 19:46:02 +00:00
840d4b8bac Merge pull request 'docs(re): give docs/re/ the citation check docs/port/ has always had, and prune' (#33) from fix/capture-citations into main
Reviewed-on: #33
2026-09-15 19:44:48 +00:00
04e8d6244c Merge pull request 'feat(xexdb): lift the DuckDB generator and disassembler out of the retired emulator' (#32) from feat/xexdb-tool into main
Reviewed-on: #32
2026-09-15 19:15:22 +00:00
5a77229bbb Merge pull request 'docs(agents): how the containers and agents are actually set up' (#31) from docs/containers-setup into main
Reviewed-on: #31
2026-09-15 19:15:12 +00:00
9d41971646 Merge pull request 'docs(reference): adopt the four homeless reference files, and a LICENSE' (#30) from harvest/xex2tractor-assets into main
Reviewed-on: #30
2026-09-15 19:15:02 +00:00
sim
0679abb9f9 harvest: RE_SYMBOLS.md and apply_re_symbols.sql, which Phase 3 left behind
Phase 3 lifted the DuckDB tool out of `xenia-rs` but not the two files that go
with it, and this branch's own code already depends on one of them: the FK rule
in `db.rs` and `db_schema_golden.rs` exists *because* `apply_re_symbols.sql`
re-stamps reverse-engineered names onto `functions` after every regeneration.
Sylpheed referenced that file three times and contained it nowhere — on no
branch. CONSOLIDATION.md's end state is "Sylpheed holds everything", and the
`xenia-rs` clone is scheduled for deletion.

  docs/re/RE_SYMBOLS.md       byte-identical to xenia-rs/RE_SYMBOLS.md (cmp)
  tools/apply_re_symbols.sql  every statement identical; the two comment lines
                              that name paths now name this repo's paths

Verified against the real 336 MB database, which carries all 16 foreign keys,
inside a transaction that was rolled back (the database is unchanged):
every statement runs, and 208 functions carry reverse-engineered names. Run
from both the old location and this one.

Not harvested: `xenia-rs/zq_dis.py`, an untracked six-line subset of
`zq.py dis` with a hardcoded path — superseded, nothing to keep.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-15 19:23:07 +02:00
sim
dce085277a chore: ignore /sylpheed.db — zq.py now defaults to it
The previous commit on this branch made `tools/zq.py` look for its database at
`<repo root>/sylpheed.db`, and its refusal message tells people to put one there.
Nothing ignored that path. The database is a build artefact of several hundred
MB, so a single `git add -A` would have committed it into a public repository's
history — the class of blob CONSOLIDATION.md's history-rewrite fork exists to
argue about.

Anchored (`/sylpheed.db`, plus DuckDB's `.wal`) so it covers only the default
location, not any file of that name elsewhere. Verified by creating the files:
both ignored, `git status` silent, and a `sylpheed.db` in a subdirectory is not
swallowed by the rule.

Found while writing the Phase 7 steps: moving the 336 MB database out of
`xenia-rs` before that clone is deleted is exactly how someone would put it here.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-15 19:20:38 +02:00
fdf498c684 docs(agents): the #32 workspace test count is in — 367 passed, and the one failure is main's
Closes the page's one explicitly outstanding result. Run in sylph-ci:local
(rustc 1.98.1, byte-identical to the runner) with the disc present and
--no-fail-fast: 45 suites, 367 passed, 1 failed, 14 ignored. The +9 against the
disc-less #35 run (377) is exactly #35's nine imports.rs unit tests.

The single failure is ui_prm_primitives_disc, red on main since #23 and
bisected there, not introduced by #32.

Records the three things that stopped the number being obtained, as rules:
--no-fail-fast (an earlier run silently covered half the workspace), a memory
cap sized to the host (the default 7 GB OOM-kills slb_leading_segment_disc on
this machine with the disc mounted), and a ~36 GB disk budget for a cold target
volume.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-15 08:13:02 +02:00
108378fe21 docs(agents): the formats-pin tag count is 7, and the disk figures have moved
Re-checked against the server rather than the page. `Sylpheed` has 7 tags and
all 7 are `formats-pin-*`. The eighth this page counts, `formats-pin-2026-08-29`
without a letter suffix, is in `Syplheed-Reborn` — a repo a Sylpheed rewrite
would not touch, and one Phase 5 archives read-only regardless.

The pin itself is exactly as claimed: `formats-pin-2026-09-01` resolves to
`e2630413`, and the in-container build fetches that git dependency over the
network for real, so the blocker is live rather than theoretical.

Also updates the disk figures the "don't rewrite" recommendation rests on: 90%
used and 96 GB free, not 83% and 154 GB, with `target/` at 34 GB. The
recommendation is unchanged and the argument is now stronger — reclaiming
118 MB by rewriting history while 34 GB of rebuildable output sits beside it is
the wrong lever.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-14 21:25:53 +02:00
d9ba2c73b1 fix(re): the capture checker counted its own selftest fixture as a citation
`check-capture-citations` exits 1 on a clean checkout of this branch, and would
have kept doing so for ever:

    🔴 cited but NOT committed: 1
        docs/re/captures/no-such-file-anywhere.png

`SEARCH` includes `tools`, so the scan reads this file -- and `selftest()`'s
planted fixture is a literal capture path. The checker cited its own test data,
to a file that will never exist by construction. A gate that is red before
anyone changes anything teaches people to ignore it, which is the opposite of
what Phase 4 built it for.

Excluding only this one file (`SELF`) keeps every other tool in scope. A real
citation belongs in a page, or in a tool that opens the capture -- never in the
checker itself.

Added a selftest case for it, because this is exactly the class of bug the rest
of this file already documents surviving: the ERE that matched nothing while
five ticks stayed green. Verified the guard can fail, rather than assuming it:

    exclusion neutralised -> "own fixtures not counted 🔴 FAILED",
                             selftest rc=2, real check rc=1 reproducing the bug
    exclusion restored    -> selftest ok (7 cases), check rc=0

After the fix, on this branch:

    captures committed          : 212
      cited by a page or a tool : 212
      cited by nothing          : 0
      🔴 cited but NOT committed: 0        rc=0

which is also the first independent confirmation of Phase 4's "212 captures,
all cited" -- the checker now agrees with the page.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-14 21:18:55 +02:00
d0f3885fb5 docs(agents): re-run the Phase 5 and Phase 7 checks, and record what they say
This page says not to trust its own ledger on arrival, so the checks were run
again rather than read. Nothing was archived and nothing was deleted — both are
the human's, and both phases stay open.

The substantive finding is that Phase 5's containment check is the wrong test
for half the list it names. `xenia-rs` and `xex2tractor` were never absorbed;
their disposition is harvest-then-archive. Run the check literally against
`xenia-rs` and it returns 42 of 42 refs "not present in Sylpheed" — every line
true, every line unactionable, which is the failure this page already names
once about Phase 0's first gate. For those two the invariant is that the
harvested artefacts are in Sylpheed and the repository is archived rather than
deleted; that is now checked separately, and it shows the harvest is real but
lives only on the unmerged PR branches, so Phase 5 should follow them rather
than precede them.

Containment itself holds for the two repos it does apply to: 21/21 and 2/2.

Also answers Phase 7's one open question — nothing cites `texcompare/`, and all
four `ship_render` citations name the example program, not the output
directory — and records that most of Phase 7's list does not exist on this
machine, that `has_wiki: true` is a flag rather than content (all six wikis
return 404, never initialised), and that the disk is at 90%, not the 83% the
page records.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-14 21:00:40 +02:00
589c403c62 docs(agents): the zq.py database path is fixed, not outstanding
This page recorded it as "not changed here, because the right replacement is a
decision". The decision was taken: PR #35 `38cc170` resolves `$SYLPH_XEXDB`,
then `<repo root>/sylpheed.db`, then refuses with both named — no third
fallback, because the database is an untracked build artefact and a default
that silently resolves to the wrong one is worse than no default.

Leaving the page saying otherwise would be the defect this section is about.

`SCHEMA.md`'s retired-repo heading is still outstanding and stays listed.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-14 20:50:44 +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
b2f089e7d3 docs(agents): the Phase 0 gate cannot see a working tree — it missed 468 lines
Found 2026-09-14 while pulling the repos on the other machine: `xenia-rs` had
468 uncommitted lines plus an untracked 338-line `imports.rs` in the very crate
Phase 3 lifted, written 2026-09-10 and sitting there for four days. Verified
absent from `iterate-4A` and from the lifted crate in PR #32 — it existed in
exactly one place, and that place was not git.

Phase 0 is titled "Secure the single-copy work" and its gate passed anyway,
because the gate iterates `refs/heads` and a dirty working tree has no ref.
Canary's two dirty files were secured only because a human already knew about
them; nothing found them. Phase 1 then declared the archive honest while this
sat beside the branches it pushed. Phase 5 ends with "delete the local clone"
and Phase 7 drops the emulator, so a deletion was scheduled against it.

Records: the finding and the `git status --porcelain` half the gate was
missing (run across all four repos — only Canary is dirty, and both entries are
already on Phase 7's drop list); that it is secured on `harvest/import-thunk-
naming` and ported in `feat/xexdb-import-naming`; a fifth entry in the
wrong-claims list; and a `0b` row in the status table.

Also records three pieces of Phase 3 residue found while porting, the sharpest
being that `tools/zq.py` still defaults its database path to a location inside
`xenia-rs` — the repository Phase 5 archives and Phase 7 drops. Left unchanged:
the right replacement is a decision, not a guess.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-14 20:44:48 +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
34d3bbc8fd docs(agents): record the progress, and correct four claims this page got wrong
Paused at six of eight phases, all committed and pushed, nothing left in a
working tree. The page now carries a STATUS section the other machine can
finish from: what is done, which PR each phase is in, what to run next, and
what is deliberately left for the human.

🔴 FOUR THINGS THIS PAGE ASSERTED WERE WRONG, and each is corrected in place
rather than quietly amended:

  * "10 dangling citations" was ONE. Eight were DIRECTORY references, which
    resolve and are absent only from `git ls-tree`; one was a path ending a
    sentence, with the full stop pulled into the match. I reported that 10 to
    the human twice.
  * `extract -r` is not how the .pe was made and nothing depends on it. The
    plain extract is, and the tool Phase 3 keeps reproduces it byte-for-byte.
  * The Phase 0 gate compared branches by SHA and called seven safe branches
    unpushed -- a branch that is an ancestor of a pushed one is preserved.
  * There is no DirectXShaderCompiler drift; the ' m' is nested submodule dirt.

The pattern is worth more than the corrections: every claim that was REASONED
turned out wrong, and every one that was RUN held. Phase 2's gate refuted its
own premise, Phase 3's proved two alarming row deltas were an improvement, and
Phase 4's check caught a deletion I had just made. The page now says to re-run
the gates rather than trust the results recorded in it.

Phase 5 (archive) and Phase 7 (drops) are open and marked NOT STARTED, with
the reason each needs the human: archiving is reversible and deleting a
repository is not, and the drops are on the human's disk.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-13 21:22:47 +02:00
MechaCat02
10dc260f0c chore(tools): adopt the PPC manual and a canary launcher that works anywhere
CONSOLIDATION.md Phase 6. Both lived untracked in the project root -- on one
disk, backed up by nothing.

  tools/ppc-manual/   393 files, 3.7 MB. 455 instructions, 350 family pages,
                      598 mnemonics resolvable through index.json, plus the
                      generator that produced them.
  tools/run-canary.sh the oracle launcher.

🔴 THE LAUNCHER WAS BROKEN IN TWO WAYS AND IS REWRITTEN, not copied:

  * it pointed at `xenia-rs/sylpheed.iso`, a SYMLINK. Wine cannot resolve one
    and says "path invalid", which reads as a corrupt image rather than a path
    problem -- it has cost a session before. It now points at the real file and
    warns if handed a symlink.
  * it hardcoded one machine's absolute paths, and named `xenia-rs`, which this
    consolidation retires. Now derived from the script's own location, with
    SYLPH_CANARY_BIN / SYLPH_ISO overrides and a check that each exists.

The standing constraints are in its header where someone will read them: one
emulator at a time, Canary runs MUTED, and never judge a crash or a hang from
a Bash-launched run -- a SIGKILL that looked like the binary was the editor's
process supervisor.

⚠️ The manual's GENERATOR reads the xenia-rs source tree, which is going away.
Its decoder now lives here as crates/sylpheed-ppc, so the generator must be
repointed before it is run again. Recorded in the README rather than left for
someone to discover; the manual's content is checked in and regenerates from
nothing implicitly.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-13 21:18:00 +02:00