# Phase 2.0 — Suspect re-verification (Stage 2, 2026-05-14) Stage 1 flagged 7 imports as "MATCH-but-suspect": classified MATCH at inventory time but with body shorter than canary, suggesting possible DIVERGENT-shallow status. This document records the verdict for each after byte-level scrutiny of both engines' source. Methodology: read canary impl + ours impl side-by-side, ask "for the observable inputs (Phase A `kernel.return.payload.*` fields, guest-memory writes flowing to subsequent `kernel.call.payload.*` fields) is the output bit-equivalent?". Cite the exact axis when divergent. ## Verdict summary | # | Import | Verdict | In-scope this stage? | Notes | |---|---|---|---|---| | A | `RtlFillMemoryUlong` | **MATCH** (false alarm) | n/a | See §A | | B | `XMACreateContext` | DIVERGENT (signature) | **NO** (T3 audio) | See §B | | C | `XamUserGetSigninState` | DIVERGENT (state coupling) | **NO** (T3 XAM) | See §C | | D | `XamUserGetXUID` | DIVERGENT (signature + state) | **NO** (T3 XAM) | See §D | | E | `MmGetPhysicalAddress` | MATCH-by-equivalence (already reclassified in Batch 0) | n/a | See §E | | F | `KeQuerySystemTime` | DIVERGENT (fake constant vs live clock) | **DEFER** (needs deterministic guest-tick clock; not LOW) | See §F | | G | `KeSetAffinityThread` | DIVERGENT (return mechanism) | **YES** (Batch 3) | See §G | Net: 3 false alarms (A, E, by analysis; plus implicit re-confirmation of others as DIVERGENT). 4 actual DIVERGENT cases (B/C/D Tier-3 defer; F defer pending clock infra; G in-scope). ## §A `RtlFillMemoryUlong` — MATCH (false alarm) **Canary** (`xboxkrnl_rtl.cc:72-83`): ```cpp uint32_t swapped_pattern = xe::byte_swap(pattern.value()); for (uint32_t n = 0; n < count; n++, p++) { *p = swapped_pattern; // direct write to uint32_t* on x86 host → LE } ``` **Ours** (`exports.rs:2380-2389`): ```rust let pattern = ctx.gpr[5] as u32; for i in 0..count { mem.write_u32(dest + i * 4, pattern); // GuestMemory.write_u32 uses val.to_be_bytes() } ``` **Byte-level equivalence**: canary writes `byte_swap(P)` as LE on x86, producing bytes `[P_byte0, P_byte1, P_byte2, P_byte3]` (where `byte_n` is the n-th byte of the original P in BE convention). Ours's `write_u32` calls `val.to_be_bytes()` and copies, producing the same bytes `[P_byte0, ...]`. For `pattern=0x11223344`: both produce `[0x11, 0x22, 0x33, 0x44]` in memory. **Verdict**: MATCH. The Stage 1 endianness suspicion was an artifact of comparing C++ source semantics (`xe::byte_swap` is loud) to Rust source semantics (`to_be_bytes` is buried in `write_u32`). The actual output bytes are bit-identical. No engine fix. ## §B `XMACreateContext` — DIVERGENT (deferred Tier-3) **Canary** (`xboxkrnl_audio_xma.cc:57`): writes allocated context VA to `*context_out_ptr`, returns `X_STATUS_NO_MEMORY` or `_SUCCESS` in r3 depending on alloc result. **Ours** (`exports.rs` near 3338): allocates a handle, stores in `ctx.gpr[3]` as a u32 return. No OUT-ptr write. **Verdict**: DIVERGENT (signature mismatch). Tier-3 audio subsystem. Defer to a future XMA/audio session. ## §C `XamUserGetSigninState` — DIVERGENT (deferred Tier-3) **Canary** (`xam_user.cc:89-99`): reads `XamState`, looks up `user_profile[user_index]->signin_state()`. Returns 0 for invalid index or unsigned user. **Ours** (`xam.rs` near 332): returns `1` for `user_index==0`, else `0`. Hardcoded. **Verdict**: DIVERGENT (state coupling). Tier-3 XAM. Defer. ## §D `XamUserGetXUID` — DIVERGENT (deferred Tier-3) **Canary** (`xam_user.cc:29-66`): 3-param signature `(user_index, type_mask, xuid_ptr)`; validates each input; reads profile XUID; writes OUT-ptr. **Ours** (`xam.rs` near 309): 2-param `(user_index, xuid_ptr)`; ignores type_mask; writes 0; always returns SUCCESS. **Verdict**: DIVERGENT (signature + state). Tier-3 XAM. Defer. ## §E `MmGetPhysicalAddress` — MATCH-by-equivalence **Canary** (`xboxkrnl_memory.cc:642-654`): heap-lookup; returns mapped physical address or 0 on lookup failure. **Ours** (`exports.rs:705-708`): masks input with `0x1FFF_FFFF`. For any address allocated through ours's heap (in the `0x4xxxxxxx` range), the result is identity (i.e. `va & 0x1FFF_FFFF` is the physical address). The lookup-failure return path is unreachable for game-allocated VAs. **Verdict**: MATCH-by-equivalence. Stage 1 classified STUB; Batch 0 re-classified MATCH (this document confirms). No engine fix in Stage 2. A future Stage may surface a divergence on the lookup-failure branch (e.g. game arithmetic on an unallocated VA), at which point the C+2 deferred 3-physical-heap memory model would need attention. ## §F `KeQuerySystemTime` — DIVERGENT (deferred — clock infra) **Canary** (`xboxkrnl_threading.cc:458-473`): reads `Clock::QueryGuestSystemTime()` (a deterministic tick-based guest clock), writes the u64 FILETIME via OUT-ptr, also updates a `KeTimestampBundle` kernel-state struct. Void return. **Ours** (`exports.rs:495-502`): writes a hardcoded fake constant `132_500_000_000_000_000` (≈ year 2021 FILETIME). No clock read, no timestamp bundle. Void return framing was fixed in Phase C+1. **Verdict**: DIVERGENT in semantics. The fake constant has produced Phase A matched-prefix 102,032 because the game has not yet read this value into a control-flow decision. Replacing with a deterministic guest-tick clock requires new infrastructure: - A `KernelState::guest_filetime()` method that derives a u64 FILETIME from `scheduler.current_tick()` or similar. - A separate `KeTimestampBundle` guest-memory struct allocated at startup and updated on each call (mirrors canary's behavior). Estimated 60-100 LOC additive plus reading-error #23 risk (the live clock value flows to the game's branch decisions). Out of scope for Stage 2 LOW sweep. Recorded in `deferred.md`. ## §G `KeSetAffinityThread` — DIVERGENT (in-scope Batch 3) **Canary** (`xboxkrnl_threading.cc:323-346`): ```cpp dword_result_t KeSetAffinityThread_entry(lpvoid_t thread_ptr, dword_t affinity, lpdword_t previous_affinity_ptr) { if (!affinity) return X_STATUS_INVALID_PARAMETER; auto thread = XObject::GetNativeObject(kernel_state(), thread_ptr); if (!thread) return X_STATUS_INVALID_HANDLE; if (previous_affinity_ptr) { *previous_affinity_ptr = uint32_t(1) << thread->active_cpu(); } thread->SetAffinity(affinity); return X_STATUS_SUCCESS; } ``` **Ours** (`exports.rs:465-474`): ```rust let handle = resolve_pseudo_handle(state, ctx.gpr[3] as u32); let new_mask = (ctx.gpr[4] as u32) as u8; let old = state.set_affinity(handle, new_mask, mem); ctx.gpr[3] = old as u64; ``` **Verdict**: DIVERGENT (return mechanism). Canary writes prev to OUT-ptr (`r5 = previous_affinity_ptr`) and returns `STATUS_SUCCESS` (0) in r3. Ours stores prev in r3 and ignores r5. Game callers expecting status in r3 will treat ours's prev-affinity as a non-zero NTSTATUS error. **Stage 2 fix (Batch 3)**: write `prev_affinity` to `*r5`, return 0 in r3, preserve canary's invalid-parameter / invalid-handle early returns. #23 risk: MED. Game's CRT may have been treating ours's r3 (prev affinity = small bitmask, 1..63 in practice) as a "success" code via 0-vs-nonzero check — i.e. always failing. Fixing to return SUCCESS=0 flips that branch direction. If matched-prefix regresses, revert.