Files
xenia-rs/migration/claude-memory/MEMORY.md
MechaCat02 e6d43a23ac chore: add migration/ bundle for cross-machine setup
Bundles state that lives OUTSIDE the xenia-rs repo so a fresh clone on
another machine can be brought up to identical configuration via
migration/setup.sh:

  - claude-memory/             ~/.claude/projects/-home-fabi-RE-Project-Sylpheed/memory/
                               (103 files, 1.1 MB - MEMORY.md + every
                                project_xenia_rs_*.md from audits
                                addis_signext through audit-058)
  - project-root/dot-claude/   <project-root>/.claude/settings.json
                               (Stop hook + permissions)
  - project-root/ppc-manual/   <project-root>/ppc-manual/
                               (PowerPC reference docs, 397 files, 3.7 MB)
  - project-root/run-canary.sh <project-root>/run-canary.sh
  - README.md                  Human-readable setup checklist
  - setup.sh                   Idempotent installer (also reclones
                               xenia-canary at pinned HEAD 6de80dffe)
  - MANIFEST.md                Per-file mapping + per-file-not-bundled
                               restoration recipe

Excluded from bundle (not shippable via git):
  - Sylpheed ISO (7.8 GB; copyright; manual copy required)
  - sylpheed.db (395 MB; regenerable from XEX via analysis tooling)
  - target/ build artifacts (rebuild on target)
  - audit-runs probe firehoses (.log/.stdout/.stderr ~11 GB; rerun if needed)
  - audit-runs memory dumps (.bin ~4.5 GB; rerun audit-026/027/029 if needed)
  - xenia-canary checkout (setup.sh reclones from
    git.mc02.dev/fabi/Xenia-Canary.git at HEAD 6de80dffe)

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-10 21:38:38 +02:00

