tools(gate): -ExeOverride and -DebuggerScript for the offline pixel gate; #422 characterised over 40 instrumented runs (Campaign VM VM7)

-ExeOverride runs another AcDream.App.exe through the SAME isolated
settings/scene/capture path so two binaries compare without mixing tool
versions (VM0's recorded fieldOfView trap). -DebuggerScript launches the
client under cdb so ntdll's debug heap validates every free and a heap
corruption breaks at the corrupting site with a stack.

#422 (1-in-8 STATUS_HEAP_CORRUPTION exit after a pack-on offline capture):
16 runs attached + 24 runs under the debug heap on 1f151242, all clean
(P ~ 0.5 % at the filed rate). Recorded as not reproducible on the current
binary, carried as a watch item for the owner's VM7 matrix with the loop as
the first step if it recurs; no longer a merge blocker. Evidence under
docs/research/evidence/vm7 alongside the final pack-off-vs-base+normals
robust diff (5-10 px, lifestone band only).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
Erik 2026-08-23 04:32:27 +02:00
parent 6ac3cc1070
commit c69029bf58
7 changed files with 131 additions and 4 deletions

View file

@ -48,7 +48,7 @@ kinds. Same class as the VM6 fix; do not guess the values.
## #422 — Intermittent heap-corruption exit (0xC0000374) after a pack-on offline capture
**Status:** OPEN — filed 2026-08-22 at Campaign VM VM3; VM7 gate item (fix or characterise before merge).
**Status:** OPEN — filed 2026-08-22 at Campaign VM VM3; **characterised at VM7 (2026-08-23): NOT REPRODUCIBLE on `1f151242` in 40 instrumented runs.** 16 runs with cdb attached during warm-up (`sxe` on bpe/av/0xC0000374/0xC0000409) and 24 runs launched under cdb with ntdll's debug heap (`tools/i422/loop-debugheap.ps1``tools/run-offline-pixel-gate.ps1 -DebuggerScript tools/cdb/i422-heap-launch.cdb`): every run captured, tore down and exited 0; no heap message, no break. At the filed 1-in-8 rate, 40 clean runs has P ≈ 0.5 %, so either the rate fell with the VM6 receiver-binding changes (`eec95535``1f151242` — the world pass now always binds the shadow/atmospheric blocks; a plausible teardown-order interaction, not proven) or the trigger is environmental. Evidence: `docs/research/evidence/vm7/i422-attached-16-runs.txt`, `i422-debugheap-24-runs.txt`. Carried as a watch item for the owner's VM7 visual matrix (an exit code `-1073740940` after any pack-on run re-opens it with the debug-heap loop as the first step); no longer blocks the merge.
**Component:** rendering / render packs (Campaign AR) — native teardown
**Description:** `tools/run-offline-pixel-gate.ps1 -RenderPackPreset high` (shipped

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 MiB

View file

@ -0,0 +1,17 @@
run,exit,cdbLog,heapMsg
1,,C:\Users\erikn\source\repos\acdream\.claude\worktrees\peaceful-blackburn-5333f0\artifacts\i422\logs-01\cdb.log,(6a58.6ce4): Break instruction exception - code 80000003 (first chance)
2,,C:\Users\erikn\source\repos\acdream\.claude\worktrees\peaceful-blackburn-5333f0\artifacts\i422\logs-02\cdb.log,(1d30.1574): Break instruction exception - code 80000003 (first chance)
3,,C:\Users\erikn\source\repos\acdream\.claude\worktrees\peaceful-blackburn-5333f0\artifacts\i422\logs-03\cdb.log,(58a0.197c): Break instruction exception - code 80000003 (first chance)
4,,C:\Users\erikn\source\repos\acdream\.claude\worktrees\peaceful-blackburn-5333f0\artifacts\i422\logs-04\cdb.log,(4374.6a90): Break instruction exception - code 80000003 (first chance)
5,,C:\Users\erikn\source\repos\acdream\.claude\worktrees\peaceful-blackburn-5333f0\artifacts\i422\logs-05\cdb.log,(2e5c.6e9c): Break instruction exception - code 80000003 (first chance)
6,,C:\Users\erikn\source\repos\acdream\.claude\worktrees\peaceful-blackburn-5333f0\artifacts\i422\logs-06\cdb.log,(682c.b3c): Break instruction exception - code 80000003 (first chance)
7,,C:\Users\erikn\source\repos\acdream\.claude\worktrees\peaceful-blackburn-5333f0\artifacts\i422\logs-07\cdb.log,(51a0.179c): Break instruction exception - code 80000003 (first chance)
8,,C:\Users\erikn\source\repos\acdream\.claude\worktrees\peaceful-blackburn-5333f0\artifacts\i422\logs-08\cdb.log,(7298.3210): Break instruction exception - code 80000003 (first chance)
9,,C:\Users\erikn\source\repos\acdream\.claude\worktrees\peaceful-blackburn-5333f0\artifacts\i422\logs-09\cdb.log,(4700.ab8): Break instruction exception - code 80000003 (first chance)
10,,C:\Users\erikn\source\repos\acdream\.claude\worktrees\peaceful-blackburn-5333f0\artifacts\i422\logs-10\cdb.log,(1d2c.5efc): Break instruction exception - code 80000003 (first chance)
11,,C:\Users\erikn\source\repos\acdream\.claude\worktrees\peaceful-blackburn-5333f0\artifacts\i422\logs-11\cdb.log,(1ee4.5d30): Break instruction exception - code 80000003 (first chance)
12,,C:\Users\erikn\source\repos\acdream\.claude\worktrees\peaceful-blackburn-5333f0\artifacts\i422\logs-12\cdb.log,(2c90.9a0): Break instruction exception - code 80000003 (first chance)
13,,C:\Users\erikn\source\repos\acdream\.claude\worktrees\peaceful-blackburn-5333f0\artifacts\i422\logs-13\cdb.log,(71b8.4568): Break instruction exception - code 80000003 (first chance)
14,,C:\Users\erikn\source\repos\acdream\.claude\worktrees\peaceful-blackburn-5333f0\artifacts\i422\logs-14\cdb.log,(4d24.2704): Break instruction exception - code 80000003 (first chance)
15,,C:\Users\erikn\source\repos\acdream\.claude\worktrees\peaceful-blackburn-5333f0\artifacts\i422\logs-15\cdb.log,(71ac.51a8): Break instruction exception - code 80000003 (first chance)
16,,C:\Users\erikn\source\repos\acdream\.claude\worktrees\peaceful-blackburn-5333f0\artifacts\i422\logs-16\cdb.log,(2594.1e28): Break instruction exception - code 80000003 (first chance)

View file

@ -0,0 +1,25 @@
run,gateExit,shutdownLine,heapLine
1,0,,
2,0,,
3,0,,
4,0,,
5,0,,
6,0,,
7,0,,
8,0,,
9,0,,
10,0,,
11,0,,
12,0,,
13,0,,
14,0,,
15,0,,
16,0,,
17,0,,
18,0,,
19,0,,
20,0,,
21,0,,
22,0,,
23,0,,
24,0,,

View file

@ -0,0 +1,11 @@
.sympath C:\Windows\System32
.symopt+ 0x40
sxe -c "!analyze -v; ~*kb 40; lm; q" bpe
sxe -c "!analyze -v; ~*kb 40; lm; q" av
sxe -c "!analyze -v; ~*kb 40; lm; q" c0000374
sxe -c "!analyze -v; ~*kb 40; lm; q" c0000409
sxd ld
sxd ud
sxd clr
sxd clrn
g

View file

@ -0,0 +1,39 @@
<#
.SYNOPSIS
#422 characterisation loop: N offline High captures, each launched under
cdb with the debug heap (tools/run-offline-pixel-gate.ps1 -DebuggerScript),
summarised to artifacts/i422dh/summary.txt.
.EXAMPLE
pwsh tools/i422/loop-debugheap.ps1 -Runs 24
#>
param([int]$Runs = 24)
$ErrorActionPreference = 'Continue'
$repo = (Resolve-Path (Join-Path $PSScriptRoot '..\..')).Path
$root = Join-Path $repo 'artifacts\i422dh'
New-Item -ItemType Directory -Force $root | Out-Null
$summary = Join-Path $root 'summary.txt'
"run,gateExit,shutdownLine,heapLine" | Set-Content $summary
for ($i = 1; $i -le $Runs; $i++) {
$out = Join-Path $root ("run-{0:D2}" -f $i)
$gateOut = Join-Path $root ("gate-{0:D2}.out" -f $i)
$gateErr = Join-Path $root ("gate-{0:D2}.err" -f $i)
$gate = Start-Process -FilePath 'pwsh' -ArgumentList @(
'-NoProfile', '-File', (Join-Path $repo 'tools\run-offline-pixel-gate.ps1'),
'-Out', $out, '-SkipBuild', '-RenderPackPreset', 'high', '-Uncapped',
'-DebuggerScript', (Join-Path $repo 'toolsbi422-heap-launch.cdb')) `
-PassThru -WindowStyle Hidden -RedirectStandardOutput $gateOut -RedirectStandardError $gateErr
$gate.WaitForExit()
$clientLog = Join-Path $out 'client.log'
$shutdown = ''
$m = Select-String -Path $gateErr -Pattern 'exited with code|timed out|No screenshot' -ErrorAction SilentlyContinue | Select-Object -First 1
if ($m) { $shutdown = $m.Line.Trim() -replace ',', ';' }
$heap = ''
if (Test-Path $clientLog) {
$h = Select-String -Path $clientLog -Pattern 'HEAP\[|Critical error|heap corruption|FAULTING_IP|Access violation|STATUS_HEAP|second chance|!analyze' |
Where-Object { $_.Line -notmatch '^\d+:\d+> sxe' } | Select-Object -First 1
if ($h) { $heap = $h.Line.Trim() -replace ',', ';' }
}
"$i,$($gate.ExitCode),$shutdown,$heap" | Add-Content $summary
Write-Host ("run {0}: gate {1} {2} {3}" -f $i, $gate.ExitCode, $shutdown, $heap)
}
Get-Content $summary

View file

@ -125,6 +125,22 @@
.PARAMETER SkipBuild
Skip the Release build (use when the caller already built).
.PARAMETER ExeOverride
Run this AcDream.App.exe instead of the repository's Release build, with
the SAME isolated settings, scene and capture path. Campaign VM VM7 used
it to compare the final binary against a reference binary built in a
throwaway worktree (VM0's base+normals) without mixing tool versions
VM0 recorded that captures from two different tool versions are not
comparable (isolated-settings fieldOfView). Implies -SkipBuild.
.PARAMETER DebuggerScript
Launch the client UNDER cdb (x64 Windows Debugger, -G -o -lines -cf
<script>) instead of directly. A process started under a debugger runs
with ntdll's debug heap (per-free validation), so a heap corruption
breaks at the corrupting site with a stack instead of fail-fasting at
exit. Campaign VM VM7 used it to characterise #422. The debugger's
console output (which includes the client's stdout) goes to client.log.
.EXAMPLE
# Capture a baseline at the parent commit, then gate the slice:
git stash
@ -164,7 +180,9 @@ param(
# (#226). Default keeps the product default (on). Pass $false to capture the
# pack-off frame without the building/EnvCell detail replay.
[bool]$BuildingDetailTextures = $true,
[switch]$SkipBuild
[switch]$SkipBuild,
[string]$ExeOverride,
[string]$DebuggerScript
)
$ErrorActionPreference = 'Stop'
@ -173,6 +191,15 @@ $exe = Join-Path $repo 'src\AcDream.App\bin\Release\net10.0\AcDream.App.exe'
$cli = Join-Path $repo 'src\AcDream.Cli\bin\Release\net10.0\AcDream.Cli.dll'
. (Join-Path $PSScriptRoot 'atmospheric-performance-matrix-common.ps1')
if ($ExeOverride) {
if (-not (Test-Path $ExeOverride)) { throw "ExeOverride not found: $ExeOverride" }
$exe = (Resolve-Path $ExeOverride).Path
$SkipBuild = $true
}
if ($DebuggerScript -and -not (Test-Path $DebuggerScript)) {
throw "DebuggerScript not found: $DebuggerScript"
}
if ($AllowSafeRenderPackFallback -and $RenderPackPreset -eq 'retail') {
throw '-AllowSafeRenderPackFallback is valid only for an explicitly selected enhanced preset.'
}
@ -309,8 +336,16 @@ if ($MsaaSamples -ge 0) { $env:ACDREAM_MSAA_SAMPLES = "$MsaaSamples" }
else { Remove-Item Env:\ACDREAM_MSAA_SAMPLES -ErrorAction SilentlyContinue }
Write-Step "launching offline client (pack $packId/$presetId, $Resolution, $(if ($Uncapped) { 'uncapped' } else { 'capped' }), orbit ${OrbitDistanceMeters}m/$OrbitYawDegrees deg yaw/$OrbitPitchDegrees deg pitch, warmup ${WarmupMs}ms, day group $DayGroup, day fraction $WorldDayFraction, sky phase $SkyPhaseSeconds, MSAA $MsaaSamples)"
$proc = Start-Process -FilePath $exe -RedirectStandardOutput $log `
-RedirectStandardError "$log.err" -PassThru -WindowStyle Hidden
$proc = if ($DebuggerScript) {
$cdb = 'C:\Program Files (x86)\Windows Kits\10\Debuggers\x64\cdb.exe'
if (-not (Test-Path $cdb)) { throw "cdb.exe not found at $cdb (install the Windows Debugging Tools)." }
Start-Process -FilePath $cdb `
-ArgumentList @('-G', '-o', '-lines', '-cf', (Resolve-Path $DebuggerScript).Path, $exe) `
-RedirectStandardOutput $log -RedirectStandardError "$log.err" -PassThru -WindowStyle Hidden
} else {
Start-Process -FilePath $exe -RedirectStandardOutput $log `
-RedirectStandardError "$log.err" -PassThru -WindowStyle Hidden
}
try {
$shots = Join-Path $Out 'screenshots'