# Iterate 2.D fire-pattern diff — report **Date**: 2026-05-27. **Mode**: read-only re-analysis of cached iterate-2D-peer-producer-trace JSONLs. Zero LOC engine/canary changes. ## Headline **DIVERGENT-FIRE-PATTERN-FOUND — multiple distinct producer LRs fire in canary with ZERO ours analog across ALL tids.** Canary total NtSetEvent+NtReleaseSemaphore fires: **79,014** across **33** distinct (op,lr) tuples. Ours total (IAT + LR thunk trace): **303** across **19** distinct (op,lr) tuples. Tuples in canary with **zero** ours analog: **28** carrying **29,441** canary fires (37.3% of canary's volume). Matched tuples: **5** carrying **49,573** canary fires. Extra-in-ours tuples (not in canary): **14** (sanity tally only). ## Reading-error #28 discipline Diff key omits tid — we ask 'does this canary (op, lr, handle-class) fire at all in ours, on ANY tid'. Tids are tracked separately per key for context but never used as cross-engine identity. ## Top divergent tuples (canary fires N, ours fires 0) | # | op | LR | canary fires | canary tids | canary handles | likely fn | |--:|----|----|--:|--|--|---| | 1 | set | `0x824d292c` | 16,452 | 14 | 0xf800007c | sub_824D2878 (AUDIO worker entry-2 γ-set) | | 2 | set | `0x82506c90` | 2,378 | 27 | 0xf8000180 | sub_82506B08+0x188 (worker dispatch γ-set) | | 3 | set | `0x82508510` | 2,373 | 14,15 | 0xf8000184 | sub_82508400+0x110 (worker dispatch γ-set) | | 4 | set | `0x82508524` | 2,373 | 14,15 | 0xf8000180 | sub_82508400+0x124 (worker dispatch γ-set) | | 5 | set | `0x82506f9c` | 2,355 | 28 | 0xf800017c | sub_82506DE8 (worker dispatch γ-set) | | 6 | set | `0x82508358` | 2,350 | 13 | 0xf8000188 | sub_825078D8+0xa80 (worker dispatch γ-set) | | 7 | set | `0x824aafc8` | 1,113 | 6,10,27,28 | 0xf800004c, 0xf8000050, 0xf8000078 (+29) | sub_824AAF50 (KeSetEvent game wrapper) | | 8 | set | `0x827e843c` | 15 | 14 | 0xf80000ac | (unknown) | | 9 | set | `0x82178d9c` | 6 | 16 | 0xf8000104 | (unknown) | | 10 | set | `0x824d0868` | 5 | 16 | 0xf8000168 | (unknown) | | 11 | set | `0x824d0c6c` | 3 | 16 | 0xf8000168 | (unknown) | | 12 | set | `0x824d08c0` | 2 | 14,16 | 0xf8000168 | (unknown) | | 13 | set | `0x824d091c` | 1 | 6 | 0xf8000168 | (unknown) | | 14 | set | `0x822d30ec` | 1 | 6 | 0xf80000c8 | (unknown) | | 15 | set | `0x82507abc` | 1 | 13 | 0xf8000178 | (unknown) | ## Top under-firing matched tuples (canary >>> ours) | op | LR | canary | ours | ratio | likely fn | |----|----|--:|--:|--:|---| | release | `0x824d229c` | 16,452 | 1 | 0.01% | sub_824D21F0+0xAC (AUDIO dispatch γ-release) | | set | `0x824d2a44` | 16,452 | 1 | 0.01% | sub_824D29F0 (AUDIO worker entry γ-set) | | set | `0x824aa304` | 15,765 | 60 | 0.38% | sub_824AA2F0 (NtSetEvent game wrapper) | | release | `0x824ab168` | 903 | 90 | 9.97% | sub_824AB158 (NtReleaseSemaphore game wrapper) | ## γ-signaler family intersection (AUDIT-069 S3/S2) | LR | op | canary | ours | likely fn | |----|----|--:|--:|---| | `0x824aa304` | set | 15,765 | 60 | sub_824AA2F0 (NtSetEvent game wrapper) | | `0x824aafc8` | set | 1,113 | 0 | sub_824AAF50 (KeSetEvent game wrapper) | | `0x824ab168` | release | 903 | 90 | sub_824AB158 (NtReleaseSemaphore game wrapper) | | `0x824d229c` | release | 16,452 | 1 | sub_824D21F0+0xAC (AUDIO dispatch γ-release) | | `0x824d292c` | set | 16,452 | 0 | sub_824D2878 (AUDIO worker entry-2 γ-set) | | `0x824d2a44` | set | 16,452 | 1 | sub_824D29F0 (AUDIO worker entry γ-set) | | `0x82506c90` | set | 2,378 | 0 | sub_82506B08+0x188 (worker dispatch γ-set) | | `0x82506f9c` | set | 2,355 | 0 | sub_82506DE8 (worker dispatch γ-set) | | `0x82508358` | set | 2,350 | 0 | sub_825078D8+0xa80 (worker dispatch γ-set) | | `0x82508510` | set | 2,373 | 0 | sub_82508400+0x110 (worker dispatch γ-set) | | `0x82508524` | set | 2,373 | 0 | sub_82508400+0x124 (worker dispatch γ-set) | Of 28 missing-in-ours tuples: **7** intersect the AUDIT-069 γ-signaler family, **21** lie outside it (fresh chains). ## Wedge-related LRs (cache-thread / worker-dispatch self-release) These LRs are the deep game-side call sites that route through `sub_824AB158` (NtReleaseSemaphore wrapper) and ultimately feed the wedge's wait predicate (work-semaphore handle 0x1050 at guest VA [0x828F3BC4]). **Note: canary's audit_70 hook fires at the IAT-thunk depth and reports the wrapper-return LR (`0x824AB168`) for ALL NtReleaseSemaphore fires** — it never sees deeper game-side LRs. Ours's `--lr-trace=0x824AB158` probe captures one level deeper (the game-wrapper caller). So canary count here is always 0; the value of this table is **ours's count** showing which of these game-side sites still execute at all in ours: | LR | op | canary | ours | likely fn | |----|----|--:|--:|---| | `0x82450314` | release | 0 | 6 | sub_82450218+0xFC (cache-thread release site) | | `0x82450ce0` | release | 0 | 68 | sub_82450B68+0x178 (worker self-release path 1) | | `0x82450d2c` | release | 0 | 6 | sub_82450B68+0x1C4 (worker self-release path 2) | Comparable apples-to-apples roll-up: canary's 903 fires at LR `0x824AB168` (NtReleaseSemaphore wrapper return) ↔ ours's 90 fires at the SAME LR (IAT trace). Ratio = **9.97%**. The shortfall is dominated by ours's worker tid=5 (75/903) and cache-thread tid=13 (1/903) under-firing per AUDIT-069 S6. ## Canary-only tids (entry-PC bucket inferred via release-LR clustering) These canary tids have ZERO matched ours analog at the (op,lr) level: | canary tid | total fires | matched-LR fires | missing-LR fires | distinct LRs | analog in ours? | |--:|--:|--:|--:|--:|---| | 14 | 33,546 | 16,452 | 17,094 | 6 | YES | | 4 | 16,452 | 16,452 | 0 | 1 | YES | | 6 | 10,965 | 10,945 | 20 | 7 | YES | | 2 | 5,268 | 5,268 | 0 | 1 | YES | | 15 | 4,120 | 0 | 4,120 | 2 | NO | | 27 | 2,726 | 0 | 2,726 | 2 | NO | | 28 | 2,724 | 0 | 2,724 | 2 | NO | | 13 | 2,356 | 5 | 2,351 | 3 | YES | | 10 | 800 | 419 | 381 | 4 | YES | | 16 | 24 | 2 | 22 | 13 | YES | | 18 | 16 | 14 | 2 | 3 | YES | | 17 | 8 | 8 | 0 | 1 | YES | | 11 | 5 | 5 | 0 | 1 | YES | | 0 | 1 | 0 | 1 | 1 | NO | | 21 | 1 | 1 | 0 | 1 | YES | | 7 | 1 | 1 | 0 | 1 | YES | | 26 | 1 | 1 | 0 | 1 | YES | ## Canary thread families with no ours analog (entire-thread divergence) Per the 'Canary-only tids' table above, **three canary tids (15, 27, 28) have ZERO matched-LR fires** — every event they produce is on an LR ours never visits. Their fire patterns: - **canary tid=15** (4,120 fires): exclusively on LRs `0x82508510` (2,373×, sub_82508400+0x110) and `0x82508524` (2,373×, sub_82508400+0x124) — paired worker-dispatch γ-set sites. Co-fires with canary tid=14 on the same LRs. - **canary tid=27** (2,726 fires): exclusively on LR `0x82506c90` (2,378×, sub_82506B08+0x188, worker dispatch) + `0x824AAFC8` (348×, KeSetEvent wrapper). - **canary tid=28** (2,724 fires): exclusively on LR `0x82506f9c` (2,355×, sub_82506DE8, worker dispatch) + `0x824AAFC8` (369×, KeSetEvent wrapper). **Conclusion: canary tids 15/27/28 are members of the sub_825070F0 worker fan-out cluster that ours fails to spawn or whose start ctx is mis-initialized.** This matches the Review A Step 1 force-spawn-workers diagnosis (workers spawn but fault on `[ctx+44] = 0xBCE25640` unmapped read). Canary tid=14 (33,546 fires, the audio worker A) HAS a partial ours analog (ours tids 9/10/11 fire 3 total events on the audio LRs), confirming that ours DOES spawn the audio threads but they wedge after 1 iteration (per iterate-2D investigation §Step 3). ## Outcome class **Class (C) Many distributed producers missing** (confirms iterate-2D's outcome). Not a single (lr, handle) tuple — at least 15+ distinct call sites in canary have zero ours analog on any tid. ## Recommendation **DROP-TO-OPTION-2 (boot-time delta replay), NOT force-spawn crowbar.** Why not the crowbar (Option-C from goal): Review A Step 1 attempted exactly that on 2026-05-27 (`review-a-step1-force-spawn/progression-result.md`) and FAILED the PRIMARY progression gate. The 4 workers spawn under `--force-spawn-workers` but fault ~159 instructions in at `vtable[35..38]` dispatching on `[ctx+44]=0xBCE25640` — an unmapped VA in ours's allocator namespace. Force-spawning without first fixing the upstream ctx-state-installer chain is futile. Why Option-2: iterate-2D §Step 3 documented a **1.3 s upstream timing skew** (canary first audio fire at host_ns=278 ms; ours first audio fire at 1,587 ms — 5.7× later). The 28 missing producer LRs found here are downstream consequences of that delay. Diffing the first ~1200 phase-a events to find the single early-init kernel-call divergence is cheaper, doesn't add LOC, and likely cascades to most of the 28 LRs at once. The canary's tid=6 ↔ ours's tid=1 main-thread bootstrap matches for 20 releases (per AUDIT-069 S6) then diverges — that's the right window to inspect. Concrete next iterate: `iterate-2E-boot-delta-replay` — ~0 engine LOC, ~100 LOC investigation. Read existing phase-a event logs at `xenia-rs/audit-runs/phase-a-diff-harness/` (dated 2026-05-26) for both engines, time-bucket by host_ns, diff at first kernel-import-call mismatch. If the harness's diff path already covers this, the analysis may be pure data work. ## Cross-check vs γ-signaler family γ-family LRs (defined per AUDIT-069 S3/S2) have **7** representatives among the missing-in-ours set. The remaining **21** missing tuples lie outside the γ-family — these are fresh producer chains the audit-069 work never characterized: - `0x827e843c` (set, canary=15 fires, tids=[14]) - `0x82178d9c` (set, canary=6 fires, tids=[16]) - `0x824d0868` (set, canary=5 fires, tids=[16]) - `0x824d0c6c` (set, canary=3 fires, tids=[16]) - `0x824d08c0` (set, canary=2 fires, tids=[14, 16]) - `0x824d091c` (set, canary=1 fires, tids=[6]) - `0x822d30ec` (set, canary=1 fires, tids=[6]) - `0x82507abc` (set, canary=1 fires, tids=[13]) ## Cascade check - A (acquire both engines' fire data): **PASS** — cached canary 79,014 events + ours 153 events. - B (build cross-engine tuple key respecting reading-error #28): **PASS** — keyed on (op, lr); handle namespace differences absorbed by structural LR identity. - C (identify divergent tuples): **PASS** — see top-15 table above. - D (attribute cause): **PASS MEDIUM** — class (C) structural ladder; not a single bug. - E (recommend next iterate): **PASS** — Option-2 boot-time delta replay (per iterate-2D's investigation §Step 5). ## Tripstones honored - **#28** (per-engine tid stability): tids omitted from diff key. - **#39** (composite progression metric): not relevant — this is an investigation, not a progression iterate. - **#40** (single-keystone framing): explicitly checked and falsified. ## Artifacts Under `xenia-rs/audit-runs/iterate-2D-fire-pattern-diff/`: - `diff.py` — this analysis script. - `report.md` — this report. - `divergent-tuples.csv` — full list of missing-in-ours tuples for further xref. - `matched-tuples.csv` — full list of matched tuples with canary/ours counts.