Replaces the "Synthesized empty file" stub for cache:/* paths with a
real host-FS HostPathDevice-style mount. Each KernelState gets a fresh
per-process tmpdir under /tmp/xenia-rs-cache-<pid>-<id>/ which is
cleared on init for lockstep determinism (mirrors canary's
xenia_main.cc:649 RegisterSymbolicLink("cache:", "\\CACHE") +
HostPathDevice in xenia-canary/src/xenia/vfs/devices/host_path_device.cc).
NtCreateFile now honours create_disposition for cache: paths:
FILE_OPEN -> NOT_FOUND if missing
FILE_CREATE -> NAME_COLLISION if present
FILE_OPEN_IF -> open or create
FILE_OVERWRITE_IF -> create or truncate
FILE_OVERWRITE -> NOT_FOUND if missing, else truncate
FILE_SUPERSEDE -> create or truncate
NtReadFile / NtWriteFile / NtSetInformationFile (XFileEndOfFileInformation)
/ NtQueryInformationFile / NtQueryFullAttributesFile route through
std::fs against the per-handle host_path; non-cache paths keep their
legacy semantics (read-only disc image, synth-empty stubs).
Verified by audit-037 cascade:
- sub_82459D18 (cache-miss restore): 0 fires (was firing constantly)
- sub_8245D230 (resize/zero-fill): 0 fires (was firing constantly)
- 105+ real cache-file writes per 500M run; 4+ MB of game data persisting
to disk per boot; cache:/recent, cache:/access, cache:/d4ea*.tmp, etc.
- Lockstep deterministic at instructions=100000004 / imports=987485
across 3+ reruns (digest shifted as expected; goldens re-baselined).
- swaps=2 plateau still in place; cluster L1 unactivated. Cascade
dimension D (cluster activation) — UNKNOWN, no L1 fires.
Tests 640 -> 645 (+5 cache-specific unit tests; full workspace green).
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Sylpheed regression goldens
These JSON files anchor xenia-rs check digest output for Project Sylpheed.
Files
| File | -n | Mode | Captures |
|---|---|---|---|
sylpheed_n2m.json |
2_000_000 | full digest | early boot (swaps=0, no rendering) |
sylpheed_n50m.json |
50_000_000 | stable-digest | first VdSwap pair (swaps=2 post-Phase-A) |
Stable-digest mode
sylpheed_n50m.json is captured with --stable-digest, which omits
timing-sensitive counters: packets (±2–8% lockstep noise from a GPU thread
race), resolves, interrupts_delivered, interrupts_dropped,
texture_decodes. The remaining fields are byte-identical across repeated
lockstep runs at a fixed -n.
sylpheed_n2m.json predates the stable-digest flag and uses full-digest
compare. It still works because at -n 2M the GPU pipeline has not produced any
packets yet — packets=0 is trivially deterministic.
Circularity hazard
Per ORACBUG-001/002/003, these goldens were captured by running the same code
they validate. They detect regression from a known-good snapshot, not
correctness. When a planned fix intentionally moves the digest (e.g. a
shader fix landing draws > 0 for the first time), re-baseline the golden as
a separate commit and reference the audit ID in the message.
Re-baselining
cargo build --release -p xenia-app
target/release/xenia-rs check \
"$SYLPHEED_ISO" \
-n 50000000 \
--stable-digest \
--out crates/xenia-app/tests/golden/sylpheed_n50m.json
Running the goldens
cargo test --release -p xenia-app --test sylpheed_oracles -- --ignored --nocapture
The tests are #[ignore]-gated because each run takes a few seconds, which is
unacceptable in the default cargo test cycle. The ISO path defaults to the
contributor's local ~/RE Project Sylpheed/Project Sylpheed*.iso and can be
overridden via SYLPHEED_ISO=/path/to/sylpheed.iso.
n4b canonical-invocation regression anchor (deferred)
The audit's recommended next sprint also called for a sylpheed_n4b.json
golden capturing the canonical reference invocation
xenia-rs check sylpheed.iso -n 4_000_000_000 --parallel --reservations-table.
This is deferred because:
- The
--parallel --reservations-tablecombination is empirically pathologically slow at -n 100M (>32 min per run per the audit memory). At -n 4B the run cost is many hours, not the single-session-friendly 5–15 min the original plan estimated. - Each phase that intentionally moves rendering counters (C, D, E, F) would need a re-baseline of n4b — a significant time cost compounding over the sprint.
Once the renderer-unblock phases (C+D+E) land and draws > 0 is confirmed at
-n 100M lockstep, an n4b artifact may be captured one-shot and stored under
audit-runs/post-fix/ (not as a test golden) as a manual regression anchor for
the canonical invocation.