# 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`), 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` → `Get` → `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** ```csharp 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; /// /// 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 . Returns /// null dat dir when the dats are absent (CI) so callers can skip cleanly, /// matching DoorBugTrajectoryReplayTests.ResolveDatDir. /// public static class ConformanceDats { private const uint EnvironmentFilePrefix = 0x0D000000u; // dat namespace for Environment files /// The Holtburg landblock these fixtures live in. public const uint HoltburgLandblock = 0xA9B40000u; /// Resolve the client dat directory, or null if unavailable (skip the test). 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; } /// The physics-verbatim cell→world transform (no +2cm render lift). public static Matrix4x4 WorldTransform(DatEnvCell datCell) => Matrix4x4.CreateFromQuaternion(datCell.Position.Orientation) * Matrix4x4.CreateTranslation(datCell.Position.Origin); /// /// Load one EnvCell from the dats with its REAL containment BSP, and register /// it into as a CellPhysics. Returns the high-level /// EnvCell (PointInCell) so a single load serves both membership predicates. /// public static EnvCell LoadEnvCell(DatCollection dats, PhysicsDataCache cache, uint cellId) { var datCell = dats.Get(cellId) ?? throw new InvalidOperationException($"EnvCell 0x{cellId:X8} not found in dats"); var environment = dats.Get(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** ```bash 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)** ```csharp 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..0xA9B40179` in the loop, re-run, and identify the two cells whose `worldOrigin` > matches the cottage (low Y, near the `014x` cellar) and that form a portal pair (one's > `portalDests` contains 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): ```csharp [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** ```bash 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** ```csharp 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** ```bash 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** ```csharp 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** ```bash 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= py= pz= picked=0xHHHHHHHH`. - [ ] **Step 1: Write the failing parser test** ```csharp 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** ```csharp using System; using System.Globalization; using System.Numerics; using System.Text.RegularExpressions; namespace AcDream.Core.Tests.Conformance; /// A single retail find_cell_list pick captured via cdb (golden oracle). public sealed record RetailCellPick(uint SeedCellId, Vector3 Position, uint PickedCellId); /// Parser for the find-cell-list-capture.cdb log format. public static class RetailTrace { private static readonly Regex Fcl = new( @"^\[fcl\]\s+seed=0x(?[0-9A-Fa-f]{1,8})\s+" + @"px=(?-?\d+(\.\d+)?)\s+py=(?-?\d+(\.\d+)?)\s+pz=(?-?\d+(\.\d+)?)\s+" + @"picked=0x(?[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** ```bash 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)`: ```csharp [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 `` 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** ```bash 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)** ```csharp using Xunit; namespace AcDream.Core.Tests.Conformance; /// /// 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. /// 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** ```bash 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_cell` matches" → Task 3 (geometric goldens vs real BSP). - "`find_cell_list` returns 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/CellBSP` member names are from the door-test read at `DoorBugTrajectoryReplayTests.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_list` pick is checked first in Task 6 Step 1 before asking the user for a live capture.