Files
xenia-rs/audit-runs/audit-046-loop-exit/findings.md
MechaCat02 8e709b0a24 chore: track audit-runs summary artifacts (md/csv/diff/txt/json/etc)
Snapshot of every non-log artifact under audit-runs/ from audits 003
through 058: findings.md per audit, comparison CSVs, probe diffs,
schema docs, register-dump txts, lr-trace JSONL streams, the saved
canary patch diffs, etc. ~284 files / ~52 MB total.

Excluded (per .gitignore): probe stdout/stderr/log streams (the raw
firehose), guest-memory dumps under audit-026/027/029 (4.5 GB of
.bin files; *.bin pattern added to .gitignore this commit).

Also adds the orphan audit-058-sub825070F0-activation directory that
a subagent accidentally created at project-root instead of
under xenia-rs/audit-runs/; relocated to its proper home.

Purpose: cross-machine continuity. With these summaries committed,
a fresh clone gives the next session the full per-audit context
(findings + tables + cascade predictions) without dependence on
local-only working tree.

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

140 lines
8.1 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 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: `<NO_SIGNALS>` 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