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

96 KiB
Raw Permalink Blame History

Memory Index

  • audit_058_sub825070F0_activation — 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 — 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 — 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 — 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_landedTRACK 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 — 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🔥 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_traceCONCRETE 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🔥 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 (RegisterToFactorysilph::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 — 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_821748F0sub_821C4EB0(UImpl@GamePart_Title@silph)sub_821CC3F8(AVGamePart_Title)sub_821CBA08sub_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_fixPATH 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_synthesisAUTONOMOUS-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 — 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 — 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 — 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 — 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🎯 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🎯 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🎯 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🎯 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 0x00001454NtCreateEvent 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🎯 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🎯 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🎯 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🎯 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🎯 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🎯 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🎯 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. 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 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🔍 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🎯 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🎯 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🎯 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🎯 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🎯 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🎯 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🎯 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🎯 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🎯 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🎯 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🎯 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🎯 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🎯 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🎯 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🎯 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🎯 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🎯 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🔍 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🎯 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🎯 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🎯 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🎯 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🎯 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🎯 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🎯 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🎯 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🎯 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🎯 KRNBUG-XAM-001 (2026-05-04, LANDED): XGetAVPack 0x168 (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🎯 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 FLIPPEDXGetAVPack: 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🎯 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🎯 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🎯 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🔍 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🎯 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🎯 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🎯 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🛠️ 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🎯 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🔍 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🎯 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.mdStage 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 — now confirmed as load-bearing.

  • project_xenia_rs_sylpheed_stage3_2026_04_29.mdStage 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.mdSylpheed 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.mdSylpheed 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.mdHLE 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.mdDisassembler 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.mdDisassembler 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.mdDisassembler unification Phase 2 complete (2026-04-27): iter_disasm iterator in xenia-cpu yields DisasmItems; 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.mdDisassembler 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.mdM3 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.mdM3 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.mdM3 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.mdM3 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.mdM3 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.mdM3 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.mdM3 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.mdHAND-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.mdM3 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 — earlier (superseded) M3 status doc; kept for context but the step-files are authoritative.

  • project_xenia_rs_concurrency_m2_progress.mdM2 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) deferred to M3. 405 tests pass; sylpheed -n 2M golden matches all flag combos.

  • project_xenia_rs_concurrency_m1_progress.mdM1 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.mdstart here — where Sylpheed boot sits now, active blockers, investigation tools, memory caveats

  • project_xenia_rs_scheduler.mdscheduler architecture (post-2026-04-23 refactor) — 6 HW slots + per-slot runqueues, ThreadRef identity, bind-and-migrate affinity

  • project_xenia_rs_ui.md — stable architecture: threading bridge, GPU pipeline, MMIO, scheduler, HLE primitives, HUD, observability

  • project_xenia_rs_cli.md — CLI commands, flags, env vars, DB table layering

  • project_xenia_rs_desktop_app.md — desktop app UI/UX (disasm/debugger/analyzer share one workspace)

  • 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 — analysis DBs are DuckDB, not SQLite despite .db extension — use python3 -c "import duckdb; ..."

  • 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.md2026-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)