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

49 KiB
Raw Blame History

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.


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):

    // -----------------------------------------------------------------------
    // 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):

    /// <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
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:

    /// <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
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:

    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):

$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
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:

    /// <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
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:

        // 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
$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
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:

    /// <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
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:

            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:

            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
$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
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:


    /// <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
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:

- `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
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

ls tools/ 2>&1; mkdir -p tools/cdb
  • Step 2: Write the cdb script

Create tools/cdb/a6-probe.cdb:

$$
$$ 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
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:

# 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
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:

# 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 ===

  1. 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.

  2. Retail running and in-world. Launch retail, log into your character, navigate to the scenario start point.

  3. ACE running locally on 127.0.0.1:9000.

Usage

For each of the 9 A6.P1 scenarios:

# 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:

$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:

  • 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
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:

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
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

$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:

# 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
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 pendingcaptured)

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
.\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:

$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
$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.

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.