P0 (verbatim-spatial-pipeline-port) Tasks 1+2. ConformanceDats loads the cottage-doorway cells from the real dats with their real ContainmentBsp; CottageDoorwayCharacterizationTests maps the Holtburg 0140..017F indoor neighborhood and pins the master-plan threshold building (origin 161.93,7.50,94.00): 0xA9B40170 vestibule (exit portal 0xFFFF + portal to 0171), 0xA9B40171 room. Grid math confirms the outdoor side is landcell 0xA9B40031 -> the 0031<->0170<->0171 ping-pong is verified real. Verified interior points recorded for the point_in_cell/find_cell_list goldens. Plan: docs/superpowers/plans/2026-06-03-p0-conformance-apparatus.md Notes: docs/research/2026-06-03-p0-conformance-apparatus-notes.md Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
32 KiB
P0 — Conformance Apparatus Implementation Plan
For agentic workers: REQUIRED SUB-SKILL: Use superpowers:executing-plans (inline) to implement this plan task-by-task. Steps use checkbox (
- [ ]) syntax for tracking.
Goal: Build the headless, dat-backed conformance apparatus that lets every later phase
(P1 membership, P2 door collision, P3 camera, P4 PView render) prove a port is verbatim
retail — not "vibes" — by asserting real-retail outcomes (point_in_cell, find_cell_list,
PVS visible-set) against fixtures loaded from the real client dats and against captured retail
cdb traces.
Architecture: Three layers. (1) A dat-backed fixture loader that hydrates the Holtburg
cottage-doorway cell neighborhood from the real dats with their real containment BSPs (no
synthetic BSP, no JSON round-trip). (2) Golden conformance tests that pin retail-faithful
outcomes — point_in_cell is geometric ground truth (the BSP is retail data, loaded from the
same dats retail loads); find_cell_list pins the membership pick, with the subtle
doorway-threshold case backed by a captured retail cdb trace. (3) cdb value-capture
tooling — a new script that dumps find_cell_list's cell-id argument/return at the threshold
(value, not just hit-count), plus a parser that turns its log into a golden fixture. The live
capture run is the single user-gated step; everything else is autonomous + headless.
Tech Stack: C# / .NET 10, xUnit, DatReaderWriter (DatCollection.Get<T>), the existing
PhysicsDataCache / CellTransit / BSPQuery engine, cdb (acclient.pdb) per the CLAUDE.md
retail-debugger toolchain.
Scope note — what P0 is NOT. P0 does not change any production membership/collision/render
code. It only adds tests/ + tools/cdb/ + docs/. The PVS visible-set golden is
scaffolded (structure + retail anchor + a skipped placeholder) but not filled — a retail
cell_draw_list trace is a P3/P4-coupled capture and the PVS code itself is replaced in P4.
P0's load-bearing deliverable is the membership goldens (point_in_cell + find_cell_list)
that P1 consumes immediately, plus ≥1 assertion backed by a real retail trace (the P1 gate).
File Structure
| File | Responsibility |
|---|---|
tests/AcDream.Core.Tests/Conformance/ConformanceDats.cs (create) |
Shared dat-dir resolution + one-call headless load of an EnvCell (real ContainmentBsp) and a cached CellPhysics by cell id. The single seam tests use to reach the real dats. |
tests/AcDream.Core.Tests/Conformance/CottageDoorwayCharacterizationTests.cs (create) |
Characterize-and-pin the real cottage-doorway cell topology (ids, worldOrigin, portals incl. the 0xFFFF exit portal, seenOutside, has-ContainmentBsp). Discovers the exact IDs the rest of P0 uses. |
tests/AcDream.Core.Tests/Conformance/PointInCellConformanceTests.cs (create) |
Golden point_in_cell: assert containment for geometrically-known points against the real BSP. Retail-faithful by construction. |
tests/AcDream.Core.Tests/Conformance/FindCellListConformanceTests.cs (create) |
Golden find_cell_list: unambiguous picks (clearly-inside / clearly-outside) from dats + the doorway-threshold pick pinned to a captured retail trace. |
tests/AcDream.Core.Tests/Conformance/RetailTrace.cs (create) |
Parser: read a find-cell-list retail cdb log → strongly-typed RetailCellPick[] golden records. TDD'd against a checked-in sample log line. |
tools/cdb/find-cell-list-capture.cdb (create) |
New cdb script: breakpoint CObjCell::find_cell_list, dump the input position + the returned containing cell id (value capture). Ready for the user to run against live retail at the cottage doorway. |
tools/cdb/README-find-cell-list-capture.md (create) |
Operator runbook for the capture: prerequisites, exact launch command, what to walk, where the log lands, how to fold it into the golden. |
docs/research/2026-06-03-p0-conformance-apparatus-notes.md (create) |
Living notes: the characterized cottage-doorway topology, the golden values + their provenance (geometric vs retail-trace), and the P1-entry checklist. |
Task 1 — Shared dat-backed fixture loader
Files:
- Create:
tests/AcDream.Core.Tests/Conformance/ConformanceDats.cs
The loader mirrors the proven dat-read pattern in
tests/AcDream.Core.Tests/Physics/DoorBugTrajectoryReplayTests.cs:184-219
(DatCollection.Get<EnvCell> → Get<Environment> → CellStruct → physics-verbatim
worldTransform) and the EnvCell.FromDat derivation
(src/AcDream.Core/World/Cells/EnvCell.cs:42-76). It returns BOTH a EnvCell (for
PointInCell) and a cached CellPhysics (for CellTransit), so membership tests have one seam.
- Step 1: Write the loader
using System;
using System.IO;
using System.Numerics;
using AcDream.Core.Physics;
using AcDream.Core.World.Cells;
using DatReaderWriter;
using DatReaderWriter.Options;
using DatEnvCell = DatReaderWriter.DBObjs.EnvCell;
using DatEnvironment = DatReaderWriter.DBObjs.Environment;
using Env = System.Environment;
namespace AcDream.Core.Tests.Conformance;
/// <summary>
/// P0 conformance apparatus — headless load of the real Holtburg dats.
/// Tests that need real cell geometry (the retail containment BSP) resolve
/// the dat dir here and load cells via <see cref="LoadEnvCell"/>. Returns
/// null dat dir when the dats are absent (CI) so callers can skip cleanly,
/// matching DoorBugTrajectoryReplayTests.ResolveDatDir.
/// </summary>
public static class ConformanceDats
{
private const uint EnvironmentFilePrefix = 0x0D000000u; // dat namespace for Environment files
/// <summary>The Holtburg landblock these fixtures live in.</summary>
public const uint HoltburgLandblock = 0xA9B40000u;
/// <summary>Resolve the client dat directory, or null if unavailable (skip the test).</summary>
public static string? ResolveDatDir()
{
var fromEnv = Env.GetEnvironmentVariable("ACDREAM_DAT_DIR");
if (!string.IsNullOrWhiteSpace(fromEnv) && Directory.Exists(fromEnv))
return fromEnv;
var def = Path.Combine(
Env.GetFolderPath(Env.SpecialFolder.UserProfile),
"Documents", "Asheron's Call");
return Directory.Exists(def) ? def : null;
}
/// <summary>The physics-verbatim cell→world transform (no +2cm render lift).</summary>
public static Matrix4x4 WorldTransform(DatEnvCell datCell) =>
Matrix4x4.CreateFromQuaternion(datCell.Position.Orientation) *
Matrix4x4.CreateTranslation(datCell.Position.Origin);
/// <summary>
/// Load one EnvCell from the dats with its REAL containment BSP, and register
/// it into <paramref name="cache"/> as a CellPhysics. Returns the high-level
/// EnvCell (PointInCell) so a single load serves both membership predicates.
/// </summary>
public static EnvCell LoadEnvCell(DatCollection dats, PhysicsDataCache cache, uint cellId)
{
var datCell = dats.Get<DatEnvCell>(cellId)
?? throw new InvalidOperationException($"EnvCell 0x{cellId:X8} not found in dats");
var environment = dats.Get<DatEnvironment>(EnvironmentFilePrefix | datCell.EnvironmentId)
?? throw new InvalidOperationException($"Environment 0x{datCell.EnvironmentId:X8} not found");
if (!environment.Cells.TryGetValue(datCell.CellStructure, out var cellStruct) || cellStruct is null)
throw new InvalidOperationException($"CellStruct {datCell.CellStructure} missing from environment");
var world = WorldTransform(datCell);
cache.CacheCellStruct(cellId, datCell, cellStruct, world); // physics CellPhysics (real CellBSP)
return EnvCell.FromDat(cellId, datCell, cellStruct, world); // render/containment EnvCell (real ContainmentBsp)
}
}
- Step 2: Verify it compiles
Run: dotnet build tests/AcDream.Core.Tests/AcDream.Core.Tests.csproj -c Debug
Expected: build succeeds (no test yet — Task 2 exercises it).
- Step 3: Commit
git add tests/AcDream.Core.Tests/Conformance/ConformanceDats.cs
git commit -m "test(p0): dat-backed cottage-doorway fixture loader (ConformanceDats)"
Task 2 — Characterize and pin the cottage-doorway topology
Files:
- Create:
tests/AcDream.Core.Tests/Conformance/CottageDoorwayCharacterizationTests.cs - Create:
docs/research/2026-06-03-p0-conformance-apparatus-notes.md
The master plan names the neighborhood loosely (0xA9B4003x + 0xA9B4017x), and the 0170/0171
ids are reused across buildings in landblock 0xA9B4. So this task discovers the real
topology and pins it. The candidate indoor ids are 0xA9B40170 and 0xA9B40171 (the
ping-pong pair named in the master plan §0). The test prints each cell's structure on first run;
fill the asserts from the printout, then they become the pinned characterization.
- Step 1: Write the characterization test (observe form)
using System;
using System.Linq;
using AcDream.Core.Physics;
using DatReaderWriter;
using DatReaderWriter.Options;
using Xunit;
using Xunit.Abstractions;
namespace AcDream.Core.Tests.Conformance;
public class CottageDoorwayCharacterizationTests
{
private readonly ITestOutputHelper _out;
public CottageDoorwayCharacterizationTests(ITestOutputHelper output) => _out = output;
// Candidate indoor cells of the cottage-doorway ping-pong (master plan §0: 0031↔0170↔0171).
public static readonly uint[] CandidateIndoor = { 0xA9B40170u, 0xA9B40171u };
[Fact]
public void Characterize_CottageDoorwayCells_PrintStructure()
{
var datDir = ConformanceDats.ResolveDatDir();
if (datDir is null) { _out.WriteLine("SKIP: dats unavailable"); return; }
using var dats = new DatCollection(datDir, DatAccessType.Read);
var cache = new PhysicsDataCache();
foreach (var id in CandidateIndoor)
{
var cell = ConformanceDats.LoadEnvCell(dats, cache, id);
var phys = cache.GetCellStruct(id)!;
var origin = System.Numerics.Vector3.Transform(
System.Numerics.Vector3.Zero, phys.WorldTransform);
bool hasExitPortal = phys.Portals!.Any(p => p.OtherCellId == 0xFFFFu);
_out.WriteLine(
$"0x{id:X8}: worldOrigin=({origin.X:F2},{origin.Y:F2},{origin.Z:F2}) " +
$"seenOutside={cell.SeenOutside} hasContainmentBsp={cell.ContainmentBsp?.Root is not null} " +
$"portals={phys.Portals!.Count} exitPortal={hasExitPortal} " +
$"stab={cell.StabList.Count} " +
$"portalDests=[{string.Join(",", phys.Portals!.Select(p => $"0x{p.OtherCellId:X4}"))}]");
}
}
}
- Step 2: Run it and READ the printed structure
Run: dotnet test tests/AcDream.Core.Tests/AcDream.Core.Tests.csproj -c Debug --filter "FullyQualifiedName~Characterize_CottageDoorwayCells" -l "console;verbosity=detailed"
Expected: PASS, with two 0xA9B401XX: worldOrigin=... portalDests=[...] lines in the output.
Record those lines in docs/research/2026-06-03-p0-conformance-apparatus-notes.md under a
"Characterized topology" heading. They are the source of truth for Tasks 2b/3.
If a candidate id throws "not found in dats", it is the wrong id — widen the candidate scan to
0xA9B40170..0xA9B40179in the loop, re-run, and identify the two cells whoseworldOriginmatches the cottage (low Y, near the014xcellar) and that form a portal pair (one'sportalDestscontains the other). Pin those two ids.
- Step 3: Pin the discovered values (assert form)
Replace the print-only body with explicit asserts using the recorded values, e.g. (substitute the REAL numbers you recorded — these are illustrative):
[Fact]
public void CottageDoorway_Cell0170_IsVestibuleWithExitPortal()
{
var datDir = ConformanceDats.ResolveDatDir();
if (datDir is null) return;
using var dats = new DatCollection(datDir, DatAccessType.Read);
var cache = new PhysicsDataCache();
var cell = ConformanceDats.LoadEnvCell(dats, cache, 0xA9B40170u);
var phys = cache.GetCellStruct(0xA9B40170u)!;
Assert.True(cell.ContainmentBsp?.Root is not null, "real cell BSP must load");
Assert.NotEmpty(phys.Portals!);
// Pin whatever the characterization printed — exit portal presence is the load-bearing fact:
Assert.Contains(phys.Portals!, p => p.OtherCellId == 0xFFFFu || p.OtherCellId == 0x0171u);
}
Keep the Characterize_..._PrintStructure test (it documents the data and re-runs cheaply).
- Step 4: Run to verify the pinned asserts pass
Run: dotnet test tests/AcDream.Core.Tests/AcDream.Core.Tests.csproj -c Debug --filter "FullyQualifiedName~CottageDoorwayCharacterizationTests"
Expected: PASS (both tests).
- Step 5: Commit
git add tests/AcDream.Core.Tests/Conformance/CottageDoorwayCharacterizationTests.cs docs/research/2026-06-03-p0-conformance-apparatus-notes.md
git commit -m "test(p0): characterize + pin cottage-doorway cell topology from dats"
Task 3 — point_in_cell golden conformance
Files:
- Create:
tests/AcDream.Core.Tests/Conformance/PointInCellConformanceTests.cs - Modify:
docs/research/2026-06-03-p0-conformance-apparatus-notes.md
Retail's point_in_cell for an EnvCell is BSPTREE::point_in_cell_bsp against cell_bsp
(master plan A6; reference doc §6.3). Our EnvCell.PointInCell → BSPQuery.PointInsideCellBsp
is the port. The BSP is loaded from the same dats retail loads, so a geometrically-correct
containment answer is the retail answer. Goldens: a point at the cell's world origin-ish
interior must be inside; a point far outside the landblock must be outside; the matching point
must be inside exactly one of the doorway pair.
- Step 1: Write the failing test
using System.Numerics;
using AcDream.Core.Physics;
using DatReaderWriter;
using DatReaderWriter.Options;
using Xunit;
namespace AcDream.Core.Tests.Conformance;
public class PointInCellConformanceTests
{
[Fact]
public void PointInCell_InteriorPoint_IsInsideItsOwnCell()
{
var datDir = ConformanceDats.ResolveDatDir();
if (datDir is null) return;
using var dats = new DatCollection(datDir, DatAccessType.Read);
var cache = new PhysicsDataCache();
var cell = ConformanceDats.LoadEnvCell(dats, cache, 0xA9B40171u);
var phys = cache.GetCellStruct(0xA9B40171u)!;
// A point just above the cell's covering-sphere centre, in world space, is interior.
var localCentre = phys.CellBSP is not null
? cache.GetCellStruct(0xA9B40171u)!.WorldTransform // placeholder; replaced below
: default;
// Use the cell's bounding-sphere origin (cell-local) lifted to world:
var worldCentre = Vector3.Transform(CharacterizedInteriorLocal_0171, phys.WorldTransform);
Assert.True(cell.PointInCell(worldCentre),
$"interior point {worldCentre} must be inside cell 0x0171's BSP");
}
[Fact]
public void PointInCell_FarAwayPoint_IsOutside()
{
var datDir = ConformanceDats.ResolveDatDir();
if (datDir is null) return;
using var dats = new DatCollection(datDir, DatAccessType.Read);
var cache = new PhysicsDataCache();
var cell = ConformanceDats.LoadEnvCell(dats, cache, 0xA9B40171u);
var faraway = new Vector3(10000f, 10000f, 10000f);
Assert.False(cell.PointInCell(faraway), "a point 10 km away cannot be inside");
}
// Pin this from Task 2's characterization: a cell-LOCAL point clearly inside 0x0171's volume
// (e.g. its bounding-sphere origin, or (0,0,1) if the cell is centred on its local origin).
private static readonly Vector3 CharacterizedInteriorLocal_0171 = new(0f, 0f, 1.0f);
}
- Step 2: Run to verify it fails (or reveals the right interior point)
Run: dotnet test ... --filter "FullyQualifiedName~PointInCellConformanceTests" -l "console;verbosity=detailed"
Expected: PointInCell_FarAwayPoint_IsOutside PASSES immediately. ..._IsInsideItsOwnCell may
FAIL if CharacterizedInteriorLocal_0171 isn't actually inside — that's the signal to use the
real interior point from Task 2 (the cell's bounding-sphere origin, printed by adding it to the
characterization output).
- Step 3: Fix the interior point from characterization data
Augment the Task-2 print to also emit the cell's bounding-sphere origin (cell-local), then set
CharacterizedInteriorLocal_0171 to a point you've confirmed is inside (the sphere origin, or a
point nudged toward the floor). Remove the dead localCentre placeholder line.
- Step 4: Run to verify both pass
Run: dotnet test ... --filter "FullyQualifiedName~PointInCellConformanceTests"
Expected: PASS (both).
- Step 5: Commit
git add tests/AcDream.Core.Tests/Conformance/PointInCellConformanceTests.cs docs/research/2026-06-03-p0-conformance-apparatus-notes.md
git commit -m "test(p0): point_in_cell golden conformance vs real dat BSP"
Task 4 — find_cell_list golden conformance (unambiguous cases)
Files:
- Create:
tests/AcDream.Core.Tests/Conformance/FindCellListConformanceTests.cs
CellTransit.FindCellList(cache, sphereCentre, radius, currentCellId) is the membership pick.
Unambiguous goldens come straight from the real dats: a sphere clearly inside room 0x0171
returns 0x0171; a sphere clearly inside vestibule 0x0170 returns 0x0170. These pin the pick
without needing a retail trace (the geometry is retail data). The threshold case (ping-pong)
is Task 6, backed by a retail trace.
- Step 1: Write the failing test
using System.Collections.Generic;
using System.Numerics;
using AcDream.Core.Physics;
using DatReaderWriter;
using DatReaderWriter.Options;
using Xunit;
namespace AcDream.Core.Tests.Conformance;
public class FindCellListConformanceTests
{
private const float FootRadius = 0.4f; // retail player foot-sphere radius (PhysicsBody default)
[Fact]
public void FindCellList_DeepInsideRoom0171_Returns0171()
{
var datDir = ConformanceDats.ResolveDatDir();
if (datDir is null) return;
using var dats = new DatCollection(datDir, DatAccessType.Read);
var cache = new PhysicsDataCache();
ConformanceDats.LoadEnvCell(dats, cache, 0xA9B40170u);
var room = ConformanceDats.LoadEnvCell(dats, cache, 0xA9B40171u);
var phys = cache.GetCellStruct(0xA9B40171u)!;
// A world point confirmed interior to 0x0171 in Task 3:
var inside0171 = Vector3.Transform(DeepInsideLocal_0171, phys.WorldTransform);
Assert.True(room.PointInCell(inside0171), "fixture sanity: point must be inside 0x0171");
// find_cell_list seeded from the room itself must return the room.
uint picked = CellTransit.FindCellList(cache, inside0171, FootRadius, 0xA9B40171u);
Assert.Equal(0xA9B40171u, picked);
}
// Pin from Task 3 (a cell-local point well inside 0x0171, away from any portal plane):
private static readonly Vector3 DeepInsideLocal_0171 = new(0f, 0f, 1.0f);
}
- Step 2: Run to verify
Run: dotnet test ... --filter "FullyQualifiedName~FindCellListConformanceTests" -l "console;verbosity=detailed"
Expected: PASS. If it returns a different cell, record the actual return in the notes doc and
investigate whether the seed point is too near a portal plane (move it deeper). A genuine
divergence here is itself a finding — document it; do NOT change production code in P0.
- Step 3: Commit
git add tests/AcDream.Core.Tests/Conformance/FindCellListConformanceTests.cs
git commit -m "test(p0): find_cell_list golden — unambiguous interior picks from dats"
Task 5 — Retail-trace parser + cdb value-capture tooling
Files:
- Create:
tests/AcDream.Core.Tests/Conformance/RetailTrace.cs - Create:
tools/cdb/find-cell-list-capture.cdb - Create:
tools/cdb/README-find-cell-list-capture.md
The autonomous half of the retail-trace golden: the parser (TDD'd against a sample line) and the capture script (ready to run). The capture run is the user gate in Task 6.
The cdb script breakpoints CObjCell::find_cell_list (acclient!CObjCell::find_cell_list,
0x52b4e0). this (the seed cell, thiscall → ecx) carries objcell_id at a known offset;
the position is an argument. We log the seed cell id and the position, and (via a return
breakpoint) the picked cell id. The exact field offsets are confirmed at capture time with
dt acclient!CObjCell @ecx (CLAUDE.md retail-debugger watchouts). The script emits lines of the
form [fcl] seed=0xHHHHHHHH px=<f> py=<f> pz=<f> picked=0xHHHHHHHH.
- Step 1: Write the failing parser test
using System.Numerics;
using Xunit;
namespace AcDream.Core.Tests.Conformance;
public class RetailTraceTests
{
[Fact]
public void Parse_FindCellListLine_YieldsSeedPosAndPicked()
{
const string line =
"[fcl] seed=0xA9B40170 px=141.5000 py=7.2200 pz=92.7400 picked=0xA9B40171";
var rec = RetailTrace.ParseFindCellList(line);
Assert.NotNull(rec);
Assert.Equal(0xA9B40170u, rec!.SeedCellId);
Assert.Equal(new Vector3(141.5f, 7.22f, 92.74f), rec.Position);
Assert.Equal(0xA9B40171u, rec.PickedCellId);
}
[Fact]
public void Parse_NonMatchingLine_ReturnsNull()
{
Assert.Null(RetailTrace.ParseFindCellList("[BP4] find_collisions hit#10170 collide=0"));
}
}
- Step 2: Run to verify it fails
Run: dotnet test ... --filter "FullyQualifiedName~RetailTraceTests"
Expected: FAIL — RetailTrace does not exist.
- Step 3: Write the parser
using System;
using System.Globalization;
using System.Numerics;
using System.Text.RegularExpressions;
namespace AcDream.Core.Tests.Conformance;
/// <summary>A single retail find_cell_list pick captured via cdb (golden oracle).</summary>
public sealed record RetailCellPick(uint SeedCellId, Vector3 Position, uint PickedCellId);
/// <summary>Parser for the find-cell-list-capture.cdb log format.</summary>
public static class RetailTrace
{
private static readonly Regex Fcl = new(
@"^\[fcl\]\s+seed=0x(?<seed>[0-9A-Fa-f]{1,8})\s+" +
@"px=(?<px>-?\d+(\.\d+)?)\s+py=(?<py>-?\d+(\.\d+)?)\s+pz=(?<pz>-?\d+(\.\d+)?)\s+" +
@"picked=0x(?<picked>[0-9A-Fa-f]{1,8})\s*$",
RegexOptions.Compiled);
public static RetailCellPick? ParseFindCellList(string line)
{
var m = Fcl.Match(line);
if (!m.Success) return null;
var ci = CultureInfo.InvariantCulture;
return new RetailCellPick(
SeedCellId: Convert.ToUInt32(m.Groups["seed"].Value, 16),
Position: new Vector3(
float.Parse(m.Groups["px"].Value, ci),
float.Parse(m.Groups["py"].Value, ci),
float.Parse(m.Groups["pz"].Value, ci)),
PickedCellId: Convert.ToUInt32(m.Groups["picked"].Value, 16));
}
}
- Step 4: Run to verify it passes
Run: dotnet test ... --filter "FullyQualifiedName~RetailTraceTests"
Expected: PASS (both).
- Step 5: Write the cdb capture script
$$ find-cell-list-capture.cdb — value-capture of CObjCell::find_cell_list at the cottage doorway.
$$ Logs the seed cell id + input position + picked cell id (NOT just a hit count).
$$ Prereqs: retail in-world at the Holtburg cottage doorway; PDB matches (check_exe_pdb.py = MATCH).
$$ Offsets for objcell_id + the position arg are CONFIRMED at runtime with `dt acclient!CObjCell @ecx`
$$ and `dv` — edit the @ecx+OFFSET below if the dt dump shows a different layout.
.logopen C:\Users\erikn\source\repos\acdream\find-cell-list-capture.log
.sympath C:\Users\erikn\source\repos\acdream\refs
.symopt+ 0x40
.reload /f acclient.exe
r $t0 = 0
$$ Entry: dump seed cell id (this->objcell_id @ ecx+0x20 — VERIFY with dt) + the position arg.
bp acclient!CObjCell::find_cell_list "r $t0 = @$t0 + 1; .printf /D \"[fcl-entry#%d] seed=0x%08x\\n\", @$t0, poi(@ecx+0x20); .if (@$t0 >= 4000) { qd } .else { gc }"
.printf \"find_cell_list capture armed. Walk SLOWLY in/out of the cottage doorway now.\\n\"
g
- Step 6: Write the operator runbook
Create tools/cdb/README-find-cell-list-capture.md with: the check_exe_pdb.py MATCH
precondition; the exact PowerShell launch (cdb.exe -pn acclient.exe -cf find-cell-list-capture.cdb);
the instruction to first run dt acclient!CObjCell @ecx once to confirm the objcell_id offset
and dv to find the position arg, then edit the script; the walk to perform (stand in the
doorway, step in and out across the threshold 5–10×); where the log lands; and how to hand the
log to Task 6.
- Step 7: Commit
git add tests/AcDream.Core.Tests/Conformance/RetailTrace.cs tools/cdb/find-cell-list-capture.cdb tools/cdb/README-find-cell-list-capture.md
git commit -m "test(p0): retail find_cell_list trace parser + value-capture cdb script"
Task 6 — The retail-trace golden (USER GATE) + P1-entry checklist
Files:
- Modify:
tests/AcDream.Core.Tests/Conformance/FindCellListConformanceTests.cs - Create:
tests/AcDream.Core.Tests/Conformance/Fixtures/find-cell-list-threshold.log(from the capture) - Modify:
docs/research/2026-06-03-p0-conformance-apparatus-notes.md
This task has the one irreducible user-gated step: a live retail cdb capture. Everything is prepped (Task 5). After the capture, encode ≥1 retail pick as a golden assertion — satisfying the kickoff's "do NOT start P1 before ≥1 golden retail-trace assertion exists."
- Step 1: USER GATE — capture the retail trace
Mining the existing committed traces first (docs/research/2026-05-21-a6-captures/scen1_inn_doorway/retail.decoded.log
and scen4_cottage_cellar/retail.decoded.log): grep for any line carrying a find_cell_list
cell-id pick. If one exists in usable form, use it (no new capture needed). Otherwise, ask the
user to run tools/cdb/find-cell-list-capture.cdb per its README against live retail at the
cottage doorway, and place the resulting log at
tests/AcDream.Core.Tests/Conformance/Fixtures/find-cell-list-threshold.log.
- Step 2: Add the trace-backed golden
For each captured RetailCellPick, assert acdream's CellTransit.FindCellList returns the same
picked cell for the same (SeedCellId, Position):
[Fact]
public void FindCellList_DoorwayThreshold_MatchesRetailTrace()
{
var datDir = ConformanceDats.ResolveDatDir();
if (datDir is null) return;
var fixturePath = System.IO.Path.Combine(
System.AppContext.BaseDirectory, "Conformance", "Fixtures", "find-cell-list-threshold.log");
if (!System.IO.File.Exists(fixturePath)) return; // gate not yet satisfied — skip until captured
using var dats = new DatCollection(datDir, DatAccessType.Read);
var cache = new PhysicsDataCache();
foreach (var id in new[] { 0xA9B40170u, 0xA9B40171u })
ConformanceDats.LoadEnvCell(dats, cache, id);
foreach (var raw in System.IO.File.ReadAllLines(fixturePath))
{
var pick = RetailTrace.ParseFindCellList(raw);
if (pick is null) continue;
uint ours = CellTransit.FindCellList(cache, pick.Position, 0.4f, pick.SeedCellId);
Assert.Equal(pick.PickedCellId, ours);
}
}
Per master-plan no-shortcuts rule §4: if this assertion fails, it means acdream diverges from retail at the threshold — that is the P1 work, captured as a RED conformance test. Leave it RED (documents-the-bug) and let P1 turn it GREEN. Do NOT weaken the assertion.
- Step 3: Wire the fixture into the test project so it copies to output
Modify tests/AcDream.Core.Tests/AcDream.Core.Tests.csproj to copy Conformance/Fixtures/**
to the output dir (mirror how existing Fixtures/issue98/** is copied — find that <ItemGroup>
and add the Conformance/Fixtures glob, or confirm a wildcard already covers it).
- Step 4: Run the full conformance suite
Run: dotnet test tests/AcDream.Core.Tests/AcDream.Core.Tests.csproj -c Debug --filter "FullyQualifiedName~Conformance"
Expected: all GREEN, except possibly the documents-the-bug threshold test if acdream diverges
(that RED is a finding for P1, not a P0 failure).
- Step 5: Write the P1-entry checklist into the notes doc
In docs/research/2026-06-03-p0-conformance-apparatus-notes.md, record: the characterized
topology; every golden + its provenance (geometric vs retail-trace); whether the threshold golden
is GREEN (acdream already matches) or RED (P1 must fix); and the explicit statement "P0 gate met:
≥1 retail-trace-backed assertion exists" so P1 can begin.
- Step 6: Commit
git add tests/AcDream.Core.Tests/Conformance/ docs/research/2026-06-03-p0-conformance-apparatus-notes.md tests/AcDream.Core.Tests/AcDream.Core.Tests.csproj
git commit -m "test(p0): retail-trace-backed find_cell_list threshold golden (P1 gate met)"
Task 7 — PVS-golden scaffold (structure only, fill deferred to P3/P4)
Files:
- Create:
tests/AcDream.Core.Tests/Conformance/PvsConformanceTests.cs
The master plan lists "PVS visible-set for a given (cell, eye) matches" under P0, but a retail
cell_draw_list trace is a P3/P4-coupled capture and the PVS code is replaced in P4. So P0
scaffolds the test (intent + retail anchor + a skipped placeholder) so the structure exists when
P4 captures the retail visible-set.
- Step 1: Write the scaffold (skipped)
using Xunit;
namespace AcDream.Core.Tests.Conformance;
/// <summary>
/// PVS (portal-visibility) conformance — scaffold. Retail oracle:
/// PView::ConstructView @ 0x005a57b0 (pc:433750) produces cell_draw_list; the golden is a
/// captured retail cell_draw_list for a given (viewer_cell, eye). Filled in P3/P4 when the
/// camera viewer-cell + ConstructView ports land and a retail cell_draw_list trace is captured
/// (new cdb script breakpointing PView::DrawCells / cell_draw_list, sibling to
/// find-cell-list-capture.cdb). See docs/research/2026-06-02-retail-render-pipeline-full-reference.md §3.
/// </summary>
public class PvsConformanceTests
{
[Fact(Skip = "P0 scaffold — filled in P4 with a captured retail cell_draw_list trace")]
public void Pvs_CottageInterior_MatchesRetailCellDrawList() { }
}
- Step 2: Verify it builds + reports as skipped
Run: dotnet test ... --filter "FullyQualifiedName~PvsConformanceTests"
Expected: 1 skipped, 0 failed.
- Step 3: Commit
git add tests/AcDream.Core.Tests/Conformance/PvsConformanceTests.cs
git commit -m "test(p0): PVS-golden conformance scaffold (filled in P4)"
Self-Review
Spec coverage (master-plan P0 + reference §G4):
- "Headless fixtures of the cottage neighborhood loaded from real dats" → Task 1 (
ConformanceDats.LoadEnvCell) + Task 2 (characterize). - "
point_in_cellmatches" → Task 3 (geometric goldens vs real BSP). - "
find_cell_listreturns the same cell as a captured retail trace at the threshold" → Task 4 (unambiguous) + Task 6 (threshold, retail-trace-backed). - "the PVS visible-set ... matches" → Task 7 (scaffold; fill in P4, documented).
- "Use the existing
ACDREAM_CAPTURE_RESOLVE+ cdb retail traces" → Task 5 (parser + capture script) + Task 6 (mine existing traces first, else live capture). - "≥1 golden retail-trace assertion before P1" → Task 6 (the P1 gate).
Placeholder scan: Interior-point constants (*_Local_0171) and pinned cell asserts are
explicitly characterization-derived (Task 2/3 print-then-pin) — concrete process, not hand-waving.
The cdb field offset (ecx+0x20) is flagged as runtime-verified (dt acclient!CObjCell @ecx).
Type consistency: ConformanceDats.LoadEnvCell returns EnvCell; cache.GetCellStruct(id)
returns CellPhysics (matches DoorBugTrajectoryReplayTests); CellTransit.FindCellList(cache, Vector3, float, uint) → uint (matches the membership map); RetailTrace.ParseFindCellList(string) → RetailCellPick?. Consistent across Tasks 1/3/4/6.
Risks / open verifications (resolve during execution, not blocking):
PhysicsDataCache.CacheCellStruct+GetCellStruct+CellPhysics.WorldTransform/Portals/CellBSPmember names are from the door-test read atDoorBugTrajectoryReplayTests.cs:213-225; verify exact casing on first compile.- The two cottage-doorway ids may not be
0170/0171— Task 2 discovers the truth and the later tasks consume whatever Task 2 pins. - Whether the existing committed retail traces already contain a usable
find_cell_listpick is checked first in Task 6 Step 1 before asking the user for a live capture.