diff --git a/docs/superpowers/plans/2026-05-21-phase-a6-p1-cdb-probe-spike.md b/docs/superpowers/plans/2026-05-21-phase-a6-p1-cdb-probe-spike.md new file mode 100644 index 0000000..0093458 --- /dev/null +++ b/docs/superpowers/plans/2026-05-21-phase-a6-p1-cdb-probe-spike.md @@ -0,0 +1,1339 @@ +# Phase A6.P1 — cdb Probe Spike Implementation Plan + +> **For agentic workers:** REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (`- [ ]`) syntax for tracking. + +**Goal:** Build the `[push-back]` acdream probe + the 7-breakpoint cdb script, then capture paired retail vs acdream traces at 9 indoor scenarios so A6.P2 can quantify the BSP collision response divergence. + +**Architecture:** Three layers — (1) a new `ProbePushBackEnabled` toggle in `PhysicsDiagnostics` with 3 helper methods + 3 emission sites in `BSPQuery` / `Transition`; (2) a cdb breakpoint script + PowerShell wrapper that attaches to live retail; (3) a per-scenario capture protocol producing `{retail,acdream}.log` pairs. + +**Tech Stack:** C# / .NET 10, xUnit, `Console.WriteLine` for probe emission (existing pattern), `cdb.exe` (Windows debugger), PowerShell. + +**Spec:** [`docs/superpowers/specs/2026-05-21-phase-a6-indoor-physics-fidelity-design.md`](../specs/2026-05-21-phase-a6-indoor-physics-fidelity-design.md). + +--- + +## File Structure + +**Files to create:** +- `tools/cdb/a6-probe.cdb` — cdb breakpoint script (~80 lines) +- `tools/cdb/a6-probe-runner.ps1` — PowerShell wrapper to attach cdb (~40 lines) +- `tools/cdb/README-a6-probe.md` — usage documentation (~60 lines) +- `docs/research/2026-05-21-a6-captures/.gitkeep` — directory marker +- `docs/research/2026-05-21-a6-captures/scenN-/{retail,acdream}.log` — capture pairs (filed by Task 15) +- `docs/research/2026-05-21-a6-cdb-capture-findings.md` — findings doc stub (Task 14) + +**Files to modify:** +- `src/AcDream.Core/Physics/PhysicsDiagnostics.cs` — add `ProbePushBackEnabled` toggle + 3 helpers +- `src/AcDream.Core/Physics/BSPQuery.cs` — 2 emission sites (lines 332, 1550) +- `src/AcDream.Core/Physics/TransitionTypes.cs` — 1 emission site in `CheckOtherCells` (line ~1472) +- `src/AcDream.UI.Abstractions/Panels/Debug/DebugVM.cs` — add `ProbePushBack` mirror +- `tests/AcDream.Core.Tests/Physics/PhysicsDiagnosticsTests.cs` — add toggle roundtrip test +- `CLAUDE.md` — add `ACDREAM_PROBE_PUSH_BACK=1` to "Diagnostic env vars" section + +--- + +## Phase A — Build the `[push-back]` probe (TDD) + +### Task 1: Add `ProbePushBackEnabled` toggle to `PhysicsDiagnostics` + +**Files:** +- Modify: `src/AcDream.Core/Physics/PhysicsDiagnostics.cs` (append after `ProbeWalkMissEnabled` at line ~277) +- Test: `tests/AcDream.Core.Tests/Physics/PhysicsDiagnosticsTests.cs` + +- [ ] **Step 1: Write the failing test** + +Append to `tests/AcDream.Core.Tests/Physics/PhysicsDiagnosticsTests.cs` (before the final closing `}` of the class): + +```csharp + // ----------------------------------------------------------------------- + // ProbePushBackEnabled — flag gates the [push-back] emission path. + // A6.P1 (2026-05-21). + // ----------------------------------------------------------------------- + + [Fact] + public void ProbePushBack_StaticApi_Roundtrip() + { + bool initial = PhysicsDiagnostics.ProbePushBackEnabled; + try + { + PhysicsDiagnostics.ProbePushBackEnabled = true; + Assert.True(PhysicsDiagnostics.ProbePushBackEnabled); + + PhysicsDiagnostics.ProbePushBackEnabled = false; + Assert.False(PhysicsDiagnostics.ProbePushBackEnabled); + } + finally + { + PhysicsDiagnostics.ProbePushBackEnabled = initial; + } + } +``` + +- [ ] **Step 2: Run test to verify it fails** + +Run: `dotnet test tests/AcDream.Core.Tests/AcDream.Core.Tests.csproj --filter FullyQualifiedName~ProbePushBack_StaticApi_Roundtrip --no-build` + +Expected: COMPILE ERROR — `'PhysicsDiagnostics' does not contain a definition for 'ProbePushBackEnabled'`. + +- [ ] **Step 3: Implement the toggle** + +Append to `src/AcDream.Core/Physics/PhysicsDiagnostics.cs` immediately before the `LogCpBoolWrite` method (around line 279): + +```csharp + /// + /// Phase A6.P1 cdb probe spike (2026-05-21). When true, every BSP + /// collision response site emits a structured [push-back] line: + /// input/output sphere center, plane geometry, push-back delta, walk + /// interp, and the dispatcher's selected path. Direct comparison to + /// retail's cdb breakpoint set documented at + /// tools/cdb/a6-probe.cdb. + /// + /// + /// Three emission sites: + /// (the suspected over-correction site), + /// (the 6-path dispatcher), and + /// (multi-cell BSP iteration outcomes). All three are zero-cost when + /// off — checked via early-out at each site. + /// + /// + /// + /// Initial state from ACDREAM_PROBE_PUSH_BACK=1. + /// Runtime-toggleable via DebugVM mirror. + /// + /// + /// + /// Spec: docs/superpowers/specs/2026-05-21-phase-a6-indoor-physics-fidelity-design.md. + /// + /// + public static bool ProbePushBackEnabled { get; set; } = + Environment.GetEnvironmentVariable("ACDREAM_PROBE_PUSH_BACK") == "1"; + +``` + +- [ ] **Step 4: Run test to verify it passes** + +Run: `dotnet build src/AcDream.Core/AcDream.Core.csproj -c Debug --nologo && dotnet test tests/AcDream.Core.Tests/AcDream.Core.Tests.csproj --filter FullyQualifiedName~ProbePushBack_StaticApi_Roundtrip --no-build` + +Expected: PASS. + +- [ ] **Step 5: Commit** + +```bash +git add src/AcDream.Core/Physics/PhysicsDiagnostics.cs tests/AcDream.Core.Tests/Physics/PhysicsDiagnosticsTests.cs +git commit -m "$(cat <<'EOF' +feat(physics): A6.P1 — add ProbePushBackEnabled toggle + +New PhysicsDiagnostics flag gates the [push-back] probe shipping +in subsequent tasks. Env-var ACDREAM_PROBE_PUSH_BACK=1 + DebugVM +mirror, matching the existing probe-toggle pattern. + +Co-Authored-By: Claude Opus 4.7 (1M context) +EOF +)" +``` + +--- + +### Task 2: Add `LogPushBackAdjust` helper method + +**Files:** +- Modify: `src/AcDream.Core/Physics/PhysicsDiagnostics.cs` + +- [ ] **Step 1: Add the helper method** + +Append immediately after the `ProbePushBackEnabled` property (just added) in `src/AcDream.Core/Physics/PhysicsDiagnostics.cs`: + +```csharp + /// + /// A6.P1 emission helper for the AdjustSphereToPlane site. + /// One line per call: input sphere center, plane geometry, push-back + /// delta, walk-interp before/after, and whether the adjust applied. + /// Direct paired comparison to retail's cdb breakpoint on + /// CPolygon::adjust_sphere_to_plane. + /// + /// + /// Caller MUST guard with if (!ProbePushBackEnabled) return; + /// before computing the delta arguments — this method assumes the + /// caller paid that price already. + /// + /// + public static void LogPushBackAdjust( + Vector3 inputCenter, + Vector3 outputCenter, + Plane plane, + float radius, + float walkInterpBefore, + float walkInterpAfter, + float dpPos, + float dpMove, + float iDist, + bool applied) + { + var delta = outputCenter - inputCenter; + float deltaMag = delta.Length(); + Console.WriteLine(System.FormattableString.Invariant( + $"[push-back] site=adjust_sphere " + + $"in=({inputCenter.X:F4},{inputCenter.Y:F4},{inputCenter.Z:F4}) " + + $"out=({outputCenter.X:F4},{outputCenter.Y:F4},{outputCenter.Z:F4}) " + + $"delta=({delta.X:F4},{delta.Y:F4},{delta.Z:F4}) deltaMag={deltaMag:F4} " + + $"n=({plane.Normal.X:F4},{plane.Normal.Y:F4},{plane.Normal.Z:F4}) d={plane.D:F4} " + + $"r={radius:F4} winterp={walkInterpBefore:F4}->{walkInterpAfter:F4} " + + $"dpPos={dpPos:F4} dpMove={dpMove:F4} iDist={iDist:F4} applied={applied}")); + } + + // Note: cellId/polyId omitted — ResolvedPolygon has no Id property and + // AdjustSphereToPlane is called from inside BSP traversal without cell + // attribution. Cross-reference with [push-back-cell] (same trace, time- + // adjacent) for cell attribution; polyId pursued only if A6.P2 needs it + // (would require plumbing the ushort dict-key through BSP traversal). + +``` + +- [ ] **Step 2: Verify it compiles** + +Run: `dotnet build src/AcDream.Core/AcDream.Core.csproj -c Debug --nologo` + +Expected: BUILD SUCCEEDED with 0 errors. + +- [ ] **Step 3: Commit** + +```bash +git add src/AcDream.Core/Physics/PhysicsDiagnostics.cs +git commit -m "$(cat <<'EOF' +feat(physics): A6.P1 — add LogPushBackAdjust helper + +One-line per-call emission helper for the AdjustSphereToPlane +instrumentation site. Direct field-for-field paired comparison to +retail's CPolygon::adjust_sphere_to_plane breakpoint. + +Co-Authored-By: Claude Opus 4.7 (1M context) +EOF +)" +``` + +--- + +### Task 3: Wire `LogPushBackAdjust` into `BSPQuery.AdjustSphereToPlane` + +**Files:** +- Modify: `src/AcDream.Core/Physics/BSPQuery.cs:332-362` (the `AdjustSphereToPlane` method body) + +- [ ] **Step 1: Read the current method body** + +Read `src/AcDream.Core/Physics/BSPQuery.cs` lines 320-365 to confirm the current shape — `AdjustSphereToPlane` returns bool, modifies `validPos.Center` and `path.WalkInterp` in-place. + +- [ ] **Step 2: Replace the method body with the instrumented version** + +Replace the body of `AdjustSphereToPlane` in `src/AcDream.Core/Physics/BSPQuery.cs` (lines 332-362) with: + +```csharp + private static bool AdjustSphereToPlane( + ResolvedPolygon poly, + SpherePath path, + CollisionSphere validPos, + Vector3 movement) + { + // A6.P1: snapshot inputs for the [push-back] probe (cheap copy of + // Vector3 + 2 floats). Only the LogPushBackAdjust call below pays + // the Console.WriteLine cost, and only when the probe is on. + var inputCenter = validPos.Center; + float walkInterpBefore = path.WalkInterp; + + float dpPos = Vector3.Dot(validPos.Center, poly.Plane.Normal) + poly.Plane.D; + float dpMove = Vector3.Dot(movement, poly.Plane.Normal); + float dist; + + if (dpMove <= PhysicsGlobals.EPSILON) + { + if (dpMove >= -PhysicsGlobals.EPSILON) + { + if (PhysicsDiagnostics.ProbePushBackEnabled) + { + PhysicsDiagnostics.LogPushBackAdjust( + inputCenter, validPos.Center, poly.Plane, validPos.Radius, + walkInterpBefore, path.WalkInterp, + dpPos, dpMove, 0f, + applied: false); + } + return false; + } + dist = dpPos - validPos.Radius; + } + else + { + dist = -validPos.Radius - dpPos; + } + + float iDist = dist / dpMove; + float interp = (1f - iDist) * path.WalkInterp; + + if (interp >= path.WalkInterp || interp < -0.5f) + { + if (PhysicsDiagnostics.ProbePushBackEnabled) + { + PhysicsDiagnostics.LogPushBackAdjust( + inputCenter, validPos.Center, poly.Plane, validPos.Radius, + walkInterpBefore, path.WalkInterp, + dpPos, dpMove, iDist, + applied: false); + } + return false; + } + + validPos.Center -= movement * iDist; + path.WalkInterp = interp; + + if (PhysicsDiagnostics.ProbePushBackEnabled) + { + PhysicsDiagnostics.LogPushBackAdjust( + inputCenter, validPos.Center, poly.Plane, validPos.Radius, + walkInterpBefore, path.WalkInterp, + dpPos, dpMove, iDist, + applied: true); + } + + return true; + } +``` + +**Note:** Cell + poly attribution intentionally omitted — `ResolvedPolygon` +has no `Id` property and `AdjustSphereToPlane` is private inside BSP +traversal without cell scope. A6.P2 cross-references with the time-adjacent +`[push-back-cell]` line for cell attribution. If `polyId` becomes +necessary, A6.P3 plumbs the dictionary key through (mechanical change). + +- [ ] **Step 3: Verify build is green** + +Run: `dotnet build src/AcDream.Core/AcDream.Core.csproj -c Debug --nologo` + +Expected: BUILD SUCCEEDED with 0 errors. The probe is now wired but inactive unless `ACDREAM_PROBE_PUSH_BACK=1`. + +- [ ] **Step 4: Quick smoke run to confirm the probe emits** + +Set the env var and run any test that calls AdjustSphereToPlane (existing BSPQuery tests touch this path): + +```powershell +$env:ACDREAM_PROBE_PUSH_BACK = "1" +dotnet test tests/AcDream.Core.Tests/AcDream.Core.Tests.csproj --filter "FullyQualifiedName~BSPQuery" --no-build --logger "console;verbosity=detailed" 2>&1 | Select-String "\[push-back\]" | Select-Object -First 3 +Remove-Item Env:\ACDREAM_PROBE_PUSH_BACK +``` + +Expected: at least 1 `[push-back] site=adjust_sphere ...` line in the output. If zero lines, the probe didn't fire — investigate. + +- [ ] **Step 5: Commit** + +```bash +git add src/AcDream.Core/Physics/BSPQuery.cs +git commit -m "$(cat <<'EOF' +feat(physics): A6.P1 — instrument AdjustSphereToPlane with [push-back] + +Wires the LogPushBackAdjust helper into all three return paths +of AdjustSphereToPlane (early-return on no-movement, early-return +on interp out-of-window, and the applied path). Probe is gated by +ProbePushBackEnabled so it's zero-cost when off. + +Co-Authored-By: Claude Opus 4.7 (1M context) +EOF +)" +``` + +--- + +### Task 4: Add `LogPushBackDispatch` helper method + +**Files:** +- Modify: `src/AcDream.Core/Physics/PhysicsDiagnostics.cs` + +- [ ] **Step 1: Add the helper method** + +Append immediately after the `LogPushBackAdjust` method (just added) in `src/AcDream.Core/Physics/PhysicsDiagnostics.cs`: + +```csharp + /// + /// A6.P1 emission helper for the FindCollisions dispatcher + /// site. One line per call: input sphere center, movement vector, + /// path-selection state flags (collide / insertType / objState), + /// walk-interp at entry, and the return state. Direct paired + /// comparison to retail's cdb breakpoint on + /// BSPTREE::find_collisions. + /// + /// + /// Caller MUST guard with if (!ProbePushBackEnabled) return; + /// before calling. + /// + /// + public static void LogPushBackDispatch( + Vector3 sphereCenter, + Vector3 movement, + bool collide, + int insertType, + int objState, + float walkInterpEntry, + int returnState) + { + Console.WriteLine(System.FormattableString.Invariant( + $"[push-back-disp] site=dispatch " + + $"center=({sphereCenter.X:F4},{sphereCenter.Y:F4},{sphereCenter.Z:F4}) " + + $"mvmt=({movement.X:F4},{movement.Y:F4},{movement.Z:F4}) " + + $"collide={collide} insertType={insertType} objState=0x{objState:X} " + + $"winterp={walkInterpEntry:F4} return={returnState}")); + } + +``` + +- [ ] **Step 2: Verify it compiles** + +Run: `dotnet build src/AcDream.Core/AcDream.Core.csproj -c Debug --nologo` + +Expected: BUILD SUCCEEDED. + +- [ ] **Step 3: Commit** + +```bash +git add src/AcDream.Core/Physics/PhysicsDiagnostics.cs +git commit -m "$(cat <<'EOF' +feat(physics): A6.P1 — add LogPushBackDispatch helper + +One-line per-call emission helper for the FindCollisions dispatcher +instrumentation site. Captures path-selection state (collide flag, +insertType, objState) + walk-interp + return state for direct +comparison to retail's BSPTREE::find_collisions breakpoint. + +Co-Authored-By: Claude Opus 4.7 (1M context) +EOF +)" +``` + +--- + +### Task 5: Wire `LogPushBackDispatch` into `BSPQuery.FindCollisions` (modern overload only) + +**Files:** +- Modify: `src/AcDream.Core/Physics/BSPQuery.cs:1550-1576` (the modern `FindCollisions` overload entry) + +**Note:** The legacy overload at `:1895` delegates to the modern overload — instrumenting only the modern one covers all dispatches. + +- [ ] **Step 1: Locate the dispatcher's entry block** + +Read `src/AcDream.Core/Physics/BSPQuery.cs` lines 1550-1580 to confirm the entry shape (we want to emit AFTER the path/collisions/obj locals are computed but BEFORE the actual dispatch begins). + +- [ ] **Step 2: Insert the probe emission after `movement` is computed** + +After line 1576 (`var movement = sphere0.Center - localCurrCenter;`) and BEFORE the next significant statement in `BSPQuery.cs`'s `FindCollisions`, add: + +```csharp + // A6.P1: snapshot dispatcher entry for the [push-back-disp] probe. + // Emitted before path selection so the captured state reflects + // the inputs the dispatcher routes on. Return value is captured + // by wrapping the actual dispatch — see end of method. + if (PhysicsDiagnostics.ProbePushBackEnabled) + { + PhysicsDiagnostics.LogPushBackDispatch( + sphereCenter: sphere0.Center, + movement: movement, + collide: path.Collide, + insertType: (int)path.InsertType, + objState: (int)obj.State, + walkInterpEntry: path.WalkInterp, + returnState: -1); // Sentinel; full return state captured separately. + } + +``` + +**Note:** The `returnState=-1` sentinel marks "entry log" — A6.P2 analysis can pair entry/exit by call order in the trace. If a per-call exit log is needed, A6.P1.5 adds a wrapping try/finally; for now entry-only suffices since the dispatcher's path can be inferred from subsequent `[push-back]` adjust-sphere lines and the eventual return. + +- [ ] **Step 3: Verify build is green** + +Run: `dotnet build src/AcDream.Core/AcDream.Core.csproj -c Debug --nologo` + +Expected: BUILD SUCCEEDED. + +- [ ] **Step 4: Quick smoke run** + +```powershell +$env:ACDREAM_PROBE_PUSH_BACK = "1" +dotnet test tests/AcDream.Core.Tests/AcDream.Core.Tests.csproj --filter "FullyQualifiedName~FindCollisions" --no-build --logger "console;verbosity=detailed" 2>&1 | Select-String "\[push-back-disp\]" | Select-Object -First 3 +Remove-Item Env:\ACDREAM_PROBE_PUSH_BACK +``` + +Expected: at least 1 `[push-back-disp] site=dispatch ...` line. + +- [ ] **Step 5: Commit** + +```bash +git add src/AcDream.Core/Physics/BSPQuery.cs +git commit -m "$(cat <<'EOF' +feat(physics): A6.P1 — instrument FindCollisions with [push-back-disp] + +Wires LogPushBackDispatch into the modern FindCollisions overload +at the entry block (after path/collisions/obj locals + movement +computed). Legacy overload delegates to modern, so single +instrumentation site covers all dispatches. + +Co-Authored-By: Claude Opus 4.7 (1M context) +EOF +)" +``` + +--- + +### Task 6: Add `LogPushBackCellTransit` helper method + +**Files:** +- Modify: `src/AcDream.Core/Physics/PhysicsDiagnostics.cs` + +- [ ] **Step 1: Add the helper method** + +Append immediately after `LogPushBackDispatch` in `src/AcDream.Core/Physics/PhysicsDiagnostics.cs`: + +```csharp + /// + /// A6.P1 emission helper for the CheckOtherCells multi-cell + /// BSP iteration site. One line per off-cell hit: from-cell, to-cell, + /// BSP result (Ok / Adjusted / Slid / Collided), and the iteration + /// outcome. Direct paired comparison to retail's + /// CTransition::check_other_cells loop at decomp line + /// 272717. Augments the existing A4 multi-cell BSP instrumentation + /// with explicit per-iteration outcome telemetry. + /// + /// + /// Caller MUST guard with if (!ProbePushBackEnabled) return; + /// before calling. + /// + /// + public static void LogPushBackCellTransit( + uint primaryCellId, + uint otherCellId, + int bspResult, + bool halted) + { + Console.WriteLine(System.FormattableString.Invariant( + $"[push-back-cell] site=other_cell " + + $"primary=0x{primaryCellId:X8} other=0x{otherCellId:X8} " + + $"bspResult={bspResult} halted={halted}")); + } + +``` + +- [ ] **Step 2: Verify it compiles** + +Run: `dotnet build src/AcDream.Core/AcDream.Core.csproj -c Debug --nologo` + +Expected: BUILD SUCCEEDED. + +- [ ] **Step 3: Commit** + +```bash +git add src/AcDream.Core/Physics/PhysicsDiagnostics.cs +git commit -m "$(cat <<'EOF' +feat(physics): A6.P1 — add LogPushBackCellTransit helper + +One-line per-iteration emission helper for the CheckOtherCells +multi-cell BSP loop. Captures primary/other cell ids, BSP result, +and halted flag for direct comparison to retail's +CTransition::check_other_cells loop. + +Co-Authored-By: Claude Opus 4.7 (1M context) +EOF +)" +``` + +--- + +### Task 7: Wire `LogPushBackCellTransit` into `Transition.CheckOtherCells` + +**Files:** +- Modify: `src/AcDream.Core/Physics/TransitionTypes.cs:1404-1480` (the `CheckOtherCells` loop) + +- [ ] **Step 1: Locate the insertion point** + +In `src/AcDream.Core/Physics/TransitionTypes.cs`, find the line block at +~1466-1473: + +```csharp + if (PhysicsDiagnostics.ProbeIndoorBspEnabled) + { + Console.WriteLine(System.FormattableString.Invariant( + $"[other-cells] primary=0x{sp.CheckCellId:X8} iter=0x{cellId:X8} result={result}")); + } + + if (ApplyOtherCellResult(result, out var halted)) + return halted; +``` + +We add the new `[push-back-cell]` emission AFTER the existing `[other-cells]` +block and BEFORE the `ApplyOtherCellResult` call. + +- [ ] **Step 2: Insert the new emission** + +In `src/AcDream.Core/Physics/TransitionTypes.cs`, modify the line block at +~1466-1473 by inserting a new `if` block between the existing +`[other-cells]` probe and the `ApplyOtherCellResult` call. The locals in +scope at this point are `sp.CheckCellId` (the primary), `cellId` (the +loop variable for the candidate cell), and `result` (the BSP query +return state). After the edit it reads: + +```csharp + if (PhysicsDiagnostics.ProbeIndoorBspEnabled) + { + Console.WriteLine(System.FormattableString.Invariant( + $"[other-cells] primary=0x{sp.CheckCellId:X8} iter=0x{cellId:X8} result={result}")); + } + + if (PhysicsDiagnostics.ProbePushBackEnabled) + { + PhysicsDiagnostics.LogPushBackCellTransit( + primaryCellId: sp.CheckCellId, + otherCellId: cellId, + bspResult: (int)result, + halted: false); // Sentinel; A6.P2 infers halt by checking if the iter ended here. + } + + if (ApplyOtherCellResult(result, out var halted)) + return halted; +``` + +- [ ] **Step 3: Verify build is green** + +Run: `dotnet build src/AcDream.Core/AcDream.Core.csproj -c Debug --nologo` + +Expected: BUILD SUCCEEDED with 0 errors. + +- [ ] **Step 4: Quick smoke run** + +```powershell +$env:ACDREAM_PROBE_PUSH_BACK = "1" +dotnet test tests/AcDream.Core.Tests/AcDream.Core.Tests.csproj --filter "FullyQualifiedName~CheckOtherCells" --no-build --logger "console;verbosity=detailed" 2>&1 | Select-String "\[push-back-cell\]" | Select-Object -First 3 +Remove-Item Env:\ACDREAM_PROBE_PUSH_BACK +``` + +Expected: at least 1 `[push-back-cell] site=other_cell ...` line. + +- [ ] **Step 5: Commit** + +```bash +git add src/AcDream.Core/Physics/TransitionTypes.cs +git commit -m "$(cat <<'EOF' +feat(physics): A6.P1 — instrument CheckOtherCells with [push-back-cell] + +Wires LogPushBackCellTransit into the multi-cell BSP iteration loop +just before ApplyOtherCellResult halts. Captures primary/other +cell ids + BSP result for direct comparison to retail's +CTransition::check_other_cells loop (already ported as A4). + +Co-Authored-By: Claude Opus 4.7 (1M context) +EOF +)" +``` + +--- + +### Task 8: Add `ProbePushBack` mirror to `DebugVM` + +**Files:** +- Modify: `src/AcDream.UI.Abstractions/Panels/Debug/DebugVM.cs` (append after `ProbeIndoorBsp` at line ~360) + +- [ ] **Step 1: Add the mirror property** + +After the `ProbeIndoorBsp` property in `src/AcDream.UI.Abstractions/Panels/Debug/DebugVM.cs` (closing `}` around line 360), insert: + +```csharp + + /// + /// Phase A6.P1 cdb probe spike (2026-05-21). Runtime mirror of + /// PhysicsDiagnostics.ProbePushBackEnabled (env var + /// ACDREAM_PROBE_PUSH_BACK). Toggling here flips the three + /// [push-back] emission sites live — no relaunch required. + /// + public bool ProbePushBack + { + get => PhysicsDiagnostics.ProbePushBackEnabled; + set => PhysicsDiagnostics.ProbePushBackEnabled = value; + } +``` + +- [ ] **Step 2: Verify build is green** + +Run: `dotnet build src/AcDream.UI.Abstractions/AcDream.UI.Abstractions.csproj -c Debug --nologo` + +Expected: BUILD SUCCEEDED. + +- [ ] **Step 3: Commit** + +```bash +git add src/AcDream.UI.Abstractions/Panels/Debug/DebugVM.cs +git commit -m "$(cat <<'EOF' +feat(ui): A6.P1 — add ProbePushBack mirror to DebugVM + +Runtime checkbox mirror for ProbePushBackEnabled. Toggling in +DebugPanel (under ACDREAM_DEVTOOLS=1) flips all three [push-back] +emission sites live without relaunch. + +Co-Authored-By: Claude Opus 4.7 (1M context) +EOF +)" +``` + +--- + +### Task 9: Update CLAUDE.md "Diagnostic env vars" section + +**Files:** +- Modify: `CLAUDE.md` ("Diagnostic env vars" subsection) + +- [ ] **Step 1: Locate the section** + +Run: `grep -n "ACDREAM_PROBE_RESOLVE\|Diagnostic env vars" CLAUDE.md | head -5` + +Identify the line where the existing `ACDREAM_PROBE_*` env var documentation ends. + +- [ ] **Step 2: Add the new env var entry** + +Append the new entry immediately after the existing `ACDREAM_PROBE_WALK_MISS` entry (look for the `[walk-miss]` documentation line). Add: + +```markdown +- `ACDREAM_PROBE_PUSH_BACK=1` — A6.P1 cdb probe spike (2026-05-21). + Emits three line types per physics tick: `[push-back]` (per + `BSPQuery.AdjustSphereToPlane` call), `[push-back-disp]` (per + `BSPQuery.FindCollisions` dispatch), `[push-back-cell]` (per + `Transition.CheckOtherCells` off-cell hit). Heavy under motion + (~100–500 lines/sec). Pair with retail's cdb breakpoint set at + `tools/cdb/a6-probe.cdb` for the A6.P1 capture protocol. + Runtime-toggleable via the DebugPanel "Diagnostics" section. +``` + +- [ ] **Step 3: Commit** + +```bash +git add CLAUDE.md +git commit -m "$(cat <<'EOF' +docs(CLAUDE): A6.P1 — document ACDREAM_PROBE_PUSH_BACK env var + +Adds the new probe to the Diagnostic env vars list with hit-rate +estimate and cross-reference to the cdb probe script. + +Co-Authored-By: Claude Opus 4.7 (1M context) +EOF +)" +``` + +--- + +## Phase B — Build the cdb script + infrastructure + +### Task 10: Write `tools/cdb/a6-probe.cdb` + +**Files:** +- Create: `tools/cdb/a6-probe.cdb` + +- [ ] **Step 1: Verify the parent directory exists** + +```bash +ls tools/ 2>&1; mkdir -p tools/cdb +``` + +- [ ] **Step 2: Write the cdb script** + +Create `tools/cdb/a6-probe.cdb`: + +```text +$$ +$$ Phase A6.P1 cdb probe spike — 2026-05-21 +$$ +$$ 7 breakpoints on retail's BSP collision response sites. Each BP fires +$$ a non-blocking action (printf + gc), incrementing a per-BP counter. +$$ Auto-detaches via 'qd' after 50,000 total hits to avoid retail lag. +$$ +$$ Symbol lookup convention per CLAUDE.md "Retail debugger toolchain": +$$ - snake_case for BSPTREE, CTransition, OBJECTINFO, COLLISIONINFO, SPHEREPATH +$$ - PascalCase for CPhysicsObj +$$ - Always 'x' first to confirm the actual name +$$ + +.logopen /t a6-probe-${ARG_LOG_TAG}.log +.sympath C:\Users\erikn\source\repos\acdream\refs +.symopt+ 0x40 +.reload /f acclient.exe + +$$ Counters: $t0 = total hits, $t1..$t7 = per-BP hits +r $t0 = 0 +r $t1 = 0 +r $t2 = 0 +r $t3 = 0 +r $t4 = 0 +r $t5 = 0 +r $t6 = 0 +r $t7 = 0 + +$$ BP1: CTransition::transitional_insert +bp acclient!CTransition::transitional_insert "r $t1 = @$t1 + 1; r $t0 = @$t0 + 1; .printf /D \"[BP1] transitional_insert hit#%d eax_2=%d insertType=%d\\n\", @$t1, poi(@ecx+0x18), poi(@ecx+0x1c); .if (@$t0 >= 50000) { qd } .else { gc }" + +$$ BP2: CTransition::step_up +bp acclient!CTransition::step_up "r $t2 = @$t2 + 1; r $t0 = @$t0 + 1; .printf /D \"[BP2] step_up hit#%d walkable_allowance=%f\\n\", @$t2, poi(@ecx+0x60); .if (@$t0 >= 50000) { qd } .else { gc }" + +$$ BP3: SPHEREPATH::set_collide +bp acclient!SPHEREPATH::set_collide "r $t3 = @$t3 + 1; r $t0 = @$t0 + 1; .printf /D \"[BP3] set_collide hit#%d normalZ=%f\\n\", @$t3, dwo(@edx+0x8); .if (@$t0 >= 50000) { qd } .else { gc }" + +$$ BP4: BSPTREE::find_collisions +bp acclient!BSPTREE::find_collisions "r $t4 = @$t4 + 1; r $t0 = @$t0 + 1; .printf /D \"[BP4] find_collisions hit#%d collide=%d insertType=%d\\n\", @$t4, poi(@ecx+0x40), poi(@ecx+0x1c); .if (@$t0 >= 50000) { qd } .else { gc }" + +$$ BP5: CPolygon::adjust_sphere_to_plane (the over-correction suspect) +bp acclient!CPolygon::adjust_sphere_to_plane "r $t5 = @$t5 + 1; r $t0 = @$t0 + 1; .printf /D \"[BP5] adjust_sphere hit#%d Nx=%f Ny=%f Nz=%f d=%f cx=%f cy=%f cz=%f r=%f winterp=%f\\n\", @$t5, dwo(@ecx+0x0), dwo(@ecx+0x4), dwo(@ecx+0x8), dwo(@ecx+0xc), dwo(@edx+0x0), dwo(@edx+0x4), dwo(@edx+0x8), dwo(@edx+0xc), dwo(@edi+0x40); .if (@$t0 >= 50000) { qd } .else { gc }" + +$$ BP6: CTransition::validate_walkable +bp acclient!CTransition::validate_walkable "r $t6 = @$t6 + 1; r $t0 = @$t0 + 1; .printf /D \"[BP6] validate_walkable hit#%d arg2=%f\\n\", @$t6, dwo(@esp+0x4); .if (@$t0 >= 50000) { qd } .else { gc }" + +$$ BP7: COLLISIONINFO::set_contact_plane +bp acclient!COLLISIONINFO::set_contact_plane "r $t7 = @$t7 + 1; r $t0 = @$t0 + 1; .printf /D \"[BP7] set_contact_plane hit#%d isWater=%d\\n\", @$t7, dwo(@esp+0x8); .if (@$t0 >= 50000) { qd } .else { gc }" + +.printf \"a6-probe armed: BPs 1-7 set, threshold=50000 total hits, qd on threshold\\n\" + +$$ Continue execution +g +``` + +**Note:** The `${ARG_LOG_TAG}` placeholder is substituted by the PowerShell runner (Task 11) per scenario. The field offsets (`+0x18`, `+0x1c`, etc.) are based on the named-retail struct layouts in `docs/research/named-retail/acclient.h`; if a BP fires with garbage values, verify the offset against the struct definition. + +- [ ] **Step 3: Commit** + +```bash +git add tools/cdb/a6-probe.cdb +git commit -m "$(cat <<'EOF' +feat(cdb): A6.P1 — 7-BP probe script for retail BSP collision response + +Sets non-blocking breakpoints on transitional_insert, step_up, +set_collide, find_collisions, adjust_sphere_to_plane, +validate_walkable, set_contact_plane. Each BP increments a counter +and emits a single printf line. Auto-detach via qd at 50K total +hits to avoid retail lag (CLAUDE.md gotcha — high BP rates trigger +ACE timeout). + +Co-Authored-By: Claude Opus 4.7 (1M context) +EOF +)" +``` + +--- + +### Task 11: Write `tools/cdb/a6-probe-runner.ps1` + +**Files:** +- Create: `tools/cdb/a6-probe-runner.ps1` + +- [ ] **Step 1: Write the wrapper** + +Create `tools/cdb/a6-probe-runner.ps1`: + +```powershell +# Phase A6.P1 cdb probe runner — 2026-05-21 +# +# Attaches cdb to a live retail acclient.exe with the a6-probe.cdb script. +# Per-scenario usage: +# .\tools\cdb\a6-probe-runner.ps1 -ScenarioTag "scen1_inn_doorway" +# +# Prerequisites (verify before invoking): +# 1. Retail acclient.exe v11.4186 running and in-world (matches refs/acclient.pdb). +# Verify with: py tools\pdb-extract\check_exe_pdb.py "C:\Turbine\Asheron's Call\acclient.exe" +# 2. ACE running locally on 127.0.0.1:9000. +# 3. Retail character at the scenario start position. +# +# Output: +# docs\research\2026-05-21-a6-captures\\retail.log + +param( + [Parameter(Mandatory=$true)] + [string]$ScenarioTag +) + +$cdbExe = "C:\Program Files (x86)\Windows Kits\10\Debuggers\x86\cdb.exe" +if (-not (Test-Path $cdbExe)) { + Write-Error "cdb.exe not found at $cdbExe. Install Microsoft Store WinDbg (~50 MB)." + exit 1 +} + +$scriptPath = Join-Path $PSScriptRoot "a6-probe.cdb" +if (-not (Test-Path $scriptPath)) { + Write-Error "a6-probe.cdb not found at $scriptPath." + exit 1 +} + +$captureDir = Join-Path $PSScriptRoot "..\..\docs\research\2026-05-21-a6-captures\$ScenarioTag" +if (-not (Test-Path $captureDir)) { + New-Item -ItemType Directory -Path $captureDir | Out-Null +} + +$logPath = Join-Path $captureDir "retail.log" + +# Patch the .cdb script with the scenario-tagged log path (in-place substitution). +$scriptContent = Get-Content $scriptPath -Raw +$patchedScript = $scriptContent -replace '\$\{ARG_LOG_TAG\}', $ScenarioTag + +$tempScript = Join-Path $env:TEMP "a6-probe-$ScenarioTag.cdb" +Set-Content -Path $tempScript -Value $patchedScript -Encoding ASCII + +Write-Host "Attaching cdb to acclient.exe with scenario tag '$ScenarioTag'..." +Write-Host "Log: $logPath" +Write-Host "(cdb auto-detaches at 50K total hits; or press Ctrl-Break to interrupt.)" + +& $cdbExe -pn acclient.exe -cf $tempScript 2>&1 | Tee-Object -FilePath $logPath + +Remove-Item $tempScript -ErrorAction SilentlyContinue + +Write-Host "" +Write-Host "Capture complete. Log saved to $logPath" +``` + +- [ ] **Step 2: Commit** + +```bash +git add tools/cdb/a6-probe-runner.ps1 +git commit -m "$(cat <<'EOF' +feat(cdb): A6.P1 — PowerShell runner for a6-probe.cdb + +Wrapper that attaches cdb to a live retail acclient.exe with a +scenario-tagged log path. Per-scenario invocation: + .\tools\cdb\a6-probe-runner.ps1 -ScenarioTag "scen1_inn_doorway" +Output: docs\research\2026-05-21-a6-captures\\retail.log + +Co-Authored-By: Claude Opus 4.7 (1M context) +EOF +)" +``` + +--- + +### Task 12: Write `tools/cdb/README-a6-probe.md` + +**Files:** +- Create: `tools/cdb/README-a6-probe.md` + +- [ ] **Step 1: Write the README** + +Create `tools/cdb/README-a6-probe.md`: + +```markdown +# A6.P1 cdb probe — usage + +Phase A6.P1 cdb probe spike (2026-05-21). Captures retail's per-tick BSP +collision response state for paired comparison against acdream. + +## Files + +- `a6-probe.cdb` — the 7-breakpoint cdb script (see comments inside). +- `a6-probe-runner.ps1` — PowerShell wrapper that attaches cdb to live retail. + +## Prerequisites + +1. **Retail binary matches our PDB.** Verify with: + ```powershell + py tools\pdb-extract\check_exe_pdb.py "C:\Turbine\Asheron's Call\acclient.exe" + ``` + Expected: `=== MATCH: this exe pairs with our acclient.pdb ===` + +2. **cdb installed.** Microsoft Store WinDbg installs cdb at + `C:\Program Files (x86)\Windows Kits\10\Debuggers\x86\cdb.exe`. 32-bit + required for acclient.exe. + +3. **Retail running and in-world.** Launch retail, log into your character, + navigate to the scenario start point. + +4. **ACE running locally on 127.0.0.1:9000.** + +## Usage + +For each of the 9 A6.P1 scenarios: + +```powershell +# 1. Position retail character at scenario start (e.g., outside Holtburg inn). +# 2. Launch the probe with a scenario tag: +.\tools\cdb\a6-probe-runner.ps1 -ScenarioTag "scen1_inn_doorway" + +# 3. cdb attaches; "a6-probe armed: BPs 1-7 set" appears in console. +# 4. In the retail client window, perform the scripted walk for this scenario. +# 5. cdb auto-detaches at 50K total hits (cleanly via qd; retail keeps running). +# 6. Log filed at docs\research\2026-05-21-a6-captures\scen1_inn_doorway\retail.log +``` + +## The 9 scenarios + +Per the A6 design spec, in capture order: + +| # | Tag | Walk script | +|---|---|---| +| 1 | `scen1_inn_doorway` | Walk forward through door, stop just inside | +| 2 | `scen2_inn_stairs` | Walk up 4 steps, stop on landing | +| 3 | `scen3_inn_2nd_floor` | Walk forward 3 m, sidestep 1 m, walk back | +| 4 | `scen4_cottage_cellar` | Walk to cellar opening, descend 2 steps | +| 5 | `scen5_sewer_entry` | Walk into portal, then walk 2 m forward inside | +| 6 | `scen6_sewer_first_stair` | Walk down full stair flight | +| 7 | `scen7_sewer_inter_room` | Walk through portal, stop 1 m past | +| 8 | `scen8_sewer_chamber` | Walk in, traverse center, walk out other side | +| 9 | `scen9_sewer_corridor` | Walk full length end-to-end | + +## Pairing with acdream + +For each scenario, run acdream IN PARALLEL with the same scripted walk: + +```powershell +$env:ACDREAM_DAT_DIR = "$env:USERPROFILE\Documents\Asheron's Call" +$env:ACDREAM_LIVE = "1" +$env:ACDREAM_TEST_HOST = "127.0.0.1" +$env:ACDREAM_TEST_PORT = "9000" +$env:ACDREAM_TEST_USER = "testaccount" +$env:ACDREAM_TEST_PASS = "testpassword" +$env:ACDREAM_DEVTOOLS = "1" +$env:ACDREAM_PROBE_PUSH_BACK = "1" +$env:ACDREAM_PROBE_INDOOR_BSP = "1" +$env:ACDREAM_PROBE_CELL = "1" +$env:ACDREAM_PROBE_CELL_CACHE = "1" +$env:ACDREAM_PROBE_CONTACT_PLANE = "1" + +dotnet run --project src\AcDream.App\AcDream.App.csproj --no-build -c Debug 2>&1 | + Tee-Object -FilePath "docs\research\2026-05-21-a6-captures\scen1_inn_doorway\acdream.log" +``` + +The `[push-back]`, `[push-back-disp]`, `[push-back-cell]` lines in +`acdream.log` pair with the `[BP1]..[BP7]` lines in `retail.log` via +scenario tag. + +## Known watchouts + +Per [`CLAUDE.md`](../../CLAUDE.md#known-watchouts): + +- **High BP hit rates cause retail lag.** 50K threshold is the calibrated + ceiling that keeps retail responsive without triggering ACE timeout. +- **`qd` (quit detached) is forbidden in BP actions** per CLAUDE.md cdb + watchout. The a6-probe.cdb script puts `qd` ONLY in the threshold + branch, NOT directly in a BP action's primary command list. Verify this + is preserved if editing. +- **Killing cdb kills retail.** `qd` detaches cleanly; `Stop-Process` does + not. If you must interrupt mid-capture, press Ctrl-Break in the cdb + console. +- **acclient.exe is 32-bit + uses thiscall.** `this` is in `ecx`. Struct + field offsets in the script come from `docs/research/named-retail/acclient.h`. +``` + +- [ ] **Step 2: Commit** + +```bash +git add tools/cdb/README-a6-probe.md +git commit -m "$(cat <<'EOF' +docs(cdb): A6.P1 — README for the cdb probe + runner + +Documents prerequisites (PDB match, cdb install, retail+ACE +running), per-scenario invocation, the 9-scenario tag table, and +the parallel acdream capture command. Includes the CLAUDE.md cdb +watchouts inline so probe operators don't have to chase them. + +Co-Authored-By: Claude Opus 4.7 (1M context) +EOF +)" +``` + +--- + +## Phase C — Execute 9 captures + file findings stub + +### Task 13: Verify retail binary matches PDB + +**Files:** None modified — verification step. + +- [ ] **Step 1: Run the PDB matcher** + +```powershell +py tools\pdb-extract\check_exe_pdb.py "C:\Turbine\Asheron's Call\acclient.exe" +``` + +Expected: `=== MATCH: this exe pairs with our acclient.pdb ===` + +If MISMATCH: stop. Investigate which retail build is installed; either re-install the matching build or update `refs/acclient.pdb` to match. Don't proceed with captures using a mismatched PDB — symbol resolution will fail and all BP actions will dump garbage. + +- [ ] **Step 2: Document the result in the capture directory** + +After confirming MATCH, capture the verification output to file. This is the audit trail for the capture session: + +```powershell +mkdir -p docs\research\2026-05-21-a6-captures +py tools\pdb-extract\check_exe_pdb.py "C:\Turbine\Asheron's Call\acclient.exe" > docs\research\2026-05-21-a6-captures\pdb-match-verification.txt 2>&1 +``` + +- [ ] **Step 3: Commit the verification artifact** + +```bash +git add docs/research/2026-05-21-a6-captures/pdb-match-verification.txt +git commit -m "$(cat <<'EOF' +docs(research): A6.P1 — record retail-PDB match verification + +Audit trail for the A6.P1 capture session: confirms the live retail +acclient.exe matches refs/acclient.pdb before any BP-driven +captures fire. + +Co-Authored-By: Claude Opus 4.7 (1M context) +EOF +)" +``` + +--- + +### Task 14: Create capture directory structure + findings doc stub + +**Files:** +- Create: `docs/research/2026-05-21-a6-captures/scen{1..9}_/.gitkeep` (9 stub dirs) +- Create: `docs/research/2026-05-21-a6-cdb-capture-findings.md` (findings doc stub) + +- [ ] **Step 1: Create the per-scenario directory stubs** + +```powershell +$scenarios = @( + "scen1_inn_doorway", + "scen2_inn_stairs", + "scen3_inn_2nd_floor", + "scen4_cottage_cellar", + "scen5_sewer_entry", + "scen6_sewer_first_stair", + "scen7_sewer_inter_room", + "scen8_sewer_chamber", + "scen9_sewer_corridor" +) +foreach ($s in $scenarios) { + $dir = "docs\research\2026-05-21-a6-captures\$s" + if (-not (Test-Path $dir)) { New-Item -ItemType Directory -Path $dir | Out-Null } + New-Item -ItemType File -Path "$dir\.gitkeep" -Force | Out-Null +} +``` + +- [ ] **Step 2: Create the findings doc stub** + +Create `docs/research/2026-05-21-a6-cdb-capture-findings.md`: + +```markdown +# A6.P1 cdb capture findings — 2026-05-21 + +**Status:** STUB — captures in progress. Tables filled by A6.P2 analysis. + +**Spec:** [`docs/superpowers/specs/2026-05-21-phase-a6-indoor-physics-fidelity-design.md`](../superpowers/specs/2026-05-21-phase-a6-indoor-physics-fidelity-design.md). + +**PDB match verification:** [`pdb-match-verification.txt`](2026-05-21-a6-captures/pdb-match-verification.txt). + +## Capture inventory + +| Scenario | Tag | Retail log | acdream log | Status | +|---|---|---|---|---| +| 1 | scen1_inn_doorway | [retail.log](2026-05-21-a6-captures/scen1_inn_doorway/retail.log) | [acdream.log](2026-05-21-a6-captures/scen1_inn_doorway/acdream.log) | pending | +| 2 | scen2_inn_stairs | [retail.log](2026-05-21-a6-captures/scen2_inn_stairs/retail.log) | [acdream.log](2026-05-21-a6-captures/scen2_inn_stairs/acdream.log) | pending | +| 3 | scen3_inn_2nd_floor | [retail.log](2026-05-21-a6-captures/scen3_inn_2nd_floor/retail.log) | [acdream.log](2026-05-21-a6-captures/scen3_inn_2nd_floor/acdream.log) | pending | +| 4 | scen4_cottage_cellar | [retail.log](2026-05-21-a6-captures/scen4_cottage_cellar/retail.log) | [acdream.log](2026-05-21-a6-captures/scen4_cottage_cellar/acdream.log) | pending | +| 5 | scen5_sewer_entry | [retail.log](2026-05-21-a6-captures/scen5_sewer_entry/retail.log) | [acdream.log](2026-05-21-a6-captures/scen5_sewer_entry/acdream.log) | pending | +| 6 | scen6_sewer_first_stair | [retail.log](2026-05-21-a6-captures/scen6_sewer_first_stair/retail.log) | [acdream.log](2026-05-21-a6-captures/scen6_sewer_first_stair/acdream.log) | pending | +| 7 | scen7_sewer_inter_room | [retail.log](2026-05-21-a6-captures/scen7_sewer_inter_room/retail.log) | [acdream.log](2026-05-21-a6-captures/scen7_sewer_inter_room/acdream.log) | pending | +| 8 | scen8_sewer_chamber | [retail.log](2026-05-21-a6-captures/scen8_sewer_chamber/retail.log) | [acdream.log](2026-05-21-a6-captures/scen8_sewer_chamber/acdream.log) | pending | +| 9 | scen9_sewer_corridor | [retail.log](2026-05-21-a6-captures/scen9_sewer_corridor/retail.log) | [acdream.log](2026-05-21-a6-captures/scen9_sewer_corridor/acdream.log) | pending | + +## Analysis tables (filled by A6.P2) + +### Table 1 — Per-site push-back delta + +*Placeholder — filled by A6.P2 analysis. Rows = (site × scenario) cross-product. +Delta computed as `‖output_center − input_center‖` per call. Bug candidate +threshold: ratio > 3× retail.* + +| Site | Scenario | Retail mean delta (mm) | Retail p99 (mm) | acdream mean (mm) | acdream p99 (mm) | Ratio | +|---|---|---|---|---|---|---| + +### Table 2 — Path-frequency diff + +*Placeholder — filled by A6.P2 analysis. Paths labeled 1-7 per the +find_collisions dispatcher.* + +| Scenario | Path | Retail count | acdream count | Diff % | +|---|---|---|---|---| + +### Table 3 — ContactPlane lifecycle diff + +*Placeholder — filled by A6.P2 analysis.* + +| Scenario | Retail CP writes/sec | acdream CP writes/sec | Retail CP-restore-from-LKCP/sec | acdream CP-restore/sec | +|---|---|---|---|---| + +### Table 4 — Sub-step state mutations + +*Placeholder — filled by A6.P2 analysis. Fields: cell_array_valid, +hits_interior_cell, walk_interp, walkable, collide.* + +| Scenario | Field | Retail mutations/sec | acdream mutations/sec | +|---|---|---|---| + +## Per-scenario narrative (filled by A6.P2) + +### Scenario 1 — Inn doorway entry + +*Placeholder.* + +### Scenario 2 — Inn stairs ascent + +*Placeholder.* + +*(etc. — 3 through 9)* + +## Findings (filled by A6.P2) + +*Numbered bug candidates. Each entry contains: title, retail decomp +anchor (line in acclient_2013_pseudo_c.txt), our suspect code site +(file + line), divergence quantified, proposed fix sketch, scenarios +affected.* +``` + +- [ ] **Step 3: Commit the stub structure** + +```bash +git add docs/research/2026-05-21-a6-captures/ docs/research/2026-05-21-a6-cdb-capture-findings.md +git commit -m "$(cat <<'EOF' +docs(research): A6.P1 — capture directory structure + findings stub + +Creates the 9 per-scenario capture directories (gitkeep stubs) and +the findings doc stub at docs/research/2026-05-21-a6-cdb-capture-findings.md. +A6.P1 fills the capture log slots; A6.P2 fills the analysis tables +and findings section. + +Co-Authored-By: Claude Opus 4.7 (1M context) +EOF +)" +``` + +--- + +### Task 15: Execute the 9 capture scenarios (USER-DRIVEN) + +**Files:** +- Modify (filled by capture runs): `docs/research/2026-05-21-a6-captures/scen{1..9}_/{retail,acdream}.log` +- Modify: `docs/research/2026-05-21-a6-cdb-capture-findings.md` (update "Status" column from `pending` → `captured`) + +**Operator role:** This task is USER-DRIVEN — the user runs retail + acdream +clients, executes the scripted walks, and confirms each scenario's +capture pair is filed. Each scenario is ~5 min of user time at the +keyboard. Captures can be split across days; each scenario's pair is +self-contained. + +For EACH of the 9 scenarios: + +- [ ] **Step 1: Position retail at scenario start** + +Open retail client, navigate to the scenario start position. For +scenario 1: outside the Holtburg inn front door, facing the doorway. +Stop. (Don't move while the cdb attaches.) + +- [ ] **Step 2: Attach cdb with the scenario tag** + +```powershell +.\tools\cdb\a6-probe-runner.ps1 -ScenarioTag "" +``` + +Wait for `a6-probe armed: BPs 1-7 set, threshold=50000 total hits, qd on threshold` +in the cdb console. + +- [ ] **Step 3: Launch acdream with all probes enabled** + +In a SEPARATE PowerShell window: + +```powershell +$env:ACDREAM_DAT_DIR = "$env:USERPROFILE\Documents\Asheron's Call" +$env:ACDREAM_LIVE = "1" +$env:ACDREAM_TEST_HOST = "127.0.0.1" +$env:ACDREAM_TEST_PORT = "9000" +$env:ACDREAM_TEST_USER = "testaccount" +$env:ACDREAM_TEST_PASS = "testpassword" +$env:ACDREAM_DEVTOOLS = "1" +$env:ACDREAM_PROBE_PUSH_BACK = "1" +$env:ACDREAM_PROBE_INDOOR_BSP = "1" +$env:ACDREAM_PROBE_CELL = "1" +$env:ACDREAM_PROBE_CELL_CACHE = "1" +$env:ACDREAM_PROBE_CONTACT_PLANE = "1" + +dotnet build -c Debug +dotnet run --project src\AcDream.App\AcDream.App.csproj --no-build -c Debug 2>&1 | + Tee-Object -FilePath "docs\research\2026-05-21-a6-captures\\acdream.log" +``` + +Navigate `+Acdream` to the same scenario start position. Stop. + +- [ ] **Step 4: Perform the scripted walk in BOTH clients** + +Per the README table: + +| Scenario | Walk script | +|---|---| +| 1 inn doorway | Walk forward through door, stop just inside | +| 2 inn stairs | Walk up 4 steps, stop on landing | +| 3 inn 2nd floor | Walk forward 3 m, sidestep 1 m, walk back | +| 4 cottage cellar | Walk to cellar opening, descend 2 steps | +| 5 sewer entry | Walk into portal, then walk 2 m forward inside | +| 6 sewer first stair | Walk down full stair flight | +| 7 sewer inter-room | Walk through portal, stop 1 m past | +| 8 sewer chamber | Walk in, traverse center, walk out other side | +| 9 sewer corridor | Walk full length end-to-end | + +Perform the SAME walk in retail and in acdream. cdb fires BPs; acdream +emits `[push-back]` lines. + +- [ ] **Step 5: Teardown** + +cdb auto-detaches at 50K hits. If it doesn't fire within ~30 sec of the +walk completing, press Ctrl-Break in the cdb console. + +Close acdream by gracefully closing the window (NOT Stop-Process, per +CLAUDE.md logout-before-reconnect rules). + +- [ ] **Step 6: Verify capture files are non-empty** + +```powershell +$dir = "docs\research\2026-05-21-a6-captures\" +Get-Item "$dir\retail.log", "$dir\acdream.log" | Format-Table Name, Length +``` + +Expected: both files > 1 KB. If retail.log is < 1 KB, BPs didn't fire — +investigate (probably PDB load failed or retail wasn't in-world). +If acdream.log doesn't contain `[push-back]` lines, the env var didn't +take effect — re-launch. + +- [ ] **Step 7: Mark scenario captured + commit** + +Update `docs/research/2026-05-21-a6-cdb-capture-findings.md`: change +the scenario's row "Status" from `pending` to `captured`. + +```bash +git add docs/research/2026-05-21-a6-captures// docs/research/2026-05-21-a6-cdb-capture-findings.md +git commit -m "$(cat <<'EOF' +capture(research): A6.P1 — scenario + +Paired retail + acdream traces filed at +docs/research/2026-05-21-a6-captures//. + +Co-Authored-By: Claude Opus 4.7 (1M context) +EOF +)" +``` + +**Repeat steps 1–7 for all 9 scenarios.** Total user time: ~45 min +(5 min per scenario) + ~30 min capture-setup overhead = ~75 min single +session. Splittable across days; each scenario's commit is self-contained. + +--- + +## A6.P1 acceptance + +Phase A6.P1 is complete when: + +1. All 9 scenarios have `{retail,acdream}.log` pairs filed under + `docs/research/2026-05-21-a6-captures/scenN_/`. +2. Each log pair is non-empty (retail > 1 KB, acdream > 1 KB). +3. Each scenario's row in `docs/research/2026-05-21-a6-cdb-capture-findings.md` + shows Status = `captured`. +4. `pdb-match-verification.txt` is filed as audit trail. +5. The `[push-back]`, `[push-back-disp]`, `[push-back-cell]` probes ship + on main (Tasks 1–9 committed). +6. `dotnet build` green, `dotnet test` baseline unchanged (no test + regressions from the probe instrumentation — probe is zero-cost when + off). + +A6.P2 takes the captures + findings doc stub and produces the +quantitative analysis tables + bug candidates list.