106 lines
96 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Memory Index
- [audit_058_sub825070F0_activation](project_xenia_rs_audit_058_sub825070F0_activation_2026_05_10.md) — Canary fires sub_825070F0 1× after `DiscImageDevice::ResolvePath(\\dat\\movie)`. Static caller ladder (6 levels: sub_824F7800 ← sub_824F7CD0 ← sub_824F8398 ← sub_821B55D8 ← sub_821B6DF4 [top]). ALL 6 fire 0× in ours. Break is NOT CRT-fnptr-array — it's the AUDIT-049 main-thread wedge (handle 0x12A4 wait at 0x824ac578) blocking the entire post-intro phase. Vtables 0x8200A208/0x8200A928 have **zero vptr_writes in DB** — writer ctor is computed-store-only OR in unreachability island. Confirms AUDIT-050 half-bootstrap: vtable-writer subset dead. AUDIT-059: pivot to unblocking the wedge (049+057 unified γ-investigation), not chasing caller-ladder further.
- [audit_057_thread_gap](project_xenia_rs_audit_057_thread_gap_2026_05_10.md) — Canary 23 thread-spawns / ours 10 = **13 missing**. 8 distinct missing-thread spawners. **Top: sub_825070F0** (4 missing, initializes 4 workers w/ shared ctx 0xBCE25340, entries 0x82506528/58/88/B8). **11 of 13** from spawners that don't fire at all in ours — same audit-050 CRT-fnptr-array unreachability. sub_821C4EB0 fires (1×) but early-returns (audit-056); sub_821746B0 fires 1× / should spawn 2. AUDIT-058: probe sub_825070F0 activation chain in canary, find fnptr-array entry ours doesn't enumerate. Cascade D 10-20% (multiple independent gaps).
- [audit_056_producer_trace](project_xenia_rs_audit_056_producer_trace_2026_05_10.md) — LR distribution at sub_82452DC0: canary 45/60s vs ours 14/26s (3.21× ratio). **Two CANARY-ONLY divergence introducers**: (a) sub_821C4EB0 calls sub_821CEDF8 5× in canary, 0× in ours despite IDENTICAL caller-LR — early-exit somewhere in +0x44..+0xE0; (b) sub_824AFF88 thread-trampoline fires 5× canary / 0× ours — **12 vs 30 XThread count gap** (18 missing threads). 3.0× thread-count ratio matches 3.21× throughput ratio. AUDIT-057: probe sub_82174828 + post-bl PCs inside sub_821C4EB0 (`0x821C4F2C/0x821C5014/0x821C5048`); fallback = audit which 18 thread-creates fail to land. Wine canary not yet justified.
- [audit_055_subB078_internal](project_xenia_rs_audit_055_subB078_internal_2026_05_10.md) — Probed sub_8245B078's body with cache override: BODY EXECUTES CORRECTLY (internal call parity ~98%, sub_8217FA08 2449/2411). Divergence is UPSTREAM — sub_82452DC0 fires 5.6× less in ours. Sharpest specific divergence: sub_8217FA08 from LR=0x82455E60 (=sub_82455DF0+0x70), canary 20 / ours 0. Bug class refined: **δ-throughput** (producer of work items doesn't fire at canary rate). AUDIT-056 recommendation: probe sub_82452DC0 entry, aggregate LR distribution upward.
- [audit_054_vfs_layout_landed](project_xenia_rs_audit_054_vfs_layout_landed_2026_05_10.md) — **TRACK A LANDED**: commits `2a8ff95` (74 LOC) + `ac2f89a` (golden re-baseline). FILE_DIRECTORY_FILE bit threaded through nt_create_file → open_cache_file. `cache:\<HASH>` with disp=2 opts=0x4021 → mkdir; leaf paths with opts=0x4020 → file. Closes ζ-class layout aliasing. Track B persistent cache OPT-IN via `XENIA_CACHE_PERSIST=1`; default keeps AUDIT-038 wipe for lockstep. Cascade A/B confirmed via AUDIT-053 Phase 1 (canary cache override); **cascade C/D STILL FAIL** — cache is necessary but not sufficient. Warm-start regression (cxx_throw=10) when persistent enabled — our cold-start halts at swaps=1 producing half-baked .tmp journals. Next: probe sub_8245B078 internal body to find next gate.
- [audit_053_cache_layout_bug](project_xenia_rs_audit_053_cache_layout_bug_2026_05_10.md) — Phase 1 confirms AUDIT-052 gate hypothesis (PCs `0x82452E30`/`0x8245B078`/`0x8245AD94` go 0→6 with canary cache override; cascade A/B PASS) BUT cascade C/D FAIL (NtSetEvent 68→63, VdSwap=1 unchanged). Phase 2 permanent fix REVERTED — warm-start regression from VFS layout aliasing: `open_cache_file` treats all `NtCreateFile` as files, but `cache:\d4ea4615 disp=CREATE` is meant as a DIRECTORY. 0-byte file blocks hierarchical creates. AUDIT-038 wipe masked this for 14 audits. **15th reading-error class ζ**: VFS layout aliasing. AUDIT-054 = honor `FILE_DIRECTORY_FILE` bit + retry persistent cache.
- [audit_052_cache_root_cause](project_xenia_rs_audit_052_cache_root_cause_2026_05_10.md) — **🔥 ROOT CAUSE FOUND**: AUDIT-051 struct hypothesis REFUTED (struct bit-identical canary/ours). `[r3+0]`/`[r3+4]` are halves of a hash key formatted into `cache:\<HASH1>\<X>\<HASH2>` paths. Real bug: `NtQueryFullAttributesFile` returns -1 for `cache:\*` in ours because **AUDIT-038's per-boot tmpdir cache is WIPED every startup**. Canary's `~/.local/share/Xenia/cache/` is persistent + pre-populated (d4ea4615/e/46ee8ca etc — game-built shader/PSO/material caches). **Reading-error class #15**: AUDIT-038 "missing-or-stale ≡ fresh" assumption invalidated. Fix = persistent cache (`crates/xenia-kernel/src/state.rs:387-398`). Cascade A/B/C HIGH; D 30-40% (cache may not be only gate).
- [audit_051_work_submitter_trace](project_xenia_rs_audit_051_work_submitter_trace_2026_05_10.md) — **CONCRETE DIVERGENCE FOUND**: `sub_8245B078` fires 18× canary / 0× ours. Gate at `sub_82452DC0+0x78` (PC `0x82452E2C beq cr6, 0x82452E88`) controlled by `sub_8245B000` returning 1 iff `[r3+0]≠0 AND [r3+4]≠0` for 80-byte stack-local struct at `r31+96`. Ours has one of those fields NULL — missing-population. Struct upstream-written by `sub_8245AE50`/`sub_82452068`/`sub_82452200` (fire in both, ours doesn't write right fields). **Single root cause** for AUDIT-047's 4 wedges (0x10A0/0x10A4/0x1530/0x1534) via `sub_8245AD00` + plausibly tid=13's stall on 0x1288. Direct-bl divergence (NOT vtable) — at this level. AUDIT-052: dump struct at PC `0x82452E1C` in both engines, find NULL field, identify missing writer. Cascade D 20-30% (5 vtable dispatches downstream might re-hit island).
- [audit_050_reframe](project_xenia_rs_audit_050_reframe_2026_05_10.md) — **🔥 METHODOLOGICAL REFRAME (2026-05-10)**: 11 prior audits' "audit-009 cluster unreachable" claim is STATIC-ANALYZER ARTIFACT. `--ctor-probe` shows CRT driver `sub_824ACB38` (called from entry_point) iterates 0x82870xxx fnptr arrays (557 slots, 82 non-NULL); `sub_8280E148` (RegisterToFactory<silph::GamePart_Title>) fires at cycle 1.4M; tid=13 chain (sub_821C4EB0/sub_821CC3F8/sub_821CBA08/sub_821CB030) fires; **work-submitter sub_82452DC0 fires on tid=13 at cycle 8127**. Real bug = γ missing-signaler inside sub_82452DC0's descendant tree. **14th reading-error class**: BFS-only insufficient when binary uses CRT-driven fnptr arrays. **Angle B (-n 5B) DEFINITIVELY FALSIFIED** (bit-identical to 500M). Cluster is HALF-bootstrapped (worker-thread subset live, vtable-writer subset dead) — virtual dispatches hit garbage. Wine canary no longer only route. Top angle: probe sub_82452DC0's 9 direct targets + 1 ind_call (`0x8245AE50,0x82452068,0x82452200,0x8245B000,0x8245B078,0x82454A40,0x82452AB8,0x82454918,0x82452EC4`) in both engines, find divergent branch. Cascade D=draws>0 YES POSSIBLE 30-50%.
- [audit_049_tid1_stall_0x1280](project_xenia_rs_audit_049_tid1_stall_2026_05_10.md) — Post-AUDIT-032 wedge: handle 0x1280 = **Thread handle** for tid=13 (not event); tid=1 is doing thread-join. Real sub-stall: tid=13 waits INFINITE on event 0x1288 (created at `sub_821CB030+0x128`, in audit-009 cluster front-end UI). 5 NtSetEvent callers in worker cluster `0x82450000-0x8245C000`: only `sub_82452DC0` (work-submitter) statically reachable; rest unreachable. tid=13 create-chain: `sub_821748F0``sub_821C4EB0(UImpl@GamePart_Title@silph)``sub_821CC3F8(AVGamePart_Title)``sub_821CBA08``sub_821CB030`. All in audit-009 island. Discipline 3/5 PASS, D=draws>0 NO. **5th consecutive audit (044/045/046/047/049) converging on same unreachability island.** Path 1 (Wine canary) now justified per user's "meaningful progress" framing.
- [audit_048_audio_host_pump_fix](project_xenia_rs_audit_048_audio_host_pump_fix_2026_05_10.md) — **PATH 2 LANDED in working tree (not committed)**. AUDIT-032 audio fix: dedicated audio worker thread per client, 75 net LOC across 4 files. Cascade A/B/D ✅ — tid=9/10 unblock from `0x828a3254`/`0x828a3230`, KeReleaseSemaphore 0→1, xaudio.callback.delivered=1. swaps 2→1 (degenerate splash lost). draws 0→0 (expected — audio≠renderer per AUDIT-032). **Boot phase advanced**: NtWaitForSingleObjectEx 1.4M→30, NEW StfsCreateDevice/XamContent*/ExCreateThread×10/XeCryptSha/etc. New stall: tid=1 main Blocked on handle 0x1280 at pc=0x824ac578. Tests pass (kernel 127/127, app 5/5 non-ignored). Lockstep goldens deferred (will drift).
- [autonomous_run_synthesis](project_xenia_rs_autonomous_run_synthesis_2026_05_10.md) — **AUTONOMOUS-MODE SYNTHESIS (2026-05-10, sessions 5-8 of 10 used; 9-10 RESERVED)**: 4 audits (044-047) refuted 4 hypotheses; no fix landed; no draws cascade; methodological floor reached within Linux Debug + READ-ONLY discipline. Cluster activation past Linux Debug horizon. Best near-reachable signaler `sub_8245AD00` covers 4 wedges but its callers sit in audit-009 unreachability island. KeReleaseSemaphore 0 ours / 73,914 canary = AUDIT-032 audio host-pump gap (already named). Three paths forward (user pick): (1) Wine/Lutris canary build for new oracle [HIGH effort/reward], (2) audit-032 audio host-pump fix [MEDIUM effort, D≠draws], (3) guest-thread injection [HIGH risk]. Sessions 9-10 held in reserve.
- [audit_047_gamma_wedges](project_xenia_rs_audit_047_gamma_wedges_2026_05_10.md) — 10 NO_SIGNALS handles inventoried + XAudio. `sub_8245AD00` reachable, covers 4 wedges (0x10A0/0x10A4/0x1530/0x1534), but callers in audit-009 island. Of 125 signal-source fns, only 2 statically-reachable + near-wedge: sub_8245AD00, sub_82450218. KeReleaseSemaphore 0/73914 canary divergence = known AUDIT-032 audio host-pump (PC 0x824D229C, r3=0x828A3230). Discipline 3/5 PASS, D=draws>0 NO. γ-wedge convergence: all hit audit-009 unreachability island.
- [audit_046_loop_exit](project_xenia_rs_audit_046_loop_exit_2026_05_10.md) — REFUTES audit-035 slot-pointer-region divergence as causal AND audit-034 "canary 3.75/5 vs ours 5/5" iter divergence. Both engines run 5/5 iters at sub_82450720+0x160..+0x1F4, fall through to no-match exit. Slot-table region split (canary 0xBC3xxxxx vs ours 0x4024xxxx) is REAL but BEHAVIORALLY INERT — predicate compares within each engine's own heap region. **Drop sub_82450720 chain as critical-path target.** Reading-error #13 (mid-block PC unprobeable in ours) reconfirmed; workaround via post-bne block-entry PC `0x82450908`. Recommended AUDIT-047: γ-cluster handle wedges per audit-042 (handles `0x10A0+0x10A4`, `0x12AC`, `0x1004`, etc).
- [audit_045_cluster_ctor_probe](project_xenia_rs_audit_045_cluster_ctor_probe_2026_05_10.md) — REFUTES audit-044 ctor hypothesis: `0x8228FAC8` (vptr write) + `0x8228F858` (ctor entry) fire **0× in CANARY too** at 50s. Cluster genuinely not activated at this horizon either engine — RECONCILE-B (Linux Vulkan/XCB) blocks before front-end-UI activation. T6 (audit-033 LR `0x82172BF8`) fires in both — gateway chain `entry→sub_8216EA68→sub_822F1AA8→sub_82172BA0` runs; cluster-ctor branch off it doesn't. **13th reading-error class**: probe-firing-granularity — ours `--pc-probe` fires only at basic-block entry, canary `--log_lr_on_pc` per-instruction; mid-block PCs systematically give ours=0. Recommended AUDIT-046: probe loop-exit predicate `0x82450904` (audit-034 5/5 vs 3.75/5 divergence). DB caveat: `v_call_graph` uses `xrefs.source`; prefer `xrefs.source_func` for caller-set queries.
- [audit_044_m55_cluster_survey](project_xenia_rs_audit_044_m55_cluster_survey_2026_05_09.md) — M5.5 lifts cluster `0x82285000-0x82294000` from 0/321 static-reach to 41/321 indirect (12.8%); only 4 vtable methods are entries. Cluster's 6 vptr-writer constructors all dead. Top probe: `sub_8228F858` writer at `0x8228FAC8` (vtable `0x820a9c28` ctor). Audit-033 chain ends genuinely at `sub_821CECF0`/`sub_821C4988` (7-hop BFS finds no ancestor). M5.5 `cand_count≤10` actionable; `=203` noise.
- [project_xenia_rs_audit_043_record_zero_offset_2026_05_09.md](project_xenia_rs_audit_043_record_zero_offset_2026_05_09.md) — **🎯 KRNBUG-AUDIT-043 (2026-05-09, READ-ONLY, master `d8766c6` tests 645)**: identifies writer of +0x00 at "records" 0x40542300/40/400/4C0. Mem-watch (-n 500M) → writer = memcpy `pc=0x825F1080 lr=0x825ED608` called from `std::basic_string::reserve_then_assign sub_8216E138+0xC8`. **Records are not records** — they are 64-byte slots in Sylpheed's pool allocator (`sub_821505D8` allocs 58MB via `sub_824A8858`; `sub_82152728` chains 64-byte free-list over 1.25MB; bucket sizes 4/16/32/64/96/128/160/192/256). Audit-030 patch reapplied; canary probe at `pc=0x825F1080`: 94,945 fires/25s, **zero hit `0x40542xxx`**, top destinations `0x705Dxxxx`/`0xBC36xxxx` (canary's pool base = `0xBC32C880` per pool-init probe). **Audit-039's "0xF80000B8 vs game" comparison is a VA-equality fallacy**: same guest VA backs different live data because allocator returns different host VAs in canary vs ours. Bug class **ε (host-allocator address-space divergence)** — NOT a guest-write bug, NO missing/wrong write at +0x00 in our impl. **Reading-error ledger 12th entry**: VA-equality fallacy across emulators — comparing memory at identical guest VAs assumes both allocators return same VA for same logical alloc; Sylpheed's pool factory makes this assumption false in general. **Recommended audit-044**: drop "record at 0x40542300+" line entirely; pivot to audit-042's actually-stalled-handle plan (0x10A0+0x10A4 worker pair, 0x12AC sema, 0x1004 event/manual). Bug class for next = γ (missing signaler). Trace `audit-runs/audit-043-record-zero-offset/{mem-watch.log, mem-watch.stdout, canary-825f1080-traces.txt.gz, audit-043-canary-poolinit.log}`. Discipline 5/5 PASS; canary patch reverted clean; xenia-rs source unmodified.
- [project_xenia_rs_audit_042_handle_lifecycle_2026_05_09.md](project_xenia_rs_audit_042_handle_lifecycle_2026_05_09.md) — **🎯 KRNBUG-AUDIT-042 (2026-05-09, READ-ONLY, master `d8766c6` tests 645)**: disambiguates audit-041 root cause for handle 0x1454 missed wakeup. Re-applied audit-030 canary patch (30 LOC, reverted clean canary `6de80dffe`). Method: ours `--trace-handles-focus=0x1454` (existing audit.rs); canary `--log_lr_on_pc=0x8284DF1C` (NtCreateEvent ord 209) + cross-ref audit-041 log. **STRUCTURAL FINDING**: `KernelState::alloc_handle` (state.rs:588) is **monotonic atomic counter** `fetch_add(4)` from 0x1000 — **bump-only, NO recycling, structurally impossible**. `nt_close` removes object but never returns ID to pool. **Lifecycle of 0x1454 in ours** (2 reruns identical): created tid=13 lr=0x824a9f6c (NtCreateEvent, kind=Event/Manual), waited tid=13 lr=0x824ac578 (do_wait_single), signaled tid=5 lr=0x824aa304 (NtSetEvent), wake fired (wake_eligible_waiters/auto). Final: waiters=0 signaled=true wakes=1 — **fully consumed, NOT stuck**. Created stack frames sub_822DFC74←sub_822E0344←sub_822D2CA4←sub_822DE768←sub_821C4B1C. **Lifecycle of canary F80000CC family**: 5+ Added/Removed/Added cycles in 30s (XObject→XEvent→XEvent→...). **Slab/free-list allocator**: F8000098 reused 130×, F80000D0 95×, F80000DC 71× per 30s window. **VERDICT: ROOT CAUSE NOT (A) HANDLE-RECYCLING** — recycling structurally impossible in ours; signal lands on same KEVENT object the wait registered for. **Audit-041's premise provisionally falsified for 0x1454**: audit-041 inferred stall from `--lr-trace` "7 pre-bl, 6 post-bl" but ran `--quiet` so end-of-run dump was suppressed; post-bl miss explained by KeWaitForSingleObject's wake-side context-restore bypassing post-bl PC. **Real wedges** (this run's stalled handles): `0x1004` (tid=11), `0x1020` (tid=3), `0x1040` (tid=5), `0x1544` (tid=17), `0x1578` (tid=19), `0x12ac` (tid=14,15), `0x10a0+0x10a4` (tid=6) — all `<NO_SIGNALS_DESPITE_WAITS>`. **Bug class**: δ-namespace + δ-wakeup BOTH RULED OUT for 0x1454; wedge migrates to **γ (missing-signaler)** on different handle set. Sharp 4-dim cascade prediction (audit-043 fix on real handle): A=signal_attempts 0→≥1, B=stalled tid Blocked→Ready, C=`<NO_SIGNALS>` count drops ≥2, D=swaps>2 OR draws>0 (low probability — γ-cluster plateau). **Recommended audit-043**: pivot to (1) `0x10a0+0x10a4` Event+Sema worker pair on tid=6, (2) `0x12ac` Sema with 2 waiters, (3) `0x1004` Event/Manual on tid=11. Trace `audit-runs/audit-042-handle-lifecycle/{probe.log, probe-run2.log, canary-create-0x8284DF1C.log}` (~11.5 MB). Discipline gate 5/5 PASS. xenia-rs source unmodified, no commit.
- [project_xenia_rs_audit_041_wait_site_2026_05_09.md](project_xenia_rs_audit_041_wait_site_2026_05_09.md) — **🎯 KRNBUG-AUDIT-041 (2026-05-09, READ-ONLY, master `d8766c6` tests 645)**: wait-site signaler determination. Re-applied audit-030 patch (30 LOC, reverted clean canary `6de80dffe`). Wait at PC `0x822DFC34 bl 0x824AA330` (KeWaitForSingleObject INFINITE) inside sub_822DFBC8 — direct caller of audit-040's NtCreateEvent. **Wait completion (canary 30s vs ours 500M-instr)**: canary 9 bl + 9 post-bl = **100%**; ours 7 pre-bl (probe at `bl` elided in HIR; pre-bl `0x822DFC30 addi r4,r0,-1` is fair) + 6 post-bl = **6/7 = 85%**. **7th wait stalls on handle `0x00001454`** (audit-040 family) at cycle 48,849. **Outcome (i) confirmed**: handle-namespace divergence is **load-bearing**. **Signaler = NtSetEvent** (xboxkrnl ord 246, thunk 0x8284DF5C): canary 9245 fires, **2 on F80000CC/C0** with LR=0x824AA304 (wrapper sub_824AA2F0, 89 callers). KeSetEvent 20588 fires, 0 on those handles (takes KEVENT*). **Cross-check**: ours's NtSetEvent fires **1× on r3=0x1454** at cycle 3,519,453 (AFTER stall) — **signaler IS firing in ours, but waiter not woken**. Bug class refined to **δ-namespace + δ-wakeup composite**: signal-before-wait race ruled out (signal is later); candidate causes = (a) handle slot 0x1454 recycled between create-epochs so signal hits different KEVENT than wait registered for, OR (b) KeSetEvent/wait-queue plumbing has missed-wake. **Recommended audit-042** (two-track): (1) probe sub_824AA2F0 entry filtering r3=0x1454 to name signaler caller chain; (2) dump our handle table state for slot 0x1454 at cycle 48,849 (wait) vs 3,519,453 (signal) — if different KEVENT pointers → handle aliasing in `xenia_kernel::handle_table`; if same → wait-queue bug. Both fixes ≤60 LOC. xenia-rs HEAD `d8766c6` unchanged. Trace `audit-runs/audit-041-wait-site/`.
- [project_xenia_rs_audit_040_record_ctor_inputs_2026_05_09.md](project_xenia_rs_audit_040_record_ctor_inputs_2026_05_09.md) — **🎯 KRNBUG-AUDIT-040 (2026-05-09, READ-ONLY, master `d8766c6` tests 645)**: identified divergent INPUT to sub_8244FC90 record ctor. Re-applied audit-030 patch + extended TrapLogLR (+56 LOC, reverted clean). Canary 33 fires at 30s; ours 8 fires via `--lr-trace`. Calling conv: r3=dest, **r4=28-byte source struct ptr (memcpy'd to dest+0x3C)**, r5=2nd this, r6/r7=scalars. LR=`0x82450440` (=sub_824503A0+0xA0) IDENTICAL in both. **Divergent dword**: `*r4+0` = canary `0xF80000DC` vs ours `0x00001454`**NtCreateEvent OUT handle** (xboxkrnl ord 209 thunk `0x8284DF1C`). Upstream chain: sub_8244FC90 ← sub_824503A0 ← sub_824528A8 ← sub_822DFBC8 ← **sub_822DFC74** (which calls sub_824A9F18→NtCreateEvent at +0xC8C, stores result at `[r31+44]` then dispatches via vtable[7]). Both runtimes call NtCreateEvent 395× successfully — divergence is **handle-namespace cosmetics** (canary `0xF8000xxx` XObject-kernel-region vs ours `0x10xx-0x14xx` KernelState-handle-table-id). **Bug class δ-namespace** (handle representation; benign unless downstream interprets bits semantically). **AUDIT-037 framing partial-correction**: the inline filename text lives at dest record's `+0x40+` (written by sibling callees `sub_822F8A70`/`sub_82150030` AFTER sub_8244FC90 returns), NOT in the 28-byte memcpy region. **Recommended audit-041**: probe `sub_822DFC34` (`bl 0x824AA330` waitsite) in BOTH runtimes — if canary's wait completes but ours doesn't = signaler-missing bug. If both stall = handle namespace finding is benign and pivot to RDX search-criteria producer. Trace `audit-runs/audit-040-record-ctor-inputs/{canary-0x8244FC90.log, ours-lrtrace.jsonl, ours-dump.log, canary-patch.diff}`. xenia-canary HEAD `6de80dffe` clean; xenia-rs HEAD `d8766c6` unchanged.
- [project_xenia_rs_audit_039_track_2_extended_canary_2026_05_09.md](project_xenia_rs_audit_039_track_2_extended_canary_2026_05_09.md) — **🎯 AUDIT-039 TRACK 2 (2026-05-09, READ-ONLY, canary `6de80dffe`, xenia-rs `d8766c6`)**: extended-horizon canary trace for cluster activation. Re-applied audit-030 `--log_lr_on_pc` patch (30 LOC, 4 files); reverted clean. Probed 3 Tier-2 PCs serially (audit-031 single-PC constraint), 15-min wallclock each: **0x82172524 = 0 fires / 22 min**, **0x82175810 = 0 fires / 15 min**, **0x8217EB78 = 0 fires / 15 min**. ~52 min canary CPU total. Steady-state mix 240k KeReleaseSemaphore + 75k VdRetrainEDRAM/XamInputGetCapabilities loop in all 3. Per task brief Step 3 outcome **(ii)**: cluster activation past Linux Debug's reach in 15 min — skipped Tier-1 (3 PCs) + L1 (6 PCs) per compressed plan (consequences of Tier-2). Confirms+extends audit-034 Phase B (5 min, 0×) and VERIFY-A (35 sec, 0/12). RECONCILE-B host-presenter caveat dominates: Vulkan/XCB Linux fails to display intro video, front-end-UI state machine never advances past post-intro. **3 horizons (35 sec/5 min/15 min) all stop in same idle loop.** Sister Track 1's cascade-A verdict FAIL combined with this OUTCOME (ii): transformation-step (`RtlInitAnsiString`-driven filename externalization) IS missing AND cluster activation IS past Linux Debug reach — independent gates. **Recommended pivot B (static-only, M5.5 alias-aware vtable dispatch resolution)** first; pivot A (Lutris Windows canary instrumentation) as fallback. Trace `audit-runs/audit-039-track-2-extended-canary/canary-0x{82172524,82175810,8217EB78}.{log,err}`. Canary patch reverted, HEAD `6de80dffe` unchanged; xenia-rs HEAD `d8766c6` untouched, tests 645.
- [project_xenia_rs_audit_039_track_1_verify_2026_05_09.md](project_xenia_rs_audit_039_track_1_verify_2026_05_09.md) — **🎯 AUDIT-039 TRACK 1 (2026-05-09, READ-ONLY, master `d8766c6`)**: cascade dimension A verification post audit-038 cache fix. Probe sub_8228E498 = 0 fires (silenced by fix). Fallback `--dump-addr` 0x40542300/40/400/4C0 + extended 0x40542100..800. **VERDICT: FAIL** — 0x40542300 IDENTICAL to audit-037 pre-fix (inline "game:\\hidden\\Resource3D\\Common.xpr…", +0x20=0x7072005C "pr\\0\\\\" text bytes); 0x405424c0 has descriptor-shape pointers at +0x20=0x40541ED8 but **filename still inlined at +0x44** ("ptc_pack.xpr"). Canary records hold pointers (0xF80000B8 handle@+0, BC65xxx/BC36xxx sub-pointers); strings live on separate `RtlInitAnsiString`-allocated heap. Cache fix is correct hygiene (silenced sub_82459D18/sub_8245D230/0x82450904) but DID NOT externalize filenames into ANSI-string heap. **Bug class η record-layout divergence (audit-036) PERSISTS** — record-population transformation step is upstream/sibling of cache machinery, untouched by audit-038. Lockstep instr=500000019 stable, swaps=2. **Recommended next**: (A) trace `RtlInitAnsiString` callers vs canary to find missing `game:/dat:/cache:` prefix populator, (B) mem-watch +0x20 of 0x40542320 to capture writer PC+LR, (C) wait for sister Track 2's extended-horizon canary trace before declaring transformation-step missing, (D) KRNBUG entry on `RtlInitAnsiString` prefix branching. Trace `audit-runs/audit-039-track-1-verify/{probe-element,dump-extended}.{out,log}`. xenia-rs HEAD `d8766c6` unchanged.
- [project_xenia_rs_audit_036_vptr_deref_2026_05_09.md](project_xenia_rs_audit_036_vptr_deref_2026_05_09.md) — **🎯 KRNBUG-AUDIT-036 (2026-05-09, READ-ONLY, master `9028021`)**: hypothesis test of audit-035 narrative — captured `[[r3+0]+32]` at sub_8228E498/sub_82451E20+0x58 in BOTH runtimes. Canary patch 49 LOC (audit-030 base + 19-LOC TrapLogLR ext to deref `[r3+0]` + 64-byte struct dump); reverted clean. **Disasm correction**: sub_8228E498 is a deque iterator deref returning element_address (NOT vtable dispatcher); the `[+32]` deref happens in CALLER sub_82451E20 at PC 0x82451E78 reading the returned element's `[+0]` (key) then `[key+32]`. **Canary value `[[r3+0]+32]` = `0xBC65D018/D2D8/CFD8/D118/D198/D398`** — phys-heap pointers. **Ours value `[[r3+0]+32]` = `0x7072005C`** — mid-FILENAME-STRING text bytes ("pr\\0\\\\" from "...Common.xpr\\0\\..."). **VERDICT: REFUTED-AS-STATED** — ours's value is text not a heap pointer. **STRONGER finding**: records held by container have FUNDAMENTALLY DIFFERENT LAYOUTS. Canary's `[r3+0]=0xBC65D1C0` is a 16-dword pointer-bearing struct (handle@+0=0xF80000B8, sub-pointers@+32/+36/+44). Ours's `[r3+0]=0x40542300` is a struct STARTING WITH inline filename "game:\\hidden\\Resource3D\\Common.xpr\\0..." — offset 32 falls inside string text. Predicate `r28 == [[r3+0]+32]` compares stack pointers vs string bytes in ours (impossible match). Bug class **η — record-layout divergence (NEW class)**, distinct from audit-035's heap-region axis. **Recommendation: DO NOT proceed with physical-heap separation as audit-037** — even after heap-split, ours's records would still hold inline strings; predicate would still fail. **Audit-037 = identify the record populator** that builds container elements (mem-watch on `0x40542300+0x20` → writer PC + LR, walk caller chain, compare to canary's resource-loader). xenia-rs HEAD `9028021` unchanged. Tests 640. Trace `audit-runs/audit-036-vptr-deref/{canary.log, canary-callsite.log, ours.log, ours-exit.log, ours-final.log}`.
- [project_xenia_rs_audit_035_slot_table_2026_05_08.md](project_xenia_rs_audit_035_slot_table_2026_05_08.md) — **🎯 KRNBUG-AUDIT-035 (2026-05-09, READ-ONLY, master `9028021`)**: re-applied audit-030 patch + extended TrapLogLR (+19 LOC, total 49) to dump 5×20-byte slot table from r3+108 at sub_82450720 entry. Disasm verified r26+108 / 5 slots / 20 stride. r3=r26=0x828F3B68, base=0x828F3BD4 in BOTH runtimes. Canary 22 entries / 30s wall; ours --dump-addr at 50M (==500M, identical). **Diff**: slots 1/2/4 same shape (zeros + ptr + size 8) but ptrs in **canary 0xBC3xxxxx (physical heap)** vs **ours 0x4024xxxx (v40 bump heap)**; slot 3 canary `(2,5)` push counters vs ours `(0,0)` (ours over-cycles 0..0xB). Slot 0 zero in both. **Bug class ε — heap-region cross-reference mismatch**: predicate at 0x82450904 compares sub_82451E20's vptr-table-derived sum vs slot's local sum; the table walked via sub_8228E498's `[r3+0][32]` holds canary-physical addresses, but slot writers push v40 addresses on ours — per-element inconsistency causes predicate to never match early in ours. 1066 mem-watch hits on slot 3 ours (writers at sub_82450bc4 chain + 0x822f8b20/0x82323364/0x8231eee8). **Falsifies audit-034**'s "different positions" — slots match in shape, mismatch is in pointer value. **Sharp cascade**: A=land physical-heap separation (CPPBUG-AUDIT-001); B=sub_8228E498 vtable + slot writers same heap region; C=predicate matches iter 1-2; D=`draws>0` UNKNOWN. Pointed-to objects: 0x4024A240=vtable-headed (vptr=0x40111860), valid. Connects directly to audit-027/029. Canary patch reverted; xenia-rs HEAD `9028021` unchanged. Tests 640. Trace `audit-runs/audit-035-slot-table/{canary-0x82450720-fix.log, ours-lrtrace.jsonl, ours-dump-stdout.log, ours-memwatch-slot3.log}`.
- [project_xenia_rs_audit_034_frame_chain_divergence_2026_05_08.md](project_xenia_rs_audit_034_frame_chain_divergence_2026_05_08.md) — **🎯 KRNBUG-AUDIT-034 (2026-05-09, READ-ONLY, master `9028021`)**: re-applied audit-030 patch; probed audit-033's full 8-PC ours-side chain in canary 50s + ours -n 500M. **Firing matrix** L0..L5 uniform **6.3× divergence** (sub_821C4988=1/1, sub_821CECF0=2/2, sub_821CBEA8=7/7, sub_821CD458=7/7, sub_821CB968=14/14, sub_82450638=14/14 — same shape, ours iterates 6.3× more often per second). L6 sub_82450720 = 24 canary / 16 ours = 4.2×; L7 sub_82451E20 = 90 canary / 80 ours = 5.5×. **Loop-exit-divergence located**: sub_82450720+0x160..+0x1F4 (PC 0x82450880..0x82450914, 5-iter loop bounded by `r25<5`). Ours runs 5/5 iters (80/16=5.00); canary avg 3.75/5 (90/24=3.75) — exits via 0x82450904 `bne` on sub_82451E20's success-predicate match. **Exit predicate**: `[sub_82451E20_out+0]==r30-12 AND [+4]==[r30+0]+[r30+4]` where r30=r26+108+iter*20; data source = 5×20-byte slot table at r26+108..207 (r26=container struct arg1). Predicate fed by sub_82451E20's inner-loop, which dereferences Tier-1 cluster sub_8228E498's `[r3+0][32]`. Bug class **β-data-divergence + γ-deep entry** (sub_821C4988=0 static call xrefs → vtable). **Phase B (300s canary) Tier 2/3 horizon** — ALL 5 PCs (0x82172524, 0x82175810, 0x8217EB78, 0x821A6CF0, 0x821A8578) = **0 fires at 300s**. Cluster activation gated deeper than 5-min Linux Debug horizon (consistent with RECONCILE-A: Linux trace reaches frame 42/186, Lutris Windows reaches 72/186). Tests 640, lockstep instr=100000003. Canary patch reverted; master `9028021` unchanged. **Recommended next**: AUDIT-035 mem-watch r26+108..207 to identify slot-table writer ours misses; OR M5.5 to name sub_821C4988 trigger; OR extended pc-probe of sub_8228E498 capturing `[r3+0][32]` to name predicate compare-target.
- [project_xenia_rs_audit_033_ui_entry_chain_2026_05_08.md](project_xenia_rs_audit_033_ui_entry_chain_2026_05_08.md) — **🎯 KRNBUG-AUDIT-033 (2026-05-08, READ-ONLY, master `9028021`)**: re-applied audit-030 `--log_lr_on_pc` patch (30 LOC, build via `ninja -f build-Debug.ninja xenia_canary`; Checked variant has code-cache alloc collision). Probed 8 PCs (Tier1 cluster externals 0x8228A628/0x8228E138/0x8228E498; Tier2 callers 0x82172524/0x82175810/0x8217EB78; Tier3 CMessageBridge sites 0x821A6CF0/0x821A8578) in BOTH canary (50s wall) and ours (-n 500M). **Convergence**: both fire 0x8228E138 (canary 2× LR=0x82172BF8 in sub_82172BA0, ours 1× same LR) AND 0x8228E498 (canary 28× LR=0x82451E78 in sub_82451E20, ours 62× same LR). **Falsifications**: 0x8228A628 + all Tier 2 + all Tier 3 = 0 fires in canary at 50s — cluster's full activation isn't triggered in canary either at this boot horizon. **Frequency divergence**: ours 62× / 8s guest vs canary 28× / 50s wall on sub_82451E20 — busy-loop in array-ctor dispatch; loop-exit gate is the divergence target. CTOR-PROBE captures full call chain sub_82451E20←sub_82450720←sub_82450638←sub_821CB968←sub_821CD458←sub_821CBEA8←sub_821CECF0←sub_821C4988. Bug class **γ (vtable-driven dispatch)** — both reach Tier 1 entries via same LR; M5.5 (this-flow vptr) prerequisite for deeper top-down probes. Canary patch reverted. Trace `audit-runs/audit-033-ui-entry-chain/{canary-0x*.log,ours.log,ours.err}`. xenia-rs HEAD `9028021` unchanged. **Recommended next**: M5.5 milestone OR pivot to probing sub_82450720/sub_82450638/sub_821CB968 to find loop-exit gate (62 vs 28 fires divergence) OR longer canary trace via Lutris Windows build for post-intro Tier 2+3 activation.
- **🚨 CLUSTER IDENTITY REFRAME (2026-05-08)** — The `0x82285000-0x82294000` cluster (audit-009/016/017/020/021/026/027/029) is **NOT the renderer plateau**. It is the **front-end UI / save-game / mission-select / HUD subsystem** per RAPID-SURVEY-Q4 (93 string refs: BASE_INFO, LOAD_BASES, SAVE_MENUS, MISSION_SELECT, NOW_LOADING, FlightTime, etc.). Past sessions calling this "renderer cluster" or "renderer plateau" misidentified the subsystem. The cluster doesn't fire because the front-end UI flow never *activates*, not because the renderer is broken. The actual renderer (which produces the 2 splash swaps we DO get) lives elsewhere. The `swaps>2 / draws>0` gate is the **front-end loader** — what should activate after intro video → main menu → mission select. **Future sessions: do NOT label this cluster "renderer"**. Add this to running-error ledger as the 11th entry (subsystem-mislabeling class, distinct from the 10 function-boundary entries).
- [project_xenia_rs_overhaul_rapid_survey_2026_05_08.md](project_xenia_rs_overhaul_rapid_survey_2026_05_08.md) — **🎯 RAPID-SURVEY (2026-05-08, READ-ONLY, master `9028021`)**: post-overhaul DB survey of audit-009 cluster `0x82285000-0x82294000`. **Q1 zero**: 6 L1 PCs in NEITHER `methods` NOR `function_pointer_array_entries` (pure `this->vptr` per audit-031/032). **Q2 LEAD**: 13 static arrays at `0x820A9B98-0x820AA024` point INTO cluster; ctor candidates `sub_8228F858, sub_82293EC8, sub_82294898, sub_82284590, sub_822A0860, sub_822A0E90` (all themselves trapped in cluster or adjacent 0x822A0xxx). **Q3 BIG**: cluster has **309 pdata-validated fns, 309 unreachable** via static-call BFS AND indirect-reach view (M5 added 0 edges, ind_call=0 globally). Audit-009's "42 unreached" was 7x undercount. **Q4 PIVOT**: 93 string refs from cluster name **save-game/mission-select/UI subsystem**: BASE_INFO, LOAD_BASES, SAVE_MENUS, AUTO_SAVED, MISSION_SELECT, NOW_LOADING, FlightTime, ClearTimes, Disk free space, Content request — NOT raw renderer. SilpheedSCS::CMessageBridge strings live OUTSIDE cluster (caller `sub_821A6CF0+0xE6C`, `sub_821A8578+0xE0`). **Q5**: 68 cluster fns have `has_eh=true` (heavy C++ EH around save I/O). **Q6**: 0 mis-merge candidates in 0x82200000-0x822F0000 — past audits stand. **Q7**: audit-031 boundary fix verified (sub_824D23B0/29F0/2BD8/2C08 separate). **External entries** sub_8228A628/sub_8228E138/sub_8228E498 ARE called from outside (`sub_82172524, sub_82175810, sub_8217EB78` etc) but THEMSELVES still unreachable in BFS — gate is even higher. **Verdict**: audit-009 framing should pivot from "renderer plateau" to "front-end-UI/save-game cluster never instantiated". M5.5 NOT mandatory before next probe — Q4 already names subsystem; M5.5 would name the trigger ctor. **Recommended next**: `--lr-trace` canary-diff on cluster external-entry PCs + their parents (sub_82172524, sub_82175810, sub_8217EB78); cross-check SilpheedSCS::CMessageBridge::Load/CreateDeviceObjects; schedule M5.5 as next analyzer milestone.
- **✅ ANALYSIS-OVERHAUL FULL CLOSE-OUT (M1-M12 + 5 closers) LANDED (2026-05-08+10)** — [analysis_overhaul_M1_M12](project_xenia_rs_analysis_overhaul_2026_05_08.md). 9 no-ff merges off `e061e21` → master `7bc9e3a`. **All 12 milestones + all 5 deferred closers done.** M1 pdata (12156→25481 fns); M2 demangler; M3 722 vtables/499 anon classes/5571 methods; M4 Class::* probes; M5+M5.5 ind_call (687,963 edges, 97 single-cand + 6,745 multi-cand, **2,746 newly reachable functions** via vptr-write inference — M5.5 surfaces audit-009 cluster); M6+VMX `addr_mode` + 442 x_form_indexed + 40 atomic + 110 stvx; M7+SJIS/UTF-8 strings (6,311 ASCII + 790 SJIS + 39 UTF-8); M8/M11/M11.5 1,110 funcptr arrays (388 dispatch + 0 static_init); M9 has_eh (2,975 fns); M9.5 EH scope-tables (2,588 FuncInfo / 10,019 unwind / 315 try-blocks); M10 .tls infra (Sylpheed none); M12 `--lr-trace` JSONL canary-diff harness. Tests 605→655. Lockstep deterministic at instr=2000005. SCHEMA.md documents all 17 layers + remaining future work (M9.6 EH→function linkage; M11.6 non-canonical static-init drivers; full SJIS→UTF-8 decode; VMX128).
- **🚨 METHODOLOGY CORRECTION (2026-05-08)** — [audit_032_audio_host_pump](project_xenia_rs_audit_032_audio_host_pump_2026_05_08.md) revises audit-025's central claim "audio gate IS renderer gate". They are SEPARATE STALLS. 7+ prior sessions (KRNBUG-018, KE-001, AUDIT-024A/025/026/030/031) chased an audio gate believing it was the renderer gate. The fixes that landed addressed real divergences but did NOT approach `draws > 0`. **Future sessions must NOT re-conflate.** The renderer plateau (audit-009 cluster L1 reachability) is INDEPENDENT and remains the actual `swaps>2 / draws>0` gate. Audio fix is hygiene cleanup; renderer hunt is critical-path. All static analysis avenues for the renderer cluster are exhausted (audit-020/021/026/027/029); next probes need new tooling — analysis-toolset overhaul motivated.
- [project_xenia_rs_methodology_verification_2026_05_08.md](project_xenia_rs_methodology_verification_2026_05_08.md) — **🔍 META-AUDIT (2026-05-08)**: 4 parallel verifications + reconciliations. **VERIFY-A**: 0/12 cluster L1 PCs fire in canary → static reachability BFS is SOUND. **VERIFY-B**: 12/12 PowerPC store classes hooked by mem-watch → coverage COMPREHENSIVE. **RECONCILE-A**: Linux Debug canary kernel-call trajectory IDENTICAL to Lutris Windows; Linux log was simply terminated earlier (frame 42/186 vs 72/186). **RECONCILE-B**: user's "Linux black window vs Windows intro video" is HOST-PRESENTER divergence (Vulkan/XCB-only on Linux; Wayland TODO; H1 swapchain failure most likely; user confirmed Weston also shows black). **Combined verdict**: methodology is sound at kernel-call level. Reading-error ledger (10 entries, mostly function-boundary mis-attribution) is the real motivating gap. Past audit findings stand; no re-grading. Master HEAD `e061e21`, tests 605.
- [project_xenia_rs_audit_032_dispatcher_lr_2026_05_08.md](project_xenia_rs_audit_032_dispatcher_lr_2026_05_08.md) — **🎯 KRNBUG-AUDIT-032 (2026-05-08, READ-ONLY, master `e061e21`)**: re-applied audit-030 `--log_lr_on_pc` canary patch (30 LOC, 4 files), reverted at session close. **7,875 fires** of `pc=0x824D6640` in canary; ALL from single host-flagged kernel thread named **"Audio Worker"** (handle=`0100001C`, native=`467FC6C0`); **LR invariant `0xBCBCBCBC`** = host stack-fill canary, NOT a guest PC. r3=`0x30063000` driver-ctx, r4=0|1 init-vs-tick, r5=`0x1800` frame-size, r6=`0xBDFBA600` callback_arg. Canary log: `XAudioRegisterRenderDriverClient(701CF210(824D6640), BDFBA658(00000000))`. **Mechanism: canary `xe::apu::AudioSystem` (`apu/audio_system.cc:84-159`) spawns host XHostThread "Audio Worker" that loops `WaitAny(client_semaphores_) → processor_->Execute(callback_pc, args)`** — invokes thunk DIRECTLY via host emulator, no guest call site, hence LR=stack-canary. **Falsifies AUDIT-031 vtable[7] hypothesis**: `addi r4, r10, 26176` at sub_824D2C08+0x374 loads PC 0x824D6640 as the callback_ptr ARGUMENT to XAudioRegisterRenderDriverClient (caller-side parameter), not vtable registration. **Outcome δ+α composite**: the "caller PC" we sought is canary's HOST C++, not guest. **Our impl gap**: `XAudioRegisterRenderDriverClient` (exports.rs:2705-2745) registers (callback_pc=0x824D6640, arg=0x41E9DD5C) correctly but **does NOT spawn a host worker thread to pump the callback**, no semaphore-release loop. Probes (`--pc-probe` and `--branch-probe` × 0x824D6640/0x824D29F0) at -n 500M: **0 fires both**. tid=9 parks `pc=0x824D28D0` waiting `0x828A3254`; tid=10 parks `pc=0x824D2990` waiting `0x828A3230` (count=0/limit=6). Bug class **δ-α composite — host-side AudioSystem worker thread missing**. Sharp cascade: A=tid 9 unparks on first sub_824D29F0:KeSetEvent(0x828A3254); B=tid 10 unparks on next sema release; C=XAudioSubmitRenderDriverFrame >0; D=KeReleaseSemaphore non-zero. **Audio gate is NOT renderer gate** (revising audit-025) — separate stalls sharing "host pump missing" symptom only. Tid 10's limit=6 sema = audio-frame queue depth (canary's `queued_frames_=6`), isolated from renderer. Recommended next: implement host-side audio worker (60-120 LOC) per `apu/audio_system.cc`. Won't flip swaps=2→draws>0 plateau alone — audit-025 strategic pivot to audit-009 renderer cluster L1 callers REMAINS priority. Trace `audit-runs/audit-032-dispatcher-lr/{canary-patch.diff, probe.{log,err}, probe-sanity.{log,err}, branchprobe.{log,err}}` + `/tmp/audit-032-canary.log` (7,875 LR fires). Tests 605, lockstep instr=100000003. Master HEAD `e061e21` unchanged.
- [project_xenia_rs_verify_A_canary_pc_trace_2026_05_08.md](project_xenia_rs_verify_A_canary_pc_trace_2026_05_08.md) — **🎯 VERIFY-A (2026-05-08, READ-ONLY, master `e061e21`)**: re-applied audit-030 patch; probed 12 PCs (6 narrow L1 + 6 broader cluster) from audit-009 unreachable cluster `0x82285000-0x82294000` in canary. **0/12 fires** across 35-sec windows while audio loop runs hot (5,600-5,800 KeReleaseSemaphore/window). Sanity-check `0x824D28D0` = 5683 fires confirms trace mechanism. **Outcome (i): static reachability claim is SOUND** — xrefs.kind='call' BFS conclusion is corroborated by canary runtime trace; indirect-dispatch reachability is NOT being missed for this cluster. Audit-009/-016/-017/-020/-021/-029 framing of the cluster as unreachable holds. AUDIT-031's γ-deep dispatcher hypothesis reinforced (the dispatcher exists, but is NOT in this cluster — different code region). 95% upper bound on cluster reach-rate ~22% from sample size; full 112-PC sweep would harden to <5% in ~75 min. Reading-error ledger UNCHANGED (this claim was not on it). Recommended next session: AUDIT-031 sharp-prediction step 1 (probe `0x824D6640`); analysis-toolset overhaul remains motivated by other 10 errors not by this verification. Canary patch reverted. Trace `audit-runs/verify-A-static-reachability/probe-*.log` (13 files).
- [project_xenia_rs_audit_031_audio_wait_site_2026_05_08.md](project_xenia_rs_audit_031_audio_wait_site_2026_05_08.md) — **🎯 KRNBUG-AUDIT-031 (2026-05-08, READ-ONLY, master `e061e21`)**: re-applied audit-030's `--log_lr_on_pc` canary patch (30 LOC, 4 files); reverted at session close. **Outcome (a) — canary EXECUTES PC 0x824D28D0**: 54128 fires in ~5min, audio worker hot-loops through wait→release. Wake source captured via probe of KeSetEvent thunk `0x8284DDDC`: `tid=0100001C lr=0x824D2A44 r3=0x828A3254` = `KeSetEvent(0x828A3254,1,0)` from PC `0x824D2A40`. **AUDIT-025/-030 mis-attribution corrected**: IDA-DB `sub_824D23B0` (claimed range `0x824D23B0..0x824D2878`) actually contains a SECOND function prologue at `0x824D29F0` — that's the real wake-source, NOT sub_824D23B0. sub_824D23B0 entry probe = 0 fires confirms. Static reachability of sub_824D29F0: tail-jump from thunk at `0x824D6640` (which loads `r3=[0x828A3264]`); `0x824D6640` is data-referenced at `sub_824D2C08+0x374` (PC `0x824D2F7C: addi r4, r10, 26176`); next instructions deref `[r31][68]`, load vtable[7] at `[[r3]+28]`, `bcctrl 20,lt` to register the thunk. **Our impl tid=9 state matches AUDIT-025**: `Blocked(WaitAny [0x828A3254]) pc=0x824d28d0`. Bug class **γ-deep, vtable-driven** (refines AUDIT-025 with named downstream witness `sub_824D29F0`). The dispatcher loop that should periodically invoke `0x824D6640` is the unreached gate — likely in `0x82287000-0x82294000` cluster (AUDIT-009). Discipline gate: 5/5 PASS. **Recommended AUDIT-032**: probe `0x824D6640` directly in canary (names dispatcher PC) + probe `0x824D2F90 bcctrl` to capture r3 (audio-engine "this") + vtable[7] address; walk dispatcher's caller chain in our DB; cross-check audit-009 cluster overlap. NO source mods, NO commit. Trace `audit-runs/audit-031-wait-site/{canary-0x824D2878.log, canary-0x824D28D0.log, canary-KeSetEvent.log, canary-sub23B0.log}`.
- [project_xenia_rs_audit_029_physical_mem_diff_2026_05_08.md](project_xenia_rs_audit_029_physical_mem_diff_2026_05_08.md) — **🎯 KRNBUG-AUDIT-029 (2026-05-08, READ-ONLY, master `e061e21`)**: physical-heap diff — LAST guest-memory surface. Architectural finding: our impl has NO separate physical heap (MmAllocatePhysicalMemoryEx folds into v40 bump allocator at 0x40000000+); 0xA0/0xE0/flat-0x00 dumps all `0 committed pages`. Canary physical extracted: 58458 commits / 228 MiB / 24.5 MB nonzero / 28851 0x82xxxxxx PC dwords across 4467 4K pages / 536 64K-regions. **L1 hits: narrow 0/6, broad 2/116 (sub_8228CC18, sub_8228A220 — both scalar, no tables); audit-017 chain 0/8.** **CONFIRMS audit-027 misplacement**: our v40 table at 0x40211900 (18 PCs, 0x20 stride) appears verbatim on canary physical at 0x1c32c910 — same 18 PCs same 0x20 stride same trailing dup. Largest PC run on canary physical: 232 dwords at 0x1e568f38 (XAM/UI 0x824b0xxx-0x824b2xxx family, ~220 PCs); 4 smaller runs ≤9. Top bucket 0x82026000 × 12655 (per-instance vtable in stride-0x38 object array at 0x144x0000). **Outcome ζ — ALL FOUR HEAPS ELIMINATED.** All vtable/dispatch-table hypotheses across audits 010/011/012/015/016/017/026/027/029 refuted. Cluster L1 functions invoked exclusively via static `bl` in unreached parents — gate is upstream of any heap data structure (control-flow gate, not data-population gate). **Strategic pivot mandatory.** Recommended AUDIT-030: Option A (preferred) comparative-execution divergence trace (canary patch periodic tid:pc:lr sample, diff vs ours to find first divergent guest instruction); Option B targeted canary trace logging LR on every entry to sub_824D23B0 (sole KeSetEvent(0x828A3254) caller, vtable-only invoked) to name the per-frame renderer caller; Option C CPPBUG-AUDIT-001 backlog. Discipline gate fails 1. NO source mods, NO commit. Tests 605, lockstep instr=100000003 preserved. Master HEAD `e061e21` unchanged. Trace `audit-runs/audit-029-physical-mem-diff/`.
- [project_xenia_rs_audit_027_v40_mem_diff_2026_05_08.md](project_xenia_rs_audit_027_v40_mem_diff_2026_05_08.md) — **🎯 KRNBUG-AUDIT-027 (2026-05-08, READ-ONLY, master `e061e21`)**: v40 heap byte-level dword diff vs canary's audit-024A 248.6 MiB dump. Captured ours via `--dump-section=0x40000000:0x3F000000` (60119 commits, 1056964608 bytes); extracted canary v40 = 90 commits / 1008 MiB. A-list (canary 0x82xxxxxx, ours differs) = **536**; B-list inverse = 31947. **Cluster L1 (0x82285000-0x82294000) hits = 0/0** broad-and-narrow — v40 ELIMINATED as dispatch-table source (after audit-026 v80 elimination). Top A-list buckets: `0x828f3xxx`(90, .data dispatcher), `0x8284dxxx`(78, .text), `0x8284cxxx`(64, .text near .text-end), `0x82150xxx`(30), `0x828f4xxx`(23), `0x82882xxx`(20). Three vtable-runs detected: `0x40000770` len=32, `0x400015a0` len=110 (same shape, two instances of 110-method class), `0x40000d90` len=20 — all target `.text` heap-allocator handler thunks NOT renderer cluster. Listener anchor `0x40BA9A80` is canary-uncommitted in this dump; ours has audit-016 listener content (`+0x2C=0x4024AC00`, `+0x3C=0x4024B3E0`) — heap-pointer divergent, not missing-write. B-list discovery: `0x40211900..0x40211B50` in OURS has 23 fn-entries spaced 0x20 apart (`0x82183ae8, 0x82187e38, 0x8218cf10, ...`) = a function-table our impl builds in v40 that canary builds elsewhere (likely physical heap). **Strategic pivot mandatory** per task brief outcome (iii). Recommended **AUDIT-029 = extract canary physical heap (0x20000000 span, 58458 commits = 228 MiB)** with same script targeting `physical`. Alt: vtable-write-tap instrumentation. Alt: CPPBUG-AUDIT-001 backlog (`nt_allocate_virtual_memory` silent-success / `mm_allocate_physical_memory_ex` ignores alignment). Trace `audit-runs/audit-027-v40-mem-diff/`. NO source mods; NO commit. Master HEAD `e061e21` unchanged. Sister 028 untouched.
- [project_xenia_rs_audit_028_steady_state_notify_2026_05_06.md](project_xenia_rs_audit_028_steady_state_notify_2026_05_06.md) — **🎯 KRNBUG-AUDIT-028 (2026-05-08, READ-ONLY, canary log + source analysis only)**: XNotify steady-state publisher audit. Canary log (17245 lines) shows ONLY `XamNotifyCreateListener(0x2F)` @1347 + `XNotifyPositionUI(0x0A)` @2018 — NO further notification API calls. `XNotifyGetNext` is `kHighFrequency` (xam_notify.cc:96), per-call logging suppressed. 34 `BroadcastNotification` publisher sites across 11 files in canary; ALL event-driven (host UI, profile change, XMP play, SMC tray, controller hotplug edge) — NONE periodic. Controller hotplug log message absent → no `kXNotificationSystemInputDevicesChanged` fired. `VdSwap` count = 1 (TOC entry only) → ZERO actual swaps in canary; our impl swaps=2 is AHEAD. Audio-sema released 2224× in canary tail. **Outcome β: XNotify queue is NOT the gate**. Our impl matches canary's notification timeline byte-for-byte. The 1.49M `XNotifyGetNext` polls are dutiful idle polling, not missing-publisher symptom. **Strategic pivot: audio/render gate is still the γ-cluster from AUDIT-009/016/017/025** (`sub_824D23B0` via vtable on audio_system `0x82006CF4`, renderer cluster `0x82287000-0x82294000` unreached). AUDIT-029 = static-grep canary for what populates the `0x82006CF4` audio_system vtable at runtime + diff against ours. Provisional cascade A: cluster L1 PC fires; B: KeReleaseSemaphore(0x828A3230) 0→many; C: XAudioSubmitRenderDriverFrame 0→many; D: VdSwap climbs. NO source mods, NO commit, master HEAD `e061e21` unchanged. Trace `audit-runs/audit-028-steady-state-notify/`.
- [project_xenia_rs_audit_025_audio_thread_start_2026_05_06.md](project_xenia_rs_audit_025_audio_thread_start_2026_05_06.md) — **🎯 KRNBUG-AUDIT-025 (2026-05-07, READ-ONLY, master `de5a15e` post-Path-2)**: audio thread-start gate identified as **γ-DEEP, vtable-driven**. XAudioRegisterRenderDriverClient (exports.rs:2705) ≈ canary `xboxkrnl_audio.cc:56-82` semantically; `0x41550000|index` return matches. Audio init `sub_824D2C08` runs to completion in our impl (KeInitializeSemaphore=1 on 0x828A3230 limit=6, ExRegisterTitleTerminateNotification=3, ExCreateThread spawns tids 9 entry=0x824D2878 + 10 entry=0x824D2940, KeResumeThread=2). DISPATCHER_HEADERs correctly populated with Path 2's "XEN\0"+ptr stamp. **Worker correctly parks on `KeWaitForSingleObject(0x828A3254)` waiting for job-submit signal** — but `sub_824D23B0` (the ONLY KeSetEvent(0x828A3254) wake-source, at +0x54/+0x4FC/+0x688) is never reached. Probe set 12 PCs × -n 500M: only `0x824D2DF8` (ExRegTitleTerm in sub_824D2C08) fires; `0x824D23B0`/`0x824D2404` zero fires. **`sub_824D23B0` body at 0x824D2BD8 has ZERO static call-xrefs** — invoked only via vtable on audio_system object (`[r31+0]=0x82006CF4`). Caller would be a per-frame audio update from renderer/scenegraph = the **same `0x82287000-0x82294000` cluster identified by AUDIT-009 as unreached**. Audio gate IS the renderer gate — no new bug class, same γ-cluster blocker. tid 9 state: `Blocked(WaitAny [0x828A3254])` pc=0x824D28D0, signal_attempts=0. Discipline gate fails 1+3. **Recommended next: strategic pivot back to AUDIT-009/016/017's renderer cluster L1 callers + listener vtable population** — what kernel call materializes the listener-dispatch table so renderer can route per-frame audio. Audio worker host-thread emulation is option C (regresses swaps via xaudio-tick path). Trace `audit-runs/audit-025-audio-thread-start/probe.{log,err}`. Master HEAD `de5a15e` unchanged.
- [project_xenia_rs_kernel_stashhandle_2026_05_06.md](project_xenia_rs_kernel_stashhandle_2026_05_06.md) — **🎯 KRNBUG-α-006 (2026-05-07, LANDED branch `xobj-stashhandle/p0-canary-mirror` → master `de5a15e`)**: `ensure_dispatcher_object` (exports.rs:~3097) now writes `+0x08=0x58454E00` (`'X','E','N','\0'` kXObjSignature) and `+0x0C=ptr` (stash handle) per canary `XObject::StashHandle` (xobject.h:253-256). 7 LOC impl + 27 LOC tests. Tests 604→605. Lockstep `instructions=100000003 imports=987516` ×2 reruns (identical to pre-fix d9e40d3 — host-side write). Cascade @ -n 500M: NIL ripple — workers=20, KeReleaseSemaphore=0, XAudioSubmitRenderDriverFrame=0, NtSetEvent=3334, VdSwap=2 all match post-ke-resume baseline. **0x828F4838+0x08 still zeros** at -n 500M because guest never invokes Ke* with that ptr (canary uses `SetNativePointer` lifecycle there, which we don't traverse via `ensure_dispatcher_object`). Audit-024A's hypothesis that this stamp gates audio init is **observationally falsified post-fix**. Lands as canary-correctness restoration (sister of XamUserGetSigninState pattern); no sharp cascade prediction per task brief. Trace `audit-runs/post-stashhandle/`. Next: audio-thread-start gate (post-XAudioRegisterRenderDriverClient) — coordinate with sister AUDIT-025.
- [project_xenia_rs_audit_024a_canary_delayed_trigger_2026_05_06.md](project_xenia_rs_audit_024a_canary_delayed_trigger_2026_05_06.md) — **🎯 KRNBUG-AUDIT-024A (2026-05-07, READ-ONLY, canary patch+rebuild+revert)**: re-applied audit-023's mem-dump pattern with delayed trigger on first `XAudioSubmitRenderDriverFrame_entry` (39 LOC: cpu_flags hunk + xboxkrnl_audio.cc hook). Linux Debug build success after `/home/fabi/xenia-canary` symlink + `--disable_instruction_infocache=true`. Captured 248.6 MiB dump (260,659,200 bytes) at deep boot — canary log shows `KeReleaseSemaphore(0x828A3230,...)` firing repeatedly, VdSwap, VdRetrainEDRAM, texture loads. **AUDIT-017 β-class hypothesis FALSIFIED**: `[0x828F40B0]` (=0x828F4070+64) is **ALL ZEROS in canary** at this post-populator moment, while ours has `-1` sentinel from sub_821701c8. The `[+64]==-1` blocker is not the gate — canary admits `[+64]==0` or takes a different path entirely. **`0x828F4838+0x08` "XEN\0 + 0xF8000034" divergence stable** across audit-023 (early) and 024A (late) triggers — populator wrote it during early init. Heap pointers at `0x828F4838+0x20..0x60` populated in BOTH (canary `0xBC36xxxx`, ours `0x4024xxxx`). `0x828A3230` audio sema has full canary state (`05000000`, "XEN\0+F8000070", count=1, chain to F8000080/F800007C, ts BE628EDC1FCA7000 at +0x38) — KeReleaseSemaphore=0 in ours. Bug class refined β→**γ-deep**: the audio-thread that calls XAudioSubmitRenderDriverFrame is never started in ours despite `XAudioRegisterRenderDriverClient=1` and `KeInitializeSemaphore=1`. Patch reverted (canary `git status` clean). xenia-rs HEAD `d9e40d3` unchanged. Sister AUDIT-024B running in parallel for "XEN\0" writer source-grep. Next: cross-reference 024B's writer with our canary-only export queue (ExTerminateThread/KeReleaseSemaphore) OR α/δ probe of audio-thread-start gate post-XAudioRegisterRenderDriverClient. Trace `audit-runs/audit-024a-canary-diff/`.
- [project_xenia_rs_audit_023_canary_diff_2026_05_06.md](project_xenia_rs_audit_023_canary_diff_2026_05_06.md) — **🎯 KRNBUG-AUDIT-023 (2026-05-06, READ-ONLY, Path B canary patch+rebuild+revert)**: temp 44-LOC canary patch (cpu_flags + xam_notify) added `--memory_dump_path` flag, dumped 216 MB on first XamNotifyCreateListener (mask=0x2F). Linux Debug build success after `--disable_instruction_infocache=true` workaround for canary's pre-existing XexInfoCache SIGBUS. PageEntry `state` bitfield empirically at qword bits 60-61 (NOT declaration-order 48-49). Canary's first-listener dump shows v80=146 committed pages but 0x828F4070 area ALL ZEROS (too-early trigger — populator hadn't run). Diff vs ours @-n 50M reveals: (1) `0x828E1F08` ours has listener pointer 0x40111890, canary=0 (mechanism difference, ours stuffs guest-mem, canary uses host-side notify_listeners_ vector); (2) **`0x828F4838+0x08` canary has ASCII `"XEN\0"` + handle `0xF8000034`, ours has zeros — NEW POPULATOR-EFFECT LEAD inside audit-016/017 cluster**; (3) `0x82124xxx` audit-009 cluster L1 PCs visible as data — REFUTED as populator target, this is static .pdata exception table, byte-identical in ours; (4) various `0xBC...` host-physical aliases vs ours `0x40...` virtual aliases (handle-namespace difference, not bug). **Audit-017 β-class hypothesis NEITHER confirmed NOR refuted** (canary trigger too early). Patch reverted (`git status` clean). Trace `audit-runs/audit-023-canary-diff/canary-memory.dump,canary-patch.diff,parse_dump.py,diff.txt`. Master HEAD `d9e40d3` unchanged. Next: AUDIT-024 either re-apply with later trigger (Nth listener / first XAudioSubmitRenderDriverFrame / first NtSetEvent on specific event) for fair like-for-like, OR static-search canary's xboxkrnl source for "XEN\\0" writer at 0x828F4840 (names populator's CODE).
- [project_xenia_rs_kernel_ke_resume_thread_2026_05_06.md](project_xenia_rs_kernel_ke_resume_thread_2026_05_06.md) — **🎯 KRNBUG-KE-001 (2026-05-06, LANDED branch `ke-resume-thread/p0-canary-mirror`)**: real `KeResumeThread` per canary `xboxkrnl_threading.cc:216-227` (mirrors nt_resume_thread plumbing). 600→601 tests; lockstep `instructions=100000003 imports=987516` ×2. **Cascade A PASS**: tids 9 (entry=0x824D2878) / 10 (entry=0x824D2940) leave Suspended → run prologue → park on audio buffer-completion semaphores 0x828A3254 / 0x828A3230. **B PARTIAL FAIL**: NtSetEvent 667→3334; KeReleaseSemaphore=0; XAudioSubmitRenderDriverFrame=0. **C FAIL** (predicted 2→1, actual 2→2): both ExTerminateThread + KeReleaseSemaphore still canary-only. **D FAIL**: γ-cluster blocker unchanged — `--pc-probe=0x82184318,0x82184374` no fires; `--dump-addr=0x828F4070` no DUMP; signal_attempts on 0x1004/0x100c/0x1020/0x15e4 still 0. swaps=2 draws=0 plateau intact. Goldens re-baselined `n50m: instructions 50000003→50000011, imports 407255→407247`. **Necessary-but-not-sufficient fix**: workers unsuspend but park on a downstream gate that's part of the audit-009/-016/-017 γ-cluster (`[0x828F4070+64]==-1`). Trace `audit-runs/post-ke-resume/`. Next: AUDIT-019 memory-watch on `[0x828F4070+64]` (audit-017 Option B).
- [project_xenia_rs_audit_018_canary_diff_2026_05_06.md](project_xenia_rs_audit_018_canary_diff_2026_05_06.md) — **🎯 KRNBUG-AUDIT-018 (2026-05-06, READ-ONLY)**: canary-log diff identifies α-class load-bearing stub. Function-name set-diff: only 2 calls in canary not in ours — `ExTerminateThread`, `KeReleaseSemaphore`. The latter is hammered by canary tid `F800006C` (audio render-frame ticker, entry=0x824D2878, ctx=0, flags=0x10000001) which canary unsuspends via `KeResumeThread(KTHREAD_ptr)`. **Our `ke_resume_thread` (exports.rs:3658-3664) is a no-op stub that ignores r3 and sets r3=0** — comment claims `nt_resume_thread` covers it, but `KeResumeThread` is a separate export. Canary `xboxkrnl_threading.cc:216-227` calls `thread->Resume()`. **Result: tids 9 (entry=0x824D2878) and 10 (entry=0x824D2940) are `Blocked(Suspended)` at -n 500M end-of-run** despite our `KeResumeThread=2` counter matching canary. Bug class **α (load-bearing stub_success)**. **All 5 discipline boxes pass — first time since IO-004**. Fix is 5 LOC (mirror nt_resume_thread pattern). Sharp 4-dim cascade prediction: A=tids 9/10 leave Suspended; B=KeReleaseSemaphore non-zero; C=2→1 canary-only; D=open hypothesis on `[0x828F4070+64]` becoming non-(-1) if β-blocker is downstream of audio init. Trace `audit-runs/audit-018-canary-diff/ours.{log,stdout.log}`. Master HEAD `7ed6192` unchanged. Next: KRNBUG-α-005, branch `ke-resume-thread/p0-canary-mirror`.
- **XamUserGetSigninState landed (2026-05-06, master `7ed6192`)** — small canary-mirror fix at xam.rs:48 (returns 1 for user 0 per `xam_user.cc:90-101`). Tests 599→600. Lockstep `instructions=100000006` deterministic ×2 reruns (was 100000012). Cascade ripple: `XamUserReadProfileSettings` now fires 2× (was canary-only). Canary-only kernel exports: 3→2 (still missing: ExTerminateThread, KeReleaseSemaphore). β-class blocker `[0x828F4070+64]==-1` unmoved per audit-017. swaps=2 draws=0 plateau intact.
- [project_xenia_rs_audit_017_state_bits_writer_2026_05_06.md](project_xenia_rs_audit_017_state_bits_writer_2026_05_06.md) — **🎯 KRNBUG-AUDIT-017 (2026-05-06, READ-ONLY)**: 5 static bit-14/15 setters of `[listener+4]` found; case-0xA `0x82173e04` sets bit-15 once at cycle 9183060, sub_821737F0 work-path enters at 9183561, but bit-14 setter at 0x82173950 NEVER fires — gated at 0x821738E0 by `[r30+64]==-1` where r30=`[0x828F48B0+0]=0x828F4070` (singleton sub-object). `[+64]` initialized to -1 by sub_821701c8; only non-(-1) writer is sub_82184318:0x82184374 (`bl 0x82456B58 (kernel handle); stw r3, 64(r30)`); chain bottoms in audit-009 cluster (`sub_82187dd0 ← sub_82183ca8 ← sub_822919c8`). bit-28 of `[singleton+60]` set at cycle 9224352 by sub_821c4988 — too late, AND is a NEGATIVE gate. Bug class **β-dominant + α-tail** (`XamUserGetSigninState=stub_return_zero` at xam.rs:48 breaks 2 separate guest paths but won't fire cascade alone). Discipline gate fails 1+3. No fix. Trace `audit-runs/audit-017-state-bits-writer/probe{1..5}.log`. Master HEAD `d736a1d` unchanged. Next: AUDIT-018 either probe-confirm sub_82184318 chain (3rd γ-cluster confirmation → strategic pivot) or canary-log-diff for missing kernel writer of `[0x828F4070+64]`.
- [project_xenia_rs_audit_016_submitter_callers_2026_05_06.md](project_xenia_rs_audit_016_submitter_callers_2026_05_06.md) — **🎯 KRNBUG-AUDIT-016 (2026-05-06, READ-ONLY)**: 0/16 submitter-chain PCs fire at -n 500M across 4 levels of caller walk-up (workitem chain `sub_822AE1F0/sub_822F55F0 → sub_822C8B50 → sub_822C6808` + parents `sub_822ADD70/sub_821A9920/sub_822ACAB8/sub_821A8578` + grandparents `sub_82299250/sub_822A4460/sub_821A82A0`). Both static caller chains bottom-out in audit-009 unreached renderer cluster (`0x82294xxx` / `0x821A6xxx`). Listener-struct dump at `0x40ba9a80`: vtable populated, callback-table A `[+0x2C]=0x4024AC00` POPULATED (audit-015's "==0" claim was WRONG), callback-table B `[+0x3C]=0x4024B3E0` POPULATED, but `[+0x04]` dispatch-state-bits=0 — real gate is `sub_821737F0`'s bit-14/15 read of [+4]. Bug class refined δ→**γ (deeper indirection)**: chicken-and-egg vtable-registry-not-populated. Discipline gate fails 1+3. Probe-machinery anomaly: `sub_82174040` entry never fires despite mid-body PC executing — verify in AUDIT-017. Next: probe `sub_822F1AA8` frame-poll + writers of `[0x40ba9a80+4]` + `sub_82181D48` predicate. Trace `audit-runs/audit-016-submitter-callers/probe{,2}.{log,err}`. Master HEAD `d736a1d` unchanged.
- [project_xenia_rs_audit_015_l1_propagation_2026_05_06.md](project_xenia_rs_audit_015_l1_propagation_2026_05_06.md) — **🎯 KRNBUG-AUDIT-015 (2026-05-06, READ-ONLY, FORK B)**: 28/112 PCs fired at -n 500M post-IO-004. sub_82173DC8 dispatches all 4 startup notifications then idles via early-exit at 0x82173ed8 (`[r31+44]==0` callback-table NULL). Worker 0x822c6870 (tids 14, 15) parks on Semaphore handle 0x1308 (`signals=0 waits=2`); producer chain `sub_822AE1F0/sub_822F55F0 → sub_822C8B50 → sub_822C6808 → 0x824AB158 (NtReleaseSemaphore)` is unreached. Worker sub_824563E0 (tid=16) is healthy XAM inactivity-poll loop; not the gate. Worker sub_823DDB50 (tid=19) parks at entry on 0x160C Event/Auto. All 21 audit-009 baseline PCs still UNFIRED. Bug class **δ (pure-guest renderer)** — no kernel boundary stub. Discipline gate fails 1+3, no fix. Next session: probe submitter chain entries + `--dump-addr=0x40ba9a80` listener struct. Trace `audit-runs/audit-015-l1-propagation/`. Master HEAD `d736a1d` unchanged.
- [project_xenia_rs_audit_014_0x15e0_wake_2026_05_06.md](project_xenia_rs_audit_014_0x15e0_wake_2026_05_06.md) — **🎯 KRNBUG-AUDIT-014 (2026-05-06, READ-ONLY)**: 0x15e0 wake-eligibility hypothesis FALSIFIED. 0x15e0 is a Semaphore (creator `lr=0x824ab110`), `signal_attempts=1 waits=1 wakes=1`, healthy handshake (tid=1 wait → tid=16 NtReleaseSemaphore wake). tid=17 actually parks on **0x15e4** (Event/Manual, signals=0/waits=1/wakes=0, creator `lr=0x824a9f6c`) — same producer-missing class as 0x1004/0x100c/0x1020. Long-standing transcription error: AUDIT-002/008/009/IO-004 label "0x15e0 worker" should be "0x15e4 worker". Bug classes α-ζ all N/A. Discipline gate fails box 1. No fix. Master HEAD `d736a1d` unchanged. Trace `audit-runs/audit-014-0x15e0-wake/probe.{log,err}`. Next: Fork B branch-probe data on `sub_82173DC8 / 0x822c6870 / 0x824563e0 / 0x823ddb50` for the actual producer.
- [project_xenia_rs_io_004_xnotify_listener_2026_05_06.md](project_xenia_rs_io_004_xnotify_listener_2026_05_06.md) — **🎯 KRNBUG-IO-004 (2026-05-06, LANDED branch `xnotify-listener/p0-startup-enqueue`)**: real `XamNotifyCreateListener` + `XNotifyGetNext` per canary `kernel_state.cc:1013-1033` + `xam_notify.cc:22-96`. NotifyListener variant + 4 startup notifications on first listener (mask 0x2F): SystemUI/SystemSignInChanged on kXNotifySystem; LiveConnectionChanged(0x001510F1)/LiveLinkStateChanged on kXNotifyLive. 594→599 tests; lockstep `instructions=100000012` deterministic ×2 reruns. Phase 1.5 sanity probe confirmed CTR=0x82175338 (audit-012-predicted dispatch target unchanged). **Cascade: dispatch arm 0x822f1be8 fires; sub_82173DC8 entered repeatedly; 3/21 renderer-cluster L1 PCs newly reached (0x822c6870 from 2 workers, 0x824563e0, 0x823ddb50)**; canary-only 7→3 (KeResetEvent/ObCreateSymbolicLink/XamTaskCloseHandle/XamTaskSchedule re-classified to fired; still missing: ExTerminateThread/KeReleaseSemaphore/XamUserReadProfileSettings); worker count 18→20; signal_attempts on 0x15e0=1 (primary=1, was 0); draws=0 still expected at this step. LOC 119 ≤ 120. Trace `audit-runs/audit-013-io-004-phase1.5/`.
- [project_xenia_rs_cpp_runtime_audit_2026_05_06.md](project_xenia_rs_cpp_runtime_audit_2026_05_06.md) — **🔍 CPPBUG-AUDIT-001 (2026-05-06, READ-ONLY, BACKGROUND-BACKLOG)**: 0x825ED990 = CRT abort dispatcher (NOT _purecall — corrects audit-010); Sylpheed CRT is statically linked. Top-3 vtable=0 candidates REFUTED by audit-012. Real gaps for later: nt_allocate_virtual_memory silent-success-on-error (exports.rs:622-625) + heap.rs:465 silent-unmapped-write drop (combined = "phantom allocation"); mm_allocate_physical_memory_ex ignores alignment/range/protect; sync/eieio interpreter no-ops; RtlRaiseException stub doesn't fatal-stop on MSVC throws. Track for after draws>0.
- [project_xenia_rs_audit_012_vtable_zero_2026_05_06.md](project_xenia_rs_audit_012_vtable_zero_2026_05_06.md) — **🎯 KRNBUG-AUDIT-012 (2026-05-06, READ-ONLY)**: ALL FIVE bug-class hypotheses for vtable=0 REFUTED. Vtable IS correctly initialized: mem[0x40111890+0] transitions monotonic 0→0x820AD894→0x820A183C, stays. AUDIT-011's "vtable=0" was a misread (captured PC 0x8284E45C XAM thunk, treated lwz address as live PC). AUDIT-010's "vtable[1]=0x825ED990 abort" was the inner ctor's transient vtable, overwritten 3 instructions later. Real runtime vtable[1] = thunk 0x82175338 → sub_82173DC8. Discipline gate now PASSES for AUDIT-011's listener fix. Next: KRNBUG-IO-004 (real xnotify queue per kernel_state.cc:1013-1033 + xam_notify.cc) with Phase 1.5 sanity probe at 0x822f1c00 (expect CTR=0x82175338) before commit.
- [project_xenia_rs_audit_010_xnotify_diff_2026_05_05.md](project_xenia_rs_audit_010_xnotify_diff_2026_05_05.md) — **🎯 KRNBUG-AUDIT-010 (2026-05-05, READ-ONLY)**: branch (α) — xnotify_get_next + xam_notify_create_listener are stubs; canary auto-enqueues 4 startup notifications on listener registration (SystemUI/SystemSignInChanged/LiveConnectionChanged/LiveLinkStateChanged). Discipline gate FAILS box 3: vtable[1] of dispatcher (mem[0x828E1F08]) statically=0x825ED990 abort handler — needs runtime --pc-probe before fix. Provisional cascade: XamUserReadProfileSettings fires next. Trace `audit-runs/audit-010/findings.md`. Master HEAD `50a4887` unchanged.
- [project_xenia_rs_audit_009_renderer_unreached_2026_05_05.md](project_xenia_rs_audit_009_renderer_unreached_2026_05_05.md) — **🎯 KRNBUG-AUDIT-009 (2026-05-05, READ-ONLY DIAGNOSTIC)**: 0/21 PCs fired at -n 500M (12 audit-008-recommended renderer-cluster parents+shims+dispatcher + 9 audit-005 producer-callsites). Stop condition 1 triggered. The 0x82287000-0x82294000 cluster is structurally above its observed call boundary — likely reached via vtable/function-pointer that's never populated (sylpheed.db: zero non-call xrefs to its level-1 roots `sub_82293448`/`sub_822919C8`). Main parks in `sub_822F1AA8` frame-poll loop forever (XNotifyGetNext=1.49M, NtWaitForSingleObjectEx=1.49M, RtlEnter/LeaveCS=889k each). 18 workers spawned incl. 0x100c (tid=3, ctx=0x828F3D08), 0x1004 (tid=11, ctx=0x828F3EC0), 0x15e0 (tid=17, ctx=0x828F4070) — all parked, signal_attempts=0. canary-only exports unchanged: ExTerminateThread/KeReleaseSemaphore/XamUserReadProfileSettings. Discipline gate fails boxes 1+3. No fix. Next probe set: cluster L1 roots (sub_82293448/sub_822919C8/sub_82288028/sub_82292d80/sub_822851e0/sub_82286bc8) + new thread entries (0x822c6870/0x824563e0/0x823dde30/0x823ddb50) + main frame-poll callees + main's post-poll continuation (sub_822F1638/sub_8216F088/sub_82173360 etc). Trace at `audit-runs/audit-009/probe-500m.{log,err}` (branch-probe.trace EMPTY).
- [project_xenia_rs_audit_008_branch_probe_2026_05_05.md](project_xenia_rs_audit_008_branch_probe_2026_05_05.md) — **🎯 KRNBUG-AUDIT-008 (2026-05-05, READ-ONLY DIAGNOSTIC)**: Model reset on IO-003 cascade. 0x100c worker IS spawned post-IO-003 (tid=3, ctx=0x828F3D08, entry=0x82181830, parked on event 0x1020). Same for 0x1004 (tid=11), 0x15e0 (tid=6). Real next gate is β-class: 5 non-create-chain callers of `sub_821800D8` (shims `bl getter; lwz r3,80(r3); bl sub_824AA1D8` at 0x821802D8/06E0/0B28/0EA0/1254) are never called; parents live in 0x82287000-0x82292FFF (renderer/scene-graph). **AUDIT-009 falsified the audit-008 hypothesis: those parents are themselves not entered — gate is one level higher still.** Discipline gate failed boxes 1+4. Trace at `audit-runs/audit-008/`.
- [project_xenia_rs_io_003_ioctl_2026_05_04.md](project_xenia_rs_io_003_ioctl_2026_05_04.md) — **🎯 KRNBUG-IO-003 (2026-05-04, LANDED branch `xboxkrnl-ioctl/p0-fsctl-mountinfo`)**: `nt_device_io_control_file` real impl per canary `NullDevice::IoControl` for FsCtlCodes 0x70000 + 0x74004. **Cascade fired**: priv-11 query runs, XamTaskSchedule fires, canary-only exports 7→3, AND 0x100c worker (tid=3, ctx=0x828F3D08) + 0x1004 worker (tid=11, ctx=0x828F3EC0) + 0x15e0 worker (tid=17, ctx=0x828F4070) all spawn (the original IO-003 prediction-scorecard's "0x100c UNCREATED / spawn count unchanged" marks were wrong per AUDIT-008 — workers were always there post-IO-003, just unlinked from dispatcher addresses in the audit). 592→594 tests; lockstep deterministic. Stack args 9-10 land at `[sp+0x54]` / `[sp+0x5C]` (Xbox 360 PPC EABI param save area = sp+0x14 + 64). `sylpheed_n50m` re-baselined `50000004→50000003`, `imports 407362→407255`. Still canary-only: `ExTerminateThread`, `KeReleaseSemaphore`, `XamUserReadProfileSettings`. **All 3 workers parked, signal_attempts=0** — the producer-side cascade is downstream of where IO-003 reaches; AUDIT-008 + AUDIT-009 trace it to the unreached 0x82287-0x82294 renderer cluster.
- [project_xenia_rs_audit_007_branch_probe_2026_05_04.md](project_xenia_rs_audit_007_branch_probe_2026_05_04.md) — **🎯 KRNBUG-AUDIT-007 (2026-05-04, READ-ONLY branch `investigate-sub-824a9710/p0-branch-probe`)**: `--branch-probe` instrumentation landed; runtime trace decisively identifies the priv-11 gate. **Exit branch: `0x824a9944` (post-bl sub_824ABD88 first call, r3=0xC0000034)**. Root cause: `NtDeviceIoControlFile` is `stub_success` at `exports.rs:90` — game-side `sub_824ABD88:0x824abe9c-eb0` reads `[out_buf+8]` of the FsCtlCode=0x74004 IOCTL response, finds zero (stub doesn't write OUT), assigns hardcoded `r3=0xC0000034` (STATUS_OBJECT_NAME_NOT_FOUND) at 0x824abea8-ac, propagates to caller, gates priv-11 site at `0x824a99a0` indefinitely. 592→592 tests, lockstep deterministic. **Next session = KRNBUG-IO-003**: implement `nt_device_io_control_file` per canary `NullDevice::IoControl` for FsCtlCodes 0x70000 + 0x74004. Predicted cascade: priv-11 fires + XamTaskSchedule fires + 0x100c worker spawn + 7→≤3 canary-only exports.
- [project_xenia_rs_io_002_volallocunit_2026_05_04.md](project_xenia_rs_io_002_volallocunit_2026_05_04.md) — **🎯 KRNBUG-IO-002 (2026-05-04, LANDED branch `xboxkrnl-vol-allocunit/p0-65536-cluster`)**: vol-info class-3 fixed from 2048→65536 alloc unit (canary NullDevice byte-identical). 591→592 tests, lockstep deterministic. **Audit-006's predicted 7→0 cascade FALSIFIED** (7→7 unchanged): all 16 NtQueryVolumeInformationFile calls originate from a single LR `0x82611f38` and complete successfully — vol-info is NOT the priv-11 gate. Stop condition triggered, no second fix attempted. Next session: `--pc-probe` on `sub_824A9710` entry to find the actual gate (priv-11 site has never fired in any session).
- [project_xenia_rs_audit_006_export_queue_2026_05_04.md](project_xenia_rs_audit_006_export_queue_2026_05_04.md) — **🎯 KRNBUG-AUDIT-006 (2026-05-04, READ-ONLY)**: 7/7 canary-only exports all REAL_BUT_UNREACHED → next session is **KRNBUG-IO-002** (block-size 2048→65536 in `exports.rs:1241-1269`, ≤4 LOC). Queue: `xenia-rs/audit-runs/audit-006/canary_export_queue.md`. **Cascade prediction FALSIFIED post-IO-002 — see io_002 memory.**
- [project_xenia_rs_io_nullfile_2026_05_04.md](project_xenia_rs_io_nullfile_2026_05_04.md) — **🎯 KRNBUG-IO-001 (2026-05-04, LANDED master `556a8c3`)**: `nt_read_file` on synth-empty files returns SUCCESS+0 instead of EOF, mirroring canary `NullFile::ReadSync`. AUDIT-005's attribution to `sub_824ABA98` was wrong — runtime trace decisively located the failure at the `NtReadFile(\Device\Harddisk0\partition0, off=2048, len=1024)` call inside `sub_824A9710` at PC `0x824a9810`. **`sub_824ABA98 = VerifyDirBlockSize(path, expected_alloc_unit_bytes)`**, **`sub_824ABD88 = MaybeMountAndIoctl`** (NtOpenFile WindowsPartition + NtDeviceIoControlFile 0x70000+0x4004). 590→591 tests. Lockstep BIT-IDENTICAL × 3 reruns. **Cascade walked massively: canary-only exports 10 → 7** (XeCryptSha + XeKeysConsolePrivateKeySign + NtDeviceIoControlFile now run; cache-recreate path executes through to NtWriteFile). Worker threads **6 → 19** at -n 500M (tid=10 `0x82178950` and tid=16 `0x82170430` — the original `0x1004`/`0x15e0` workers — now spawn). `n50m` golden re-baselined `50000004→50000000`, `imports 407416→407362`. **Next blockers**: (1) XamTaskSchedule cluster + ExTerminateThread/KeReleaseSemaphore/KeResetEvent/ObCreateSymbolicLink/XamTaskCloseHandle/XamUserReadProfileSettings — the 7 still-canary-only exports; (2) **block-size mismatch**: `nt_query_volume_information_file` returns `SectorsPerAllocUnit=1, BytesPerSector=2048` (=2048) but Sylpheed expects `0x10000=65536` from `main(1, 0x10000, 0xFF000)``sub_824A9710 r27=0x10000`; sub_824ABA98 will return `0xC000014F` when the recreate path eventually reaches it. New parked sites: 0x12fc/0x1600/0x1040/0x10b8/0x15e8/0x1014/0x101c/0x10bc/0x1044 + 0x42450b5c. `swaps=2 draws=0` plateau persists.
- [project_xenia_rs_xam_avpack_hdmi_2026_05_04.md](project_xenia_rs_xam_avpack_hdmi_2026_05_04.md) — **🎯 KRNBUG-XAM-001 (2026-05-04, LANDED)**: `XGetAVPack` `0x16``8` (HDMI). One-line at `xenia-kernel/src/xam.rs:383` mirroring canary `xam_info.cc:35` (`DEFINE_int32(avpack, 8)`); Sylpheed accepts `{3,4,6,8}` only (`xam_info.cc:250-251`). 589→590 tests. Lockstep deterministic across 3 reruns: `instructions=100000010, import_calls=987686 (+2.4×), VdSwap=2`; `n50m` golden re-baselined `50000005→50000004`. **Canary diff: 11 → 10 missing exports** (XGetAVPack matched). Cascade went exactly **one step**. **NEW telemetry signal**: `RtlNtStatusToDosError(c0000011)` from `lr=0x824a97e4` post-fix — `sub_824A9710` IS being entered now but priv-11 query never fires (a precondition exits early). **Next blocker: `sub_824ABA98` returning negative NTSTATUS** (per AUDIT-005 disasm); if cleared, `XeCryptSha`/`XeKeysConsolePrivateKeySign`/`NtDeviceIoControlFile`/etc. should follow. Parked handles 0x1004/0x100c/0x15e0 still `signal_attempts=0`; 9-PC producer probe still 0×; `swaps=2 draws=0` plateau persists.
- [project_xenia_rs_xex_priv_fix_2026_05_04.md](project_xenia_rs_xex_priv_fix_2026_05_04.md) — **🎯 KRNBUG-XEX-001 (2026-05-04, LANDED)**: real `XexCheckExecutablePrivilege` reading XEX `SYSTEM_FLAGS=0x00030000` bitmap (Sylpheed=`0x00000400`, bit 10 set). 588→589 tests. Lockstep deterministic at new value (`instructions=50000005, imports=407417, swaps=2, draws=0` × 3 reruns). Goldens re-baselined. **Priv-10 gate FLIPPED**`XGetAVPack: 0→1`. Other 10 canary-only exports + 9 producer PCs + 3 parked handles still unchanged: priv-11 site at `sub_824A9710` is downstream and not reached because the AV/crypto block aborts after `XGetAVPack`. **Next blocker: `XGetAVPack` returns `0x16`** — canary returns `cvars::avpack` (default 8 = HDMI), and Sylpheed accepts only 3/4/6/8 (xenia-canary `xam_info.cc:250-251`). One-line follow-up at `xenia-kernel/src/xam.rs:383`.
- [project_xenia_rs_audit_005_priv_stub_2026_05_04.md](project_xenia_rs_audit_005_priv_stub_2026_05_04.md) — **🎯 KRNBUG-AUDIT-005 (2026-05-04, LANDED master `451b3b2`)**: --pc-probe extension + canary kernel-call diff. 9 producer PCs unreached at -n 500M (failure mode α). **Root cause: `XexCheckExecutablePrivilege` is `stub_return_zero`** — gates XGetAVPack (priv=10) and XamTaskSchedule (priv=11) via opposite polarities, so guest walks wrong arm of every priv-gated branch and skips the entire init flow that populates dispatcher fields. 11 exports canary calls and we don't (XGetAVPack/XeCryptSha/XamTaskSchedule/...). Next: implement real priv-bit lookup from XEX header.
- [project_xenia_rs_audit_004_ctor_probe_2026_05_04.md](project_xenia_rs_audit_004_ctor_probe_2026_05_04.md) — **🎯 KRNBUG-AUDIT-004 (2026-05-04, LANDED master `6a070be`)**: read-only `--ctor-probe=PC` + `--dump-addr=ADDR` diagnostics; 586→588 tests; lockstep `instructions=100000002` preserved. **DECISIVE: "8-instance pool" hypothesis FALSE** — handle 0x1004 has a SINGLE dispatcher at `0x828F3EC0`; inner per-instance ctors `[0x821783D8,0x82181750,0x821701C8]` each fire EXACTLY ONCE. The "called 8 times" claim from AUDIT-002/003 came from miscounting OUTER getter `sub_8217C850` entries — itself a Meyers singleton-getter. **Producer indirection layer IDENTIFIED**: outer getters `sub_821800D8` (0x100c) and `sub_8216F618` (0x15e0) have 5+4 non-create-chain callers using canonical pattern `bl outer_getter; lwz r3, OFFSET(r3); bl 0x824AA1D8` (OFFSET=80 for 0x100c, =36 for 0x15e0). Static byte-scan of .rdata/.data shows 0 hits → no registry table; indirection is via the singleton-getter return value. **Interpretation (2) confirmed.** 9 producer-callsite PCs ready for next-session probe to discriminate failure mode A (producer never reached) from B (producer fires but reads zero from dispatcher field). Files: `crates/xenia-kernel/src/state.rs` (`fire_ctor_probe_if_match`, `ctor_probe_pcs`, `dump_addrs`), `crates/xenia-app/src/main.rs` (CLI wiring + 128-byte struct dumper). Trace at `audit-runs/audit-004/`.
- [project_xenia_rs_audit_003_class_probe_2026_05_03.md](project_xenia_rs_audit_003_class_probe_2026_05_03.md) — **🎯 KRNBUG-AUDIT-003 (2026-05-03, LANDED master `48eed25`)**: vtable/RTTI class-readout helper + create-time + wait-time per-frame class probes. 581→586 tests; lockstep `instructions=100000002` preserved. **Identified dispatcher addresses**: handle 0x100c → `0x828F3D08` (verified by `[this+0]=-1` POD struct + sub_82181750 disasm + xref table); handle 0x15e0 → `0x828F4070` (xref table). RTTI is **stripped**; dispatchers are hand-rolled job queues, NOT C++ polymorphic classes (so no class names — `[this+0]=-1` sentinel, not a vtable). **Producer hunt deliverable**: `xrefs` table audit shows EVERY reference to 0x828F3D08 / 0x828F4070 is in a ctor or the CRT — NO submitter code references either dispatcher in static analysis. Confirms unreachable-producer hypothesis. Handle 0x1004's 8-instance pool member addresses still need offline analysis (saved-r31 in MSVC ctors didn't preserve `this`; need to hook sub_8217C850 to capture each pool element's r3). 0x42450b5c remains a separate bug class (heap-allocated, AUDIT_BLIND). Files: `crates/xenia-kernel/src/state.rs` (`read_class_at_this`, `probe_create_stack_classes`), `crates/xenia-app/src/main.rs` (WAIT-side dump). Trace at `audit-runs/audit-003/run-500m-v4.txt`.
- [project_xenia_rs_producer_stack_trace_2026_05_03.md](project_xenia_rs_producer_stack_trace_2026_05_03.md) — **🔍 KRNBUG-AUDIT-002 (2026-05-03, LANDED master `6440261`)**: multi-frame back-chain capture at `NtCreateEvent`/`NtCreateSemaphore`/`NtCreateTimer`/`XamTaskSchedule` gated on `--trace-handles-focus`; 576→581 tests; lockstep `sylpheed_n50m` BIT-IDENTICAL. **Subsystems identified**: 0x1004 = static-ctor 8-instance pool (sub_821783D8 + sub_8217C850 chain → static ctor 0x8280F810 calls bridge 8×); 0x100c = singleton built inside main() (sub_8216EA68 = main); 0x15e0 = singleton in distinct cluster (sub_82172BA0 chain). All 3 ctors share identical 4-callee shape (Rtl InitCS + silph::Event ctor + silph internals); all 3 workers do `silph::Thread::SetProcessor(CURRENT,5)` first thing. **Corrections to prior memory**: (1) third handle is **0x15e0**, not 0x15e4 (transcription typo); (2) **0x42450b5c is not a kernel handle** — it's a guest-heap pointer (0x4xxxxxxx), tid=6 parks via a non-`do_wait_single` path (`<UNCREATED> <AUDIT_BLIND>`) — separate bug class. Walker is in `state.rs::walk_guest_back_chain` (PPC EABI back-chain, gated, read-only).
- [project_xenia_rs_xaudio_register_driver_2026_05_03.md](project_xenia_rs_xaudio_register_driver_2026_05_03.md) — **🎯 APUBUG-PRODUCER-001 (2026-05-03)**: XAudio register stub replaced with canary-faithful registration + dual-mode ticker (`XAUDIO_INSTR_PERIOD=48k` / `XAUDIO_PERIOD=5.333ms`) + `try_inject_audio_callback` reusing SavedCallbackCtx; 562→576 tests. Ticker gated **default-off** behind `--xaudio-tick`/`XENIA_XAUDIO_TICK=1` so lockstep `sylpheed_n*m.json` goldens stay green. **Producer hypothesis FALSIFIED for handles 0x1004/0x100c/0x15e4** — at `-n 500M --xaudio-tick` all 3 still show `signal_attempts=0`. Side-effect: under the flag the audio callback fires once, hijacks a guest HW thread on a `KeWaitForSingleObject` infinite loop (4M waits, swaps regress 2→1). Next candidate: **Timer DPC** (`KeSetTimer` / `KeInsertQueueDpc`). Master HEAD `9d45efe`.
- [project_xenia_rs_xam_task_schedule_2026_05_03.md](project_xenia_rs_xam_task_schedule_2026_05_03.md) — **🎯 XAMBUG-PRODUCER-001 (2026-05-03)**: XamTaskSchedule stub replaced with canary-faithful real spawn; 561→562 tests; lockstep `instructions=100000002` preserved. **Producer hypothesis FALSIFIED for handles 0x1004/0x100c/0x15e4** — counter `kernel.calls{XamTaskSchedule}` never appears at -n 500M (call site `0x824a9a10` unreached). Boot stalls before XamTaskSchedule. Next candidate: `XAudioRegisterRenderDriverClient` (counter=1, currently stub). Master HEAD `38f78c8`.
- [project_xenia_rs_audit_2026_05_followup_session.md](project_xenia_rs_audit_2026_05_followup_session.md) — **🎯 FOLLOW-UP SESSION COMPLETE (2026-05-03)**: 3 audit IDs landed (GPUBUG-DRAIN-001 vd_swap fallback warning silenced + new `drain_until_wptr`; KRNBUG-AUDIT-001 ghost-trail diagnostic with `--trace-handles-focus`; KRNBUG-D08 wall-clock vsync under `--parallel`). Tests 556→561. Lockstep BIT-IDENTICAL. **DECISIVE FINDING**: parked-waiter handles 0x1004/0x100c/0x15e4 show `signal_attempts=0 (primary=0, ghost=0)` after 500M instructions — producer is genuinely missing, **NOT a wake-eligibility bug or BST-paradox**. 3 share creator `lr=0x824a9f6c` + wait-wrapper `lr=0x824ac578`. Next session: producer hunt (file I/O completion / XAM async / XAudio buffer-complete / Timer DPC). Master HEAD `b54aa48`.
- [project_xenia_rs_fix_session_2026_05_03.md](project_xenia_rs_fix_session_2026_05_03.md) — **🛠️ AUDIT FIX SPRINT (2026-05-03)**: applied 11 commits closing 12 audit IDs across 4 of 8 planned phases. **swaps 1→2** confirmed (Phase A SWAPBUG-001). VdSwap PM4 ring path live (Phase C). Shader operand decode fixed (D1/D2/D3). 8 register addresses + index_size bit corrected (E). Kf-spinlock real impl (F1). 2 P1s (G1 GPUBUG-006 mmio ordering, G2 XMODBUG-002 write_bulk page bumps). **`draws=0` persists at -n 100M lockstep** — renderer plateau is multi-causal, parked-waiter handles still unresolved. Next session: trace producers for handles 0x1004/0x100c/0x15e4/0x42450b5c. Tests 551→556. Plan: `we-just-finished-a-shiny-conway.md`. **Engineering gotchas saved**: VdSwap buffer_ptr is NOT in primary ring; D1's c-vs-temp selector is at w0 bits 29-31 not bit 7; canary's addic actually does full 64-bit add (Plan agent was wrong, G3 deferred); `--stable-digest` flag added to xenia-rs check for byte-exact lockstep determinism.
- [project_xenia_rs_audit_2026_05_02.md](project_xenia_rs_audit_2026_05_02.md) — **🎯 COMPREHENSIVE AUDIT COMPLETE (2026-05-02)**: 13-milestone read-only audit of all modules vs canary. **197 finding IDs (15 P0, 40 P1) across 9 prefixes**. **SWAP REGRESSION SOLVED**: SWAPBUG-001 = PPCBUG-001 (addi 32-bit truncation in `bf8208e` at `interpreter.rs:114-118`) — single revert restores swaps=2. **Renderer plateau explained (multi-causal)**: VdSwap PM4 ring bypass + 5 P0 GPU shader/draw bugs (operand modifiers, constant-reg selector, vertex endian, 8 register addresses). Memory write-visibility NOT broken. Parked-waiter handles still unexplained. Final report: `xenia-rs/audit-2026-05-final.md`.
- [project_xenia_rs_ppc_audit_2026_04_29.md](project_xenia_rs_ppc_audit_2026_04_29.md) — **🔍 PPC AUDIT COMPLETE (2026-04-29)**: 253 PPCBUG IDs (~55 HIGH, ~75 MEDIUM, 5 retracted). Audit-only, no code changes. **Triaged fix-order plan at `xenia-rs/audit-report-2026-04-29.md`** — start there for fix session. Detailed per-bug entries at `xenia-rs/audit-findings.md`. **Headline finds**: PPCBUG-107 cascade (50+ stores missing `invalidate_for_write` → cross-thread atomics broken, likely Sylpheed renderer cause); 8 decoder/field-extraction bugs collapse into 6 missing accessors + 1 wrong sh64 + 1 missing decode_op6 entry (Phase 2 sweep); PPCBUG-046 (`clrldi r3, r4, 32` no-op); PPCBUG-053+054 (broken `bdnz` after `negx`); PPCBUG-510 (stvewx128 corrupts 12 bytes); PPCBUG-424/425 (vmaddfp128/vmaddcfp128 operand swap — every D3D FMA wrong). 14 must-land-together coupling pairs documented. Audit verified mechanically: every tracker entry referenced in the report.
- [project_xenia_rs_addis_signext_root_cause_2026_04_29.md](project_xenia_rs_addis_signext_root_cause_2026_04_29.md) — **🎯 ROOT CAUSE FIX (2026-04-29)**: addis was sign-extending simm16 to 64 bits per PPC ISA, but Xbox 360 user code runs in 32-bit ABI. When sign-extended addis result mixed with zero-extended lwz value, the 64-bit unsigned subfc compare yielded wrong CA, breaking BST traversals. Fix: truncate addis result to 32 bits (`result as u32 as u64`). Throw at sub_82175F10→sub_82454770 fully silenced WITHOUT the r31=14 hack (now removed). All 506+ tests pass. -n 4B runs clean. Renderer plateau at swaps=2 persists — not caused by the addis bug. Lookup other simm16-immediate instructions (`addi rD,r0,...`, `addic`, `subfic`) for similar bugs if more issues surface.
- [project_xenia_rs_sylpheed_event_chain_2026_04_29.md](project_xenia_rs_sylpheed_event_chain_2026_04_29.md) — **Stage 3 Path A traced + DECISIVE FINDING (2026-04-29)**: The BST callback-walker hypothesis is RULED OUT (BST module has no walker; only 2 indirect calls in the module are byte-walkers for string transforms). HOWEVER traced upstream and **found that 0x828F3F68 IS registered in the BST by sub_82175E68 at instruction 0x82179134, eight instructions before the validation site sub_82175F10 at 0x82179144 — same function, same thread, sequential execution**. This means the PPC validator's failure to find 0x828F3F68 in the just-populated BST is the PRIMARY bug. **Our throw fix masks it but doesn't fix it.** The likely same memory-coherence issue prevents event 0x1004's signal from being visible to its waiter. Next session: trace specific guest-memory addresses (e.g. `0x40249F68`) at the emulator level, log every write+read with PC, find the visibility bug. This is the unresolved paradox from [project_xenia_rs_sylpheed_throw_2026_04_28.md](project_xenia_rs_sylpheed_throw_2026_04_28.md) — now confirmed as load-bearing.
- [project_xenia_rs_sylpheed_stage3_2026_04_29.md](project_xenia_rs_sylpheed_stage3_2026_04_29.md) — **Stage 3 thread-state map (2026-04-29)**: post-throw-fix run at -n 4B confirms deadlock isn't slow-init. 10 worker threads parked, 4 of them on `mr=true` events with `sig=false`: handle 0x1004 (tid=10, sub_82178950), 0x100c (tid=2, sub_82181830), 0x15e4 (tid=16, sub_82170430), 0x42450b5c (tid=6, sub_824CD458). tid=1 main is in a healthy frame-poll loop (PC=0x822F1E00 inside sub_822F1AA8). The throw fix is necessary but not sufficient — Sylpheed renderer cascade has additional breaks. Next session candidates: (A) trace producer for event 0x1004, (B) per-handle NtSetEvent telemetry, (C) Canary diff.
- [project_xenia_rs_sylpheed_throw_fix_2026_04_29.md](project_xenia_rs_sylpheed_throw_fix_2026_04_29.md) — **Sylpheed throw silenced (2026-04-29)**: `rtl_leave_critical_section` HLE detects the failing BST validation (cs=0x828F3DA8, lr=0x824546C8, our Rust CEIL finds the node, but PPC computed r31=32) and overrides ctx.gpr[31]=14 → sub_82454600 returns valid → no throw. Game advances to loading renderer resources (ptc_pack.xpr) + spawning all 18 worker threads. **But draws=0 plateau persists** — Stage 2 gate NOT met. The PPC-vs-Rust traversal paradox remains unexplained. Workers park on unsignaled events (Stage 3 territory).
- [project_xenia_rs_sylpheed_throw_2026_04_28.md](project_xenia_rs_sylpheed_throw_2026_04_28.md) — **Sylpheed VdSwap=2 plateau diagnosed (2026-04-28)**: rtl_raise_exception rewritten with correct EXCEPTION_RECORD layout + 6-level PPC stack walk + runtime_error decoder (one-shot via new `KernelState::cxx_throw_logged`). Single throw on tid=1 at ~1.2s: `std::runtime_error("lhs is not valid instance")` at PC `0x824547e4` in `sub_82454770` (a generic intrusive-list validator with 29 callers, called from a chain inside `silph::Silph::Impl::OnInit`'s config-tree walker). Canary's RtlRaiseException is also a stub — so the divergence is upstream. Memory file lists next-session candidates (trace registry, or implement minimal SEH).
- [project_xenia_rs_hle_import_fixes_2026_04_27.md](project_xenia_rs_hle_import_fixes_2026_04_27.md) — **HLE import fixes (2026-04-27)**: KeInitializeSemaphore now seeds count/limit (was zero-fill), XexGet{Module,Procedure}Address use distinct `HMODULE_XBOXKRNL`/`HMODULE_XAM` pseudo-handles + reverse `(ModuleId,ordinal)→thunk_addr` map populated from main.rs Phase 1. 76 kernel tests pass; -n 30M --parallel still reaches VdSwap=2 with unimpl=0.
- [project_xenia_rs_disasm_unify_phase4.md](project_xenia_rs_disasm_unify_phase4.md) — **Disassembler unification Phase 4 complete (2026-04-27)**: assert-based JSON-fixture goldens for base/extended/VMX128 mnemonics + 7 VMX128 accessor unit tests + analysis-shim parity test + DB schema golden (PRAGMA table_info per-table, 5 SQL views). Old println-only audits deleted. All 4 phases complete; constraints honored end-to-end.
- [project_xenia_rs_disasm_unify_phase3.md](project_xenia_rs_disasm_unify_phase3.md) — **Disassembler unification Phase 3 complete (2026-04-27)**: db.rs split into `ingest_instructions` + `write_analysis_results`; new `target_hex` column on instructions; `sql_views.rs` defines 5 additive views; new `--analyze=rust|sql|both` flag (default rust). Cross-check confirms Rust and SQL agree on 299,615 branch xrefs; reachability: 7,557/12,156 functions (62%) reachable from entry. Two bugs found+fixed: kind-tag mismatch (xrefs.kind uses short `br`/`j`/`call`, not long names) and reachability seed-collapse.
- [project_xenia_rs_disasm_unify_phase2.md](project_xenia_rs_disasm_unify_phase2.md) — **Disassembler unification Phase 2 complete (2026-04-27)**: `iter_disasm` iterator in xenia-cpu yields `DisasmItem`s; `enrich_section` adds analysis context; 3 sinks (text/JSON/DuckDB) consume `RichDisasmItem`. New `xenia dis --json` flag. db.rs and formatter.rs both drive through the iterator. End-to-end smoke verified: 1.87M rows match between DB and JSONL.
- [project_xenia_rs_disasm_unify_phase1.md](project_xenia_rs_disasm_unify_phase1.md) — **Disassembler unification Phase 1 complete (2026-04-27)**: single source of truth in `xenia-cpu/disasm.rs` (`format` returns `DisasmText`); analysis `ppc.rs` collapsed 1374→30 LOC shim; `DecodedInstr` unchanged at 8 bytes; silent VMX128 bit-position bug fixed. Phases 2-4 (iterator+sinks, ingest/analyze split + SQL views, fixture goldens) pending.
- [project_xenia_rs_m3_realpar_step_08.md](project_xenia_rs_m3_realpar_step_08.md) — **M3 real-par Step 08 / SESSION COMPLETE (2026-04-27)**: real per-HW-thread parallelism landed. N=6 workers + coord + 7-party phaser. 430 tests; 4 lockstep combos match golden; --parallel boots sylpheed to VdSwap=2 in 57s; 20× stress passed. **Perf gate NOT met** — --parallel ~24× slower than lockstep (target was 1.5× faster); deferred parking (Step 05) is the next session's first task.
- [project_xenia_rs_m3_realpar_step_06_07.md](project_xenia_rs_m3_realpar_step_06_07.md) — **M3 real-par Step 06+07 (2026-04-27)**: stress harness (parallel_stress.rs) — 20×@5M passed; perf gate measured — 24× slowdown vs lockstep. parallel_stress_long (100×@50M) wired but #[ignore]-gated (impractical at current perf).
- [project_xenia_rs_m3_realpar_step_05.md](project_xenia_rs_m3_realpar_step_05.md) — **M3 real-par Step 05 (2026-04-27)**: slot-wake parking attempted but DEFERRED. TOCTOU race between coord's mask publish and worker's mask read across round boundaries — the phaser counter wrapped, B2 timed out. Reverted to Step 04 design (workers always arrive at B1). Documented 3 race-free alternatives for follow-up.
- [project_xenia_rs_m3_realpar_step_04.md](project_xenia_rs_m3_realpar_step_04.md) — **M3 real-par Step 04 (2026-04-27)**: real N=6 workers + main-thread coordinator + 7-party phaser via thread::scope. 5 lockstep combos match golden; --parallel digest diverges ~7 instr at -n 2M (expected); -n 30M --parallel reaches VdSwap=2 with halts==0. ~18x slower than lockstep (Step 05+07 will address).
- [project_xenia_rs_m3_realpar_step_03.md](project_xenia_rs_m3_realpar_step_03.md) — **M3 real-par Step 03 (2026-04-26)**: run_execution_parallel with per-round drop/reacquire around step_block; --parallel branch routes through it. Single worker; 430 tests; 6 golden combos match; sylpheed -n 30M --parallel reaches VdSwap=2 (3866ms).
- [project_xenia_rs_m3_realpar_step_02.md](project_xenia_rs_m3_realpar_step_02.md) — **M3 real-par Step 02 (2026-04-26)**: per-slot body split into worker_prologue + worker_epilogue, WorkerCtx owns per-HW-slot block+decode cache. Lockstep bit-identical; 430 tests; 6 golden combos match.
- [project_xenia_rs_m3_realpar_step_01.md](project_xenia_rs_m3_realpar_step_01.md) — **M3 real-par Step 01 (2026-04-26)**: coord_pre_round/idle_advance/post_round + RoundCtl carved out of run_execution. Pure motion refactor; 430 tests pass; all 6 golden combos match.
- [project_xenia_rs_m3_followup_real_parallelism_plan.md](project_xenia_rs_m3_followup_real_parallelism_plan.md) — **HAND-OFF (2026-04-26)**: precise design for the N=6 spawn follow-up session. Includes worker-loop pseudocode, coordinator-thread responsibilities, 9 specific concurrency hazards to handle, ~250-350 line size estimate, and the verification matrix the session must pass. Read this first before starting M3-real-parallelism work.
- [project_xenia_rs_m3_step_08_verification.md](project_xenia_rs_m3_step_08_verification.md) — **M3 session complete (2026-04-26)**: phaser, per-thread block caches, --parallel spawn (N=1 substrate), reservation table activation, full verification. 411 tests pass; all 6 flag combos golden-match; sylpheed -n 30M --parallel reaches VdSwap=2 with halts==0. Per-step memory files: project_xenia_rs_m3_step_03_04_kernel_wrap_spawn.md, project_xenia_rs_m3_step_07_reservation_activation.md, project_xenia_rs_m3_step_08_verification.md. N=6 actual parallelism deferred per the followup memo.
- [project_xenia_rs_concurrency_m3_progress.md](project_xenia_rs_concurrency_m3_progress.md) — earlier (superseded) M3 status doc; kept for context but the step-files are authoritative.
- [project_xenia_rs_concurrency_m2_progress.md](project_xenia_rs_concurrency_m2_progress.md) — **M2 substantively complete** (2026-04-26): ReservationTable, ThreadRef gen-packing, atomic bump allocators, per-slot pending_local_irq, --reservations-table flag. M2.6/M2.7 (KernelStateInner + per-slot Mutex<HwSlot>) deferred to M3. 405 tests pass; sylpheed -n 2M golden matches all flag combos.
- [project_xenia_rs_concurrency_m1_progress.md](project_xenia_rs_concurrency_m1_progress.md) — **M1 complete** (2026-04-26): default GPU backend is threaded; DrainFence RPC + parker + fence helpers all live; 395 tests pass; sylpheed -n 2M golden matches both modes; VdSwap=1/=2 fire end-to-end.
- [project_xenia_rs_current_state.md](project_xenia_rs_current_state.md) — **start here** — where Sylpheed boot sits now, active blockers, investigation tools, memory caveats
- [project_xenia_rs_scheduler.md](project_xenia_rs_scheduler.md) — **scheduler architecture (post-2026-04-23 refactor)** — 6 HW slots + per-slot runqueues, ThreadRef identity, bind-and-migrate affinity
- [project_xenia_rs_ui.md](project_xenia_rs_ui.md) — stable architecture: threading bridge, GPU pipeline, MMIO, scheduler, HLE primitives, HUD, observability
- [project_xenia_rs_cli.md](project_xenia_rs_cli.md) — CLI commands, flags, env vars, DB table layering
- [project_xenia_rs_desktop_app.md](project_xenia_rs_desktop_app.md) — desktop app UI/UX (disasm/debugger/analyzer share one workspace)
- [project_xenia_rs_edram_resolve_gap.md](project_xenia_rs_edram_resolve_gap.md) — TILE_FLUSH byte copy now lands (clear-resolve + bitwise-equivalent 32bpp); file lists smaller remaining gaps + backlog order
- [project_xenia_rs_duckdb.md](project_xenia_rs_duckdb.md) — analysis DBs are **DuckDB**, not SQLite despite `.db` extension — use `python3 -c "import duckdb; ..."`
- [project_xenia_rs_perf_tier4.md](project_xenia_rs_perf_tier4.md) — Tier-4 perf landed (2026-04-25): MMIO fast-reject + basic-block cache + GPU pacer; 318→136 ms (2.3×); `XENIA_FORCE_PER_INSTR=1` env var for A/B
- [project_xenia_rs_handle_audit.md](project_xenia_rs_handle_audit.md) — **2026-04-25 session**: `--trace-handles` audit harness landed, original HLE sync gap no longer reproduces at -n 500M, MSAA averaging + 64bpp source/clear-resolve in resolve.rs, wgpu RT readback deferred (foundation in place)