Commit Graph

1707 Commits

Author SHA1 Message Date
9414830ed7 Merge pull request 'fix(canary): point the launchers at a binary that exists and is instrumented' (#63) from fix/canary-native-binary-path into main
Some checks failed
CI / WASM — Web (push) Has been cancelled
CI / Formatting (push) Has been cancelled
CI / Native — linux (push) Has been cancelled
Reviewed-on: #63
2026-09-21 16:03:06 +00:00
884a2c3944 fix(canary): point the launchers at a binary that exists and is instrumented
Some checks failed
CI / Native — linux (pull_request) Failing after 1h3m36s
CI / WASM — Web (pull_request) Successful in 24m29s
CI / Formatting (pull_request) Successful in 27s
`/sylph-canary` was dead at both ends, measured rather than assumed:

  * `run-canary-safe.sh` runs the Wine build and defaults to
    `xenia_canary_i2d.exe`, which DOES NOT EXIST. The `xenia_canary.exe` that
    does (2026-06-19) has ZERO strings for `audit_61_branch_probe_pcs` and zero
    for `RE-INPUT`/`RE-DRAW` -- it predates all our instrumentation, and
    refreshing it needs the clang-cl + xwin toolchain on `cross-build-wine`.
  * both native launchers defaulted to
    `xenia-canary-native/build/bin/Linux/Release/xenia_canary`. That directory
    does not exist on this workspace -- the checkout is `xenia-canary/` -- and
    Release is not even a target in that build tree (`ninja -n` lists 0 steps),
    so its binary is frozen at 2026-08-28, before the probe.

Native launchers now default to
`xenia-canary/build/bin/Linux/Checked/xenia_canary`: the config this tree can
actually build, rebuilt today with the audit_61 probe (Canary PR #2), verified
by `strings` -- audit_61 8 hits, RE-INPUT/RE-DRAW 4. `Checked` is optimised WITH
assertions, which is what a behavioural reference should be: a bad state stops
loudly rather than being sampled.

The Wine launcher now ABORTS with the reason and points at the native one,
instead of failing somewhere downstream on a missing file.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-20 21:00:13 +02:00
b9d009b7a2 Merge pull request 'fix(export): take the sylpheed-formats dependency by path, not by tag' (#62) from fix/export-path-dep into main
Some checks failed
CI / Native — linux (push) Failing after 5m31s
CI / WASM — Web (push) Successful in 30m10s
CI / Formatting (push) Successful in 2m1s
Reviewed-on: #62
2026-09-20 15:09:50 +00:00
b0906f3ed6 Merge pull request 'chore(agents): restore evidence sharing after the asset purge' (#61) from chore/agent-evidence-sharing into main
Some checks failed
CI / Native — linux (push) Has been cancelled
CI / WASM — Web (push) Has been cancelled
CI / Formatting (push) Has been cancelled
Reviewed-on: #61
2026-09-20 15:09:43 +00:00
1fec20a2a3 fix(export): take the sylpheed-formats dependency by path, not by tag
Some checks failed
CI / Native — linux (pull_request) Failing after 5m12s
CI / WASM — Web (pull_request) Successful in 32m8s
CI / Formatting (pull_request) Successful in 1m31s
Removes the last reason this repository depends on its own history.

The pin was deliberate and carried its own exit condition, written into the
comment above it: "revert to the path dependency the day the tag is an ancestor
of `main`." Measured -- `formats-pin-2026-09-01` (e2630413) IS an ancestor of
`main` now, so the condition is met, and the cost the comment named goes away
with it: while the pin held, `sylpheed-cli` built from the workspace crate and
the exporter from the tag, so `tools/port/verify-screen` compared two eras
instead of detecting drift. They read one decoder again.

It also removes a failure mode nobody priced in. Depending on this repo by tag
is what made the #49 history rewrite break the build: every commit was replaced,
the locked rev vanished, and clean checkouts could not resolve it while the
rewriting machine kept working off its `~/.cargo/git` cache (PR #60). A path
dependency cannot fail that way. `Cargo.lock` now has ZERO references to
Sylpheed.git.

⚠️ This moves the exporter across a 243-file decoder change (8 467 insertions),
so it was gated on the full suite rather than a compile:

  45 suites / 377 passed / 0 failed / 14 ignored, cargo exit 0
  45 binaries launched, 45 reported  (a SIGKILLed suite prints no result line
  and would otherwise vanish from the tally)
  corpus report: PRESENT for disc, res3d and iso

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-20 14:05:52 +02:00
46ee0d7f78 chore(agents): restore evidence sharing after the asset purge
Some checks failed
CI / Native — linux (pull_request) Failing after 5m14s
CI / WASM — Web (pull_request) Successful in 36m12s
CI / Formatting (pull_request) Successful in 1m40s
Issue #49 removed game assets from git. It also, silently, removed the only
transport agents had for showing each other evidence: each agent works in its
OWN clone, so "commit the screenshot, the other one pulls it" was the mechanism,
and PROTOCOL.md's file table said so in as many words -- "evidence cited by a
finding -> git". That row sat directly above "🔴 Never commit game content",
which is how 76 MB accumulated: the two contradicted each other and the table
won, because it was the one that told you what to do.

WHAT REPLACES IT

  * one host directory, `Sylpheed/docs/re/captures/`, bind-mounted read-write
    into BOTH agents at /work/docs/re/captures. All three -- host, decoder,
    port -- see the same files live, every citation resolves, and nothing can
    reach git history. Read-write on purpose: showing each other a screenshot
    is the point.
  * PROTOCOL.md's table rewritten. Cited evidence -> present but never
    committed; derived measurements (csv/tsv/txt/log/json) -> still git, they
    are our numbers not game content; evidence that must cross MACHINES ->
    attached to the issue or PR, because a bare clone has no captures.

Verified, not assumed: container A wrote a .png there, a SEPARATE container B
read it back, the host saw it, `git status` reported 0 changes, and
`git check-ignore` named the rule.

THE CHECKER WAS RED ON EVERY CLEAN CHECKOUT

A fresh clone/worktree/CI has no captures, so it called all 134 citations
dangling and exited 1. A gate that is red before anyone changes anything is one
people learn to ignore -- the exact failure this file already carries a comment
about. It now distinguishes "no captures here" (expected, explains itself,
exit 0) from "these are missing" (real, exit 1, unchanged when assets ARE
present). Both paths tested.

ALSO
  * `sylph-decoder` no longer mounts `xenia-rs` -- retired repo, gone from disk,
    the mount pointed at nothing.
  * CONSOLIDATION.md closed: it still described captures as committed and the
    history fork as undecided. Both are settled.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-20 13:12:26 +02:00
c0a5840ce8 Merge pull request 'fix: re-lock the self-referencing git dep after the history rewrite' (#60) from fix/relock-after-history-rewrite into main
Some checks failed
CI / Native — linux (push) Failing after 3h1m17s
CI / WASM — Web (push) Successful in 35m42s
CI / Formatting (push) Successful in 2m7s
Reviewed-on: #60
2026-09-20 11:01:57 +00:00
4156cb6bd1 fix: re-lock the self-referencing git dep after the history rewrite
Some checks failed
CI / Native — linux (pull_request) Failing after 2h42m36s
CI / WASM — Web (pull_request) Successful in 33m28s
CI / Formatting (pull_request) Successful in 2m29s
`crates/sylpheed-export` depends on THIS repository by tag:

    sylpheed-formats = { git = "…/Sylpheed.git", tag = "formats-pin-2026-09-01" }

and `Cargo.lock` pinned it to commit `#1cd5b8b1`. The issue-#49 history rewrite
replaced every commit, so `1cd5b8b1` no longer exists on the remote and the tag
now dereferences to `e2630413`.

⚠️ The failure is invisible here: `~/.cargo/git` still has the old object, so
builds on the machine that did the rewrite keep working. A clean checkout --
CI, or the other desktop -- cannot resolve the locked rev at all. That is the
worst shape for a breakage, which is why this was measured from an empty
CARGO_HOME rather than trusted to a local build.

`CONSOLIDATION.md` called this dependency out as the hard blocker for the
rewrite. It was not re-checked before the push; this is the fix.

The dependency's SOURCE is unchanged -- `crates/sylpheed-formats` has tree
`55461e46` at both the old and the new commit, so the rewrite never touched it
and the build result is identical.

Verified:
  * remote tag peels to e2630413, matching the new lock
  * `cargo fetch --locked` from an EMPTY CARGO_HOME -> exit 0
  * `cargo check -p sylpheed-export --locked` -> exit 0

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-19 23:11:06 +02:00
e16556dc29 Merge pull request 'chore(re): stop committing game assets; captures stay local' (#59) from chore/captures-local-only into main
Some checks failed
CI / Native — linux (push) Failing after 6m55s
CI / WASM — Web (push) Failing after 6m24s
CI / Formatting (push) Successful in 1m8s
Reviewed-on: #59
2026-09-19 19:16:47 +00:00
d96b225e47 chore(re): stop committing game assets; captures stay local
Issue #49: the repos carry code, tooling and docs only.

Untracks 143 screenshots, 3 savegame blobs and `tools/re-capture/ob_digits.png`
(a digit-template sheet cut from game frames) -- 146 files, 76.4 MB. They stay
in the working tree and are gitignored, so the pages' relative links still
resolve where the captures exist and nothing ships.

Derived measurements (csv/tsv/txt/log/json/jsonl/npy) are our own numbers, not
game content, and stay tracked -- they are what most claims rest on.

`check-capture-citations` had its contract inverted, and it is the half worth
reading:

  * presence now comes from the WORKING TREE, not `git ls-files`. The assets are
    deliberately untracked, so asking the index would report every screenshot as
    missing and fail all 203 citations.
  * a NEW failure: a game asset that IS tracked. A screenshot that sneaks back
    in is invisible in review -- a binary shows as "Bin 0 -> 1234567 bytes" --
    and is permanent once merged, since removing it later needs a history
    rewrite. So that half has to be loud.

Verified:
  * selftest 8/8, including the new rule
  * scan: 212 present, 212 cited, 0 dangling, 0 tracked  -> exit 0
  * force-add one PNG -> "game assets TRACKED: 1", exit 1, selftest red

⚠️ This does NOT remove the blobs from history; a clone still fetches them.
That needs a filter-repo rewrite and a force-push, which is a separate,
human-run step.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-19 21:03:46 +02:00
4c1e15b818 Merge pull request 'fix(test): open sound.pak once, not once per call' (#58) from fix/slb-suite-one-archive into main
Reviewed-on: #58
2026-09-19 18:48:28 +00:00
9a8746d380 Merge pull request 'fix(ci): run the container as the invoking user, not root' (#57) from fix/ci-run-file-ownership into main
Reviewed-on: #57
2026-09-19 18:48:21 +00:00
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
2f39c8826e fix(test): open sound.pak once, not once per call
`slb_leading_segment_disc` was SIGKILLed by the OOM killer in `docker/ci/run`
at its 7 GB cap, so the documented 45/377 baseline did not reproduce on a 15 GB
box.

`PakArchive` holds the whole concatenated payload in memory and `sound.pak` is
1.01 GB (sound.p00-.p04). `bank()` and `bank_named()` opened it on every call --
inside loops -- and five tests opened their own besides, ~26 opens in all. With
cargo's default thread count that is ~6.1 GB of archive in flight against a
7 GB cap with `--memory-swap` equal to `--memory`, so there is no swap to
absorb it.

The archive is immutable once open and every accessor takes `&self`, so one
`OnceLock` instance is equivalent to N private ones at 1/N the memory.

⚠️ The failure mode is worth knowing: a SIGKILLed suite prints no
`test result:` line at all, so it disappears from a scraped tally instead of
failing visibly. The run still reported "0 failed" -- true, and useless. Check
cargo's exit code (101), not the tally.

Measured in the capped container, 7 GB, default threads:
  * before: SIGKILL (signal 9), 0 of 10 tests reported
  * after : 10 passed in 3.17s
  * (single-threaded before the fix: 10 passed in 22.64s -- the fix is also
     ~7x faster, because it no longer re-reads 1 GB from disc 26 times)
  * cargo fmt --check clean; cargo clippy --tests -D warnings clean

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-19 16:59:10 +02:00
4a8f1221b2 fix(ci): run the container as the invoking user, not root
Docker on the dev boxes is rootful, so without `--user` every byte the build
writes into the bind-mounted repo is owned by root and the user needs `sudo` to
delete their own artifacts. This is not hypothetical: `export/` in a working
tree held 227 root-owned paths (149 MB) from earlier runs, and the `sylpheed.db`
regen in the workspace CLAUDE.md writes straight into /work, so it lands
root-owned every time.

The catch is that the daemon creates a named volume root-owned, so a `--user`
container cannot write /cargo or /target at all. So take ownership of both
volumes first -- once, and only when it is actually wrong, since a recursive
chown across a ~36 GB target volume is not something to repeat per invocation.
Both are sampled, not just one, because an older run can leave them drifted.

Volume names become overridable (SYLPH_CI_CARGO_VOL / SYLPH_CI_TARGET_VOL),
which is what let the chown path be tested without touching the real caches.

Placed above the corpus-mount block so it does not collide with #53.

Measured, not assumed:
  * fresh root-owned volumes  -> chowns once, then writes as uid 1000
  * second run                -> no chown, correctly cached
  * `cargo check -p sylpheed-ppc` through the runner -> passes, exit 0
  * a file touched in /work   -> owned fabi:fabi, removable without sudo

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-18 21:30:29 +02: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