From 1662da8731cac12196871ab83a6c703c45d9d2d6 Mon Sep 17 00:00:00 2001 From: Erik Date: Wed, 3 Jun 2026 14:29:30 +0200 Subject: [PATCH] test(p0): threshold-trace golden wiring + PVS scaffold + P1-entry checklist P0 Tasks 6 (autonomous half) + 7. FindCellList_DoorwayThreshold_MatchesRetailTrace asserts acdream's pick == each captured retail pick; skips until the capture fixture lands. PvsConformanceTests scaffolds the render visible-set golden (skipped; filled in P4). ConformanceDats.FixturesDir resolves fixtures from the source tree (issue98 pattern). Notes record: existing retail traces are collision-only (no membership) so the strict P1 gate needs the one live capture; plus the P1 re-scope finding (Stage-1 membership already on this branch). Co-Authored-By: Claude Opus 4.8 (1M context) --- ...26-06-03-p0-conformance-apparatus-notes.md | 38 +++++++++++++++++-- .../Conformance/ConformanceDats.cs | 21 ++++++++++ .../FindCellListConformanceTests.cs | 29 ++++++++++++++ .../Conformance/Fixtures/README.md | 11 ++++++ .../Conformance/PvsConformanceTests.cs | 24 ++++++++++++ 5 files changed, 120 insertions(+), 3 deletions(-) create mode 100644 tests/AcDream.Core.Tests/Conformance/Fixtures/README.md create mode 100644 tests/AcDream.Core.Tests/Conformance/PvsConformanceTests.cs diff --git a/docs/research/2026-06-03-p0-conformance-apparatus-notes.md b/docs/research/2026-06-03-p0-conformance-apparatus-notes.md index 83a8972..9bd744f 100644 --- a/docs/research/2026-06-03-p0-conformance-apparatus-notes.md +++ b/docs/research/2026-06-03-p0-conformance-apparatus-notes.md @@ -64,7 +64,39 @@ retail loads, so a geometrically-correct containment answer is the retail answer | `find_cell_list` doorway-threshold pick | **retail cdb trace** | Task 6 — USER GATE / mine existing traces | | PVS visible-set | retail cdb `cell_draw_list` trace | deferred to P4 (Task 7 scaffold) | -## P1-entry checklist (filled at end of P0) +## Existing retail traces — mined, NOT usable for membership -- [ ] Threshold golden GREEN (acdream already matches retail) or RED (P1 must fix) — recorded here. -- [ ] "P0 gate met: ≥1 retail-trace-backed assertion exists" — stated explicitly so P1 can begin. +`docs/research/2026-05-21-a6-captures/*/retail.log` + `retail.decoded.log` were grepped for +`change_cell` / `curr_cell` / `find_cell_list` / `cell=0x` / `insert_into_cell`. **Zero matches in +any retail log** — all 15,492 membership/cell-id matches are in the paired `acdream.log` files +(our own probe output). The committed retail traces are collision-only (`find_collisions` +hit-counters, `set_neg_poly_hit`, etc.); they carry no membership cell-id or position. So the +retail-trace-backed threshold golden **cannot** be built from existing data — a live capture is +required (`tools/cdb/find-cell-list-capture.cdb`). + +## P0 status / P1-entry checklist + +**Autonomous apparatus: COMPLETE + GREEN.** (Conformance suite 58 pass / 1 skip / 0 fail.) +- ✅ Dat-backed fixture loader (`ConformanceDats`). +- ✅ Characterized + pinned cottage-doorway topology (`0031↔0170↔0171` verified real). +- ✅ `point_in_cell` goldens vs real dat BSP. +- ✅ `find_cell_list` unambiguous goldens (interior picks + stale-seed re-pick stability). +- ✅ Retail-trace parser (`RetailTrace`, 4 tests) + cdb capture script + README. +- ✅ PVS-golden scaffold (skipped; filled in P4). +- ⏳ `FindCellList_DoorwayThreshold_MatchesRetailTrace` — wired, **skips until the capture fixture + `Conformance/Fixtures/find-cell-list-threshold.log` exists**. + +**P0 gate for P1 (`≥1 retail-trace-backed assertion`): PENDING the one user-gated capture.** +The existing traces don't satisfy it (collision-only). To meet the strict gate, run +`tools/cdb/find-cell-list-capture.cdb` against live retail at the cottage doorway (its README is +the runbook), decode, drop the log at the fixture path, and re-run the threshold test: +- GREEN → acdream already matches retail at the threshold; P1's membership port preserves it. +- RED → the P1 divergence, captured as a documents-the-bug conformance test (do not weaken). + +**Re-scope note for P1 (discovered during P0):** this branch already carries the membership +"Stage 1" work the master plan's §2 "acdream now" column lists as partial — `CellArray` (ordered +CELLARRAY / R1 flap fix), `FindCellSet`'s interior-wins pick (cites pc:308788-308825), +`RunCheckOtherCellsAndAdvance` (collide-then-pick), swept `sp.CurCellId` return, player-only +`UpdatePlayerCurrCell`. P1's REAL remaining scope is narrower: intrinsic building entry (delete +`CheckBuildingTransit`) + uniform `find_env_collisions` (delete the `cellLow >= 0x0100` fork) + +demote `ResolveCellId` to seed-only. Re-confirm against the code when P1 starts. diff --git a/tests/AcDream.Core.Tests/Conformance/ConformanceDats.cs b/tests/AcDream.Core.Tests/Conformance/ConformanceDats.cs index 1c056c1..197f937 100644 --- a/tests/AcDream.Core.Tests/Conformance/ConformanceDats.cs +++ b/tests/AcDream.Core.Tests/Conformance/ConformanceDats.cs @@ -40,6 +40,27 @@ public static class ConformanceDats return Directory.Exists(def) ? def : null; } + /// + /// The conformance fixtures dir in the SOURCE tree (mirrors + /// CellarUpTrajectoryReplayTests.FixtureDir — fixtures are read from source, + /// not copied to the output dir). + /// + public static string FixturesDir => + Path.Combine(SolutionRoot(), "tests", "AcDream.Core.Tests", "Conformance", "Fixtures"); + + private static string SolutionRoot() + { + var dir = AppContext.BaseDirectory; + while (!string.IsNullOrEmpty(dir)) + { + if (File.Exists(Path.Combine(dir, "AcDream.slnx"))) + return dir; + dir = Path.GetDirectoryName(dir); + } + throw new InvalidOperationException( + "Could not locate AcDream.slnx from " + AppContext.BaseDirectory); + } + /// The physics-verbatim cell→world transform (no +2cm render lift). public static Matrix4x4 WorldTransform(DatEnvCell datCell) => Matrix4x4.CreateFromQuaternion(datCell.Position.Orientation) * diff --git a/tests/AcDream.Core.Tests/Conformance/FindCellListConformanceTests.cs b/tests/AcDream.Core.Tests/Conformance/FindCellListConformanceTests.cs index 8d09c0c..e14add6 100644 --- a/tests/AcDream.Core.Tests/Conformance/FindCellListConformanceTests.cs +++ b/tests/AcDream.Core.Tests/Conformance/FindCellListConformanceTests.cs @@ -84,4 +84,33 @@ public class FindCellListConformanceTests CottageDoorwayCharacterizationTests.Room0171); // stale/wrong seed Assert.Equal(CottageDoorwayCharacterizationTests.Vestibule0170, picked); } + + /// + /// THE retail-trace-backed golden (P0 gate for P1). For each captured retail + /// find_cell_list pick at the doorway threshold, assert acdream's FindCellList + /// returns the SAME cell for the SAME (seed, position). Skips until the capture + /// fixture exists (see tools/cdb/find-cell-list-capture.cdb). If it FAILS once + /// the fixture is in place, that is the P1 divergence — leave it RED, do NOT + /// weaken the assertion (master plan §4). + /// + [Fact] + public void FindCellList_DoorwayThreshold_MatchesRetailTrace() + { + var datDir = ConformanceDats.ResolveDatDir(); + if (datDir is null) return; + var fixturePath = System.IO.Path.Combine(ConformanceDats.FixturesDir, "find-cell-list-threshold.log"); + if (!System.IO.File.Exists(fixturePath)) return; // gate not yet satisfied — capture pending + + using var dats = new DatCollection(datDir, DatAccessType.Read); + var cache = LoadThresholdBuilding(dats); + + var picks = RetailTrace.ParseAll(System.IO.File.ReadAllLines(fixturePath)); + Assert.NotEmpty(picks); // a present-but-unparseable fixture is itself a failure + + foreach (var pick in picks) + { + uint ours = CellTransit.FindCellList(cache, pick.Position, FootRadius, pick.SeedCellId); + Assert.Equal(pick.PickedCellId, ours); + } + } } diff --git a/tests/AcDream.Core.Tests/Conformance/Fixtures/README.md b/tests/AcDream.Core.Tests/Conformance/Fixtures/README.md new file mode 100644 index 0000000..3afeca8 --- /dev/null +++ b/tests/AcDream.Core.Tests/Conformance/Fixtures/README.md @@ -0,0 +1,11 @@ +# Conformance fixtures + +Captured retail golden data for the P0 conformance tests. + +- `find-cell-list-threshold.log` — **pending capture.** Retail `find_cell_list` picks at the + Holtburg cottage doorway, in the `[fcl] seed=0x.. px=.. py=.. pz=.. picked=0x..` format read by + `RetailTrace.ParseFindCellList`. Produced by `tools/cdb/find-cell-list-capture.cdb` (see its + README). Until it lands, `FindCellList_DoorwayThreshold_MatchesRetailTrace` skips. + +Fixtures are read from this SOURCE directory (via `ConformanceDats.FixturesDir`), not copied to +the build output — matching the existing `Fixtures/issue98/**` pattern. diff --git a/tests/AcDream.Core.Tests/Conformance/PvsConformanceTests.cs b/tests/AcDream.Core.Tests/Conformance/PvsConformanceTests.cs new file mode 100644 index 0000000..a11718e --- /dev/null +++ b/tests/AcDream.Core.Tests/Conformance/PvsConformanceTests.cs @@ -0,0 +1,24 @@ +using Xunit; + +namespace AcDream.Core.Tests.Conformance; + +/// +/// PVS (portal-visibility) conformance — P0 scaffold. The render visible-set +/// golden. Retail oracle: PView::ConstructView(CEnvCell*) @ 0x005a57b0 +/// (pc:433750) produces the ordered cell_draw_list for a given (viewer_cell, +/// eye); see docs/research/2026-06-02-retail-render-pipeline-full-reference.md §3. +/// +/// FILLED IN P4, not P0: a retail cell_draw_list trace is a P3/P4-coupled +/// capture (a new cdb script breakpointing PView::DrawCells / cell_draw_list, +/// sibling to find-cell-list-capture.cdb), and the PVS code itself +/// (PortalVisibilityBuilder) is REPLACED by the ConstructView port in P4. The +/// scaffold exists now so the structure + retail anchor are in place; P4 adds +/// the capture + the golden assertion (PVS root id == physics CurrCell.Id; +/// a cell seen through two portals appears once per slice; dungeon +/// outside_view==0). +/// +public class PvsConformanceTests +{ + [Fact(Skip = "P0 scaffold — filled in P4 with a captured retail cell_draw_list trace")] + public void Pvs_CottageInterior_MatchesRetailCellDrawList() { } +}