# AUDIT-046 — Loop-exit predicate at 0x82450904 **Date**: 2026-05-10 **Mode**: READ-ONLY **xenia-rs HEAD**: `7bc9e3a` (unchanged) **xenia-canary HEAD**: `6de80dffe` (patch reverted clean at session close) **Discipline gate**: 5/5 PASS ## Question Does the audit-034 / audit-035 frame-chain divergence at `sub_82450720+0x160..+0x1F4` reflect a real behavioral divergence — specifically, does the loop-exit `bne` predicate at PC `0x82450904` succeed early in canary (3.75/5 iters per audit-034) and fail every iter in ours (5/5)? If yes, audit-035's slot-pointer heap-region split (canary `0xBC3xxxxx` physical vs ours `0x4024xxxx` v40-bump) becomes a sharp causal target. ## Method 1. Re-applied audit-030 `--log_lr_on_pc` patch verbatim from `audit-runs/audit-045-cluster-ctor-probe/canary-patch.diff` (30 LOC, 4 files in xenia-canary). Saved here as `canary-patch.diff`. 2. Built canary Debug variant. 3. Probed canary at three PCs (60-90s wall each): - `0x82450904` — the `bne` predicate itself - `0x82450918` — the loop-completion no-match exit (post-`bdnz` block-entry) - `0x82450934` — early-match handler (block-entry on predicate success while `r25<5`) 4. Probed ours at four block-entry PCs (`-n 500000000`): - `0x82450720` — outer-call entry (`sub_82450720`) - `0x82450890` — loop-back top - `0x82450908` — post-bne fall-through (fires every iter that fails predicate) - `0x82450918` — loop-completion no-match exit 5. Dumped slot table at `0x828F3BD4` + 2 adjacent windows in ours via `--dump-addr=0x828F3BD4,0x828F3C14,0x828F3C54`. 6. Reverted canary patch (`git checkout` of touched files) and confirmed clean tree. ⚠️ Per AUDIT-045 reading-error class #13: ours `--pc-probe` only fires at basic-block entry; canary `--log_lr_on_pc` fires per-instruction inline in HIR. `0x82450904` is the `bne` instruction itself (mid-block) → ours-side direct probe at that PC would yield 0 fires regardless. Worked around by probing the block-entry alternatives `0x82450908` (post-bne fall-through, fires every iter that fails) and `0x82450918` (loop-completion exit, fires once per outer call). ## Results ### Canary (per probe) | PC | Site | Wall | Fires | |----|------|------|-------| | 0x82450904 | `bne` predicate | 70s | **140** | | 0x82450918 | no-match completion | 70s | **22** outer-call completions | | 0x82450934 | early-match handler | 70s | **0** | Canary's predicate fires 140 times across 22 outer-call completions ≈ **5+ iters per outer call**. The predicate never resolves to `cr0.eq=1` (early-match handler `0x82450934` sees zero fires). Canary always exits via the no-match path. ### Ours (single multi-PC run, `-n 500000000`) | PC | Site | Fires | |----|------|-------| | 0x82450720 | `sub_82450720` outer entry | 16 | | 0x82450874 | post-prologue block-entry | 16 | | 0x82450880 | post-prologue block-entry | 16 | | 0x82450890 | loop-back top | **64** (= 16 outer × 4 loop-backs) | | 0x82450908 | post-bne fall-through | **80** (= 16 outer × 5 fail iters) | | 0x82450918 | no-match completion | **16** | Ours exhibits **5/5 iters per outer call** with **0 early matches**, falling through to `0x82450918` exactly once per outer call. ### Slot table at `0x828F3BD4` (ours, end-of-run) Walking 5 slots × 20 bytes from base, bytes `[0x0C..0x13]` per slot are the (ptr, size) pair: | Slot | Offset | Content | Region | |------|--------|---------|--------| | 0 | 0xBD4 | all zeros | — | | 1 | 0xBE8 | ptr=`0x4024A240` size=`0x00000008` | v40-bump | | 2 | 0xBFC | ptr=`0x4024AEE0` size=`0x00000008` | v40-bump | | 3 | 0xC10 | all zeros (audit-035's "over-cycled" slot, now stable) | — | | 4 | 0xC24 | ptr=`0x4024A300` size=`0x00000008` | v40-bump | Slot 0 zero in both engines per audit-035. Audit-035 reported canary slots 1/2/4 holding `0xBC3xxxxx` physical-heap pointers; here ours slots 1/2/4 hold `0x4024xxxx` v40-bump pointers. **Region split confirmed and persistent.** ## Verdict ### Hypothesis FALSIFIED The loop-exit predicate at `0x82450904` does **not** match in either engine. Both engines: 1. Run the full 5/5 iters every outer call. 2. Never resolve the predicate to `cr0.eq=1` (canary `0x82450934` early-match handler sees 0 fires). 3. Exit via the no-match path at `0x82450918`. ### Why audit-035's region split is behaviorally inert The predicate at `0x82450904` compares two values: - **LHS**: a sum derived by `sub_82451E20`'s vptr-walk return (objects in the same heap region as the slot table) - **RHS**: each slot's local sum (ptr + size pair from the slot table itself) Both LHS and RHS originate from the **same heap region within a given engine**. In ours, both come from v40-bump (`0x4024xxxx`). In canary, both come from physical (`0xBC3xxxxx`). The cross-engine address-space difference is **internally consistent** within each engine's view, so it cancels as a divergence cause at this predicate. The slot-table region split is REAL DATA but does NOT gate any predicate behavior here. **The data observation does not become a behavioral divergence.** ### Why audit-034's "canary 3.75/5 vs ours 5/5" measurement is also falsified Canary 70s probe yields 140 fires of `0x82450904` across 22 outer-call completions = ~6.4 fires/call (5 fail-iters + tail). Ours yields 80 fail-iter fires across 16 outer-call completions = exactly 5/5. **Both engines exhibit identical 5/5 loop shape.** Audit-034's earlier measurement was either pre-overhaul or stale. ## Strategic implication The audit-035/036 frame-chain divergence at `sub_82450720` is now triple-refuted as a causal target: | Audit | Refuted layer | |-------|---------------| | 036 | "η-class record-layout divergence as stated" — refined to ε-class heap-region | | 043 | ε-class heap-region as "missing/wrong write at +0x00" — VA-equality fallacy (12th reading-error class) | | 046 | ε-class heap-region as causally responsible at predicate `0x82450904` (this audit) | **Recommendation: drop the `sub_82450720` chain entirely as a critical-path target.** The slot-table region split is data hygiene, not a behavioral gate. ## Reading-error class 13 reconfirmed Mid-block PCs are unprobeable in ours via `--pc-probe`; canary's `--log_lr_on_pc` fires per-instruction. Working pattern validated here: probe the post-bne block-entry PC (`0x82450908`) instead — fires every fail iter as expected (80 = 16×5). Plus the loop-completion block-entry (`0x82450918`) for outer-call counting (16). Future audits should follow this pattern when the target is a mid-block predicate. ## Recommended AUDIT-047 **γ-cluster handle wedges per audit-042**. Concrete stalled handles at end-of-run in our impl: `0x10A0+0x10A4` (Event+Sema worker pair, tid=6), `0x12AC` (Sema with 2 waiters, tid=14,15), `0x1004` (Event/Manual, tid=11), plus `0x1020/0x1040/0x1544/0x1578`. These are γ-class missing-signaler bugs — concrete and reachable. Sharp 4-dim cascade prediction (γ-fix on a single wedge): - A: signal_attempts on the wedged handle 0 → ≥1 - B: stalled tid state Blocked → Ready - C: `` count drops ≥2 - D: `swaps>2` OR `draws>0` UNKNOWN — γ-cluster typically plateaus on a sister wedge, low cascade probability per audit-042 Cost: 1 ours run + 1-2 canary probes ≈ ~10 min runtime + analysis. ## Discipline confirmation - xenia-rs HEAD `7bc9e3a` unchanged. No source modifications, no commits. - xenia-canary HEAD `6de80dffe` clean tree (`git status --short` empty for tracked files after revert). - Tests count: not re-run (no source changes; preserved at 645 per audit-038 baseline). - Lockstep determinism: not re-run (no source changes). - Master plateau: swaps=2 draws=0 intact. ## Trace artifacts (this directory) - `canary-patch.diff` — verbatim audit-045 patch - `canary-0x82450904.{log,err}` — 22MB, 140 fires - `canary-0x82450918.{log,err}` — 21MB, 22 outer-call completions - `canary-0x82450934.{log,err}` — 28MB, **0 fires** (early-match handler) - `ours-entry-probe.{log,err}` — 16 outer-call entries - `ours-loop-probe.{log,err}` — 64 loop-back fires + 16 completion fires - `ours-loop-detailed.{log,err}` — 80 post-bne fall-through fires + 16 completion fires - `slot-table-dump-ours.{log,err}` — 5-slot table at 0x828F3BD4 with v40-bump pointers - `findings.md` — this document