acdream/docs/superpowers/plans/2026-05-21-phase-a6-p1-cdb-probe-spike.md
Erik 0bdd5c7fca docs(plan): Phase A6.P1 — cdb probe spike implementation plan
15-task TDD plan covering the three pieces of A6.P1:
  Phase A — Build the [push-back] acdream probe (Tasks 1-9):
    toggle + 3 helpers + 3 emission sites in BSPQuery/Transition,
    DebugVM mirror, CLAUDE.md env-var docs.
  Phase B — Build the cdb infrastructure (Tasks 10-12):
    7-BP cdb script, PowerShell runner, README.
  Phase C — Execute 9 captures + findings stub (Tasks 13-15):
    PDB-match verify, capture dir + findings stub, scenario captures.

API surface verified against current code: ResolvedPolygon has no
Id property (probe omits poly attribution; cross-ref via time-
adjacent [push-back-cell] line). CheckOtherCells locals are
sp.CheckCellId + cellId + result (verified at TransitionTypes.cs
lines 1418-1473). SpherePath has Collide/InsertType/WalkInterp,
ObjectInfo has State (verified).

Spec: docs/superpowers/specs/2026-05-21-phase-a6-indoor-physics-fidelity-design.md

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

1339 lines
49 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.

# 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-<scenario>/{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
/// <summary>
/// Phase A6.P1 cdb probe spike (2026-05-21). When true, every BSP
/// collision response site emits a structured <c>[push-back]</c> 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
/// <c>tools/cdb/a6-probe.cdb</c>.
///
/// <para>
/// Three emission sites: <see cref="BSPQuery.AdjustSphereToPlane"/>
/// (the suspected over-correction site), <see cref="BSPQuery.FindCollisions"/>
/// (the 6-path dispatcher), and <see cref="Transition.CheckOtherCells"/>
/// (multi-cell BSP iteration outcomes). All three are zero-cost when
/// off — checked via early-out at each site.
/// </para>
///
/// <para>
/// Initial state from <c>ACDREAM_PROBE_PUSH_BACK=1</c>.
/// Runtime-toggleable via DebugVM mirror.
/// </para>
///
/// <para>
/// Spec: <c>docs/superpowers/specs/2026-05-21-phase-a6-indoor-physics-fidelity-design.md</c>.
/// </para>
/// </summary>
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) <noreply@anthropic.com>
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
/// <summary>
/// A6.P1 emission helper for the <c>AdjustSphereToPlane</c> 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
/// <c>CPolygon::adjust_sphere_to_plane</c>.
///
/// <para>
/// Caller MUST guard with <c>if (!ProbePushBackEnabled) return;</c>
/// before computing the delta arguments — this method assumes the
/// caller paid that price already.
/// </para>
/// </summary>
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) <noreply@anthropic.com>
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) <noreply@anthropic.com>
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
/// <summary>
/// A6.P1 emission helper for the <c>FindCollisions</c> 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
/// <c>BSPTREE::find_collisions</c>.
///
/// <para>
/// Caller MUST guard with <c>if (!ProbePushBackEnabled) return;</c>
/// before calling.
/// </para>
/// </summary>
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) <noreply@anthropic.com>
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) <noreply@anthropic.com>
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
/// <summary>
/// A6.P1 emission helper for the <c>CheckOtherCells</c> 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
/// <c>CTransition::check_other_cells</c> loop at decomp line
/// 272717. Augments the existing A4 multi-cell BSP instrumentation
/// with explicit per-iteration outcome telemetry.
///
/// <para>
/// Caller MUST guard with <c>if (!ProbePushBackEnabled) return;</c>
/// before calling.
/// </para>
/// </summary>
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) <noreply@anthropic.com>
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) <noreply@anthropic.com>
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
/// <summary>
/// Phase A6.P1 cdb probe spike (2026-05-21). Runtime mirror of
/// <c>PhysicsDiagnostics.ProbePushBackEnabled</c> (env var
/// <c>ACDREAM_PROBE_PUSH_BACK</c>). Toggling here flips the three
/// <c>[push-back]</c> emission sites live — no relaunch required.
/// </summary>
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) <noreply@anthropic.com>
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
(~100500 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) <noreply@anthropic.com>
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) <noreply@anthropic.com>
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\<ScenarioTag>\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\<ScenarioTag>\retail.log
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
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) <noreply@anthropic.com>
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) <noreply@anthropic.com>
EOF
)"
```
---
### Task 14: Create capture directory structure + findings doc stub
**Files:**
- Create: `docs/research/2026-05-21-a6-captures/scen{1..9}_<name>/.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) <noreply@anthropic.com>
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}_<name>/{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 "<scenN_name>"
```
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\<scenN_name>\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\<scenN_name>"
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/<scenN_name>/ docs/research/2026-05-21-a6-cdb-capture-findings.md
git commit -m "$(cat <<'EOF'
capture(research): A6.P1 — scenario <N> <name>
Paired retail + acdream traces filed at
docs/research/2026-05-21-a6-captures/<scenN_name>/.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
EOF
)"
```
**Repeat steps 17 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_<name>/`.
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 19 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.