fix(p1): membership already matches retail — the 0/11 was a cdb capture artifact
The P1 "doorway membership lags retail" premise is FALSIFIED. acdream's swept ResolveWithTransition already matches retail's true per-frame curr_cell: the production gate ProductionPath_IndoorCrossings reads 9/9 on the indoor 0170<->0171 crossings with NO code change, once fed an aligned retail golden. Root cause of the false 0/11: CPhysicsObj::SetPositionInternal calls change_cell (acclient_2013_pseudo_c.txt:283456) BEFORE set_frame writes m_position (:283458), so the original golden (find-cell-list-capture.cdb, read at the change_cell BP) paired each frame's NEW cell with the PREVIOUS frame's position — a one-frame skew. Verified 3 ways: the decomp ordering; golden_picked[i] == geom(golden_position[i+1]) for all 22 rows; acdream's static pick == golden_picked[i-1] for all rows. Both retail and acdream pick with center-only point_in_cell on global_sphere[0] (no XY lead; cache_global_sphere @ pc:274196). curr_cell commits via validate_transition (@ pc:272608, curr_cell = check_cell) = the find_cell_list pick, structurally identical to acdream's RunCheckOtherCellsAndAdvance -> FindCellSet -> SetCheckPos. There was nothing to port; a swept advance would make membership LEAD by a frame. - tools/cdb/find-cell-list-capture-aligned.cdb: re-capture reads the committed position from the set_frame that follows change_cell (cell+position same instant). - Fixtures/find-cell-list-threshold.log: replaced with the aligned capture. - ThresholdPortalCrossingReplayTests / FindCellListConformanceTests: rewritten from documents-the-bug to assert retail truth (per-segment / per-indoor-pick equality). - handoff + notes + README + memory: banners correcting the disproven premise. Still open (NOT indoor membership, which is DONE): outdoor->indoor 0031<->0170 entry conformance (needs landcell + building stab in the gate cache); master-plan cleanups (delete CheckBuildingTransit, unify find_env_collisions, demote ResolveCellId) refactor working retail-faithful code -> need explicit user approval. Conformance 60 pass / 1 skip / 0 fail; full Core 1309 pass / 5 fail (pre-existing 2 BSPStepUp + 3 door-collision = P2) / 1 skip. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
db94cb1c90
commit
9017107960
7 changed files with 197 additions and 64 deletions
|
|
@ -106,37 +106,41 @@ public class FindCellListConformanceTests
|
|||
}
|
||||
|
||||
/// <summary>
|
||||
/// THE retail-trace-backed golden (the P0 gate for P1). Documents-the-bug form:
|
||||
/// it PASSES while acdream diverges and FAILS when P1's membership port lands
|
||||
/// (prompting its rewrite to assert the full sequence). The retail truth is the
|
||||
/// committed golden fixture; do NOT weaken it (master plan §4).
|
||||
/// Retail-trace-backed conformance for the INDOOR (0170↔0171) membership picks: for every
|
||||
/// captured pick whose seed AND committed cell are interior, acdream's center-only
|
||||
/// <c>point_in_cell</c> <see cref="CellTransit.FindCellList"/> returns retail's committed cell.
|
||||
///
|
||||
/// ROOT CAUSE (P0 finding, 2026-06-03, live retail capture + the per-transition
|
||||
/// containment diagnostic in ThresholdDivergenceDiagnosticTests): retail
|
||||
/// transitions membership at the PORTAL CROSSING (CEnvCell::find_transit_cells —
|
||||
/// the sphere crosses the doorway polygon plane), while acdream's FindCellList
|
||||
/// re-picks by POINT-IN-CELL containment at the foot. So retail commits the
|
||||
/// neighbour cell BEFORE the foot point is geometrically inside it (it enters
|
||||
/// room 0171 while the foot is still inside vestibule 0170's BSP, in_0171=0), and
|
||||
/// acdream lags. ALL 22 captured transitions diverge for this one reason — it is
|
||||
/// NOT a per-cell hysteresis or a building-entry-only split. P1 (port
|
||||
/// find_transit_cells' directed portal crossing; master plan A2, plus intrinsic
|
||||
/// building entry A3) makes them match.
|
||||
/// HISTORY (2026-06-03): with the FIRST capture (find-cell-list-capture.cdb) this read
|
||||
/// all-diverge and was believed to prove a "membership lags retail" bug needing a
|
||||
/// find_transit_cells portal-crossing / swept curr_cell-advance port. That was a CAPTURE
|
||||
/// ARTIFACT, not a real divergence: <c>CPhysicsObj::SetPositionInternal</c> calls
|
||||
/// <c>change_cell</c> (acclient_2013_pseudo_c.txt:283456) BEFORE <c>set_frame</c> updates
|
||||
/// <c>m_position</c> (:283458), so the golden paired THIS frame's new cell with the PREVIOUS
|
||||
/// frame's position (golden_picked[i] == geom(position[i+1])). The aligned re-capture
|
||||
/// (tools/cdb/find-cell-list-capture-aligned.cdb) removes the skew, and acdream matches retail
|
||||
/// on every indoor pick — acdream's pick already IS retail's true per-frame membership
|
||||
/// (both use center-only point_in_cell on global_sphere[0]; the foot sphere does not lead the
|
||||
/// foot). See docs/research/2026-06-03-p1-membership-swept-advance-handoff.md.
|
||||
///
|
||||
/// Outdoor-involving (0031↔0170) picks are NOT asserted here: the building-only cache cannot
|
||||
/// promote an outdoor seed into the interior (no landcell/building stab loaded) — that is the
|
||||
/// separate outdoor-entry validation.
|
||||
/// </summary>
|
||||
[Fact]
|
||||
public void FindCellList_DoorwayThreshold_DivergesFromRetail_PendingP1()
|
||||
public void FindCellList_DoorwayThreshold_IndoorPicks_MatchRetail()
|
||||
{
|
||||
var (cache, picks) = LoadThresholdGolden();
|
||||
if (cache is null) return;
|
||||
Assert.NotEmpty(picks!);
|
||||
|
||||
int matches = picks!.Count(p =>
|
||||
CellTransit.FindCellList(cache, p.Position, FootRadius, p.SeedCellId) == p.PickedCellId);
|
||||
var indoor = picks!.Where(p =>
|
||||
(p.SeedCellId & 0xFFFFu) >= 0x100u && (p.PickedCellId & 0xFFFFu) >= 0x100u).ToList();
|
||||
Assert.NotEmpty(indoor);
|
||||
|
||||
Assert.True(matches < picks.Count,
|
||||
$"acdream now reproduces {matches}/{picks.Count} retail doorway transitions. " +
|
||||
"If this == Total, P1's membership port (find_transit_cells portal crossing) " +
|
||||
"landed -> rewrite this test to Assert.Equal(pick.PickedCellId, FindCellList(...)) " +
|
||||
"for every captured pick. The retail truth is in the golden fixture.");
|
||||
foreach (var p in indoor)
|
||||
{
|
||||
uint got = CellTransit.FindCellList(cache, p.Position, FootRadius, p.SeedCellId);
|
||||
Assert.Equal(p.PickedCellId, got);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,10 +2,22 @@
|
|||
|
||||
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.
|
||||
- `find-cell-list-threshold.log` — retail `find_cell_list` picks at the Holtburg "Agent of
|
||||
Arcanum" doorway (the `0031↔0170↔0171` building), in the
|
||||
`[fcl] seed=0x.. px=.. py=.. pz=.. picked=0x..` format read by `RetailTrace.ParseFindCellList`.
|
||||
**Captured ALIGNED** by `tools/cdb/find-cell-list-capture-aligned.cdb`: each row's position is
|
||||
the COMMITTED position read from the `set_frame` call that follows `change_cell`, so cell and
|
||||
position are from the same instant.
|
||||
|
||||
History (2026-06-03): the first capture (`tools/cdb/find-cell-list-capture.cdb`) read position
|
||||
from `m_position` AT the `change_cell` breakpoint — but `SetPositionInternal` calls `change_cell`
|
||||
(`acclient_2013_pseudo_c.txt:283456`) BEFORE `set_frame` writes `m_position` (`:283458`), so each
|
||||
row paired THIS frame's new cell with the PREVIOUS frame's position (a one-frame skew,
|
||||
`picked[i] == geom(position[i+1])`). That skew made the conformance read 0/11 and was
|
||||
briefly misdiagnosed as a "membership lags retail" bug. The aligned golden removes the skew;
|
||||
acdream's center-only `point_in_cell` pick matches retail 9/9 on the indoor crossings with **no
|
||||
code change** — acdream's membership already IS retail's true per-frame behaviour. See
|
||||
`docs/research/2026-06-03-p1-membership-swept-advance-handoff.md`.
|
||||
|
||||
Fixtures are read from this SOURCE directory (via `ConformanceDats.FixturesDir`), not copied to
|
||||
the build output — matching the existing `Fixtures/issue98/**` pattern.
|
||||
|
|
|
|||
|
|
@ -1,22 +1,19 @@
|
|||
[fcl] seed=0xA9B40031 px=155.4350 py=16.1483 pz=94.0050 picked=0xA9B40170
|
||||
[fcl] seed=0xA9B40170 px=155.4210 py=15.4818 pz=94.0050 picked=0xA9B40171
|
||||
[fcl] seed=0xA9B40171 px=155.4130 py=15.1004 pz=94.0050 picked=0xA9B40170
|
||||
[fcl] seed=0xA9B40170 px=155.4302 py=15.9169 pz=94.0050 picked=0xA9B40031
|
||||
[fcl] seed=0xA9B40031 px=155.4360 py=16.1878 pz=94.0050 picked=0xA9B40170
|
||||
[fcl] seed=0xA9B40170 px=155.4192 py=15.3880 pz=94.0050 picked=0xA9B40171
|
||||
[fcl] seed=0xA9B40171 px=155.4126 py=15.0677 pz=94.0050 picked=0xA9B40170
|
||||
[fcl] seed=0xA9B40170 px=155.4298 py=15.8842 pz=94.0050 picked=0xA9B40031
|
||||
[fcl] seed=0xA9B40031 px=155.4341 py=16.0885 pz=94.0050 picked=0xA9B40170
|
||||
[fcl] seed=0xA9B40170 px=155.4173 py=15.2887 pz=94.0050 picked=0xA9B40171
|
||||
[fcl] seed=0xA9B40171 px=155.4139 py=15.1239 pz=94.0050 picked=0xA9B40170
|
||||
[fcl] seed=0xA9B40170 px=155.4311 py=15.9404 pz=94.0050 picked=0xA9B40031
|
||||
[fcl] seed=0xA9B40031 px=155.4369 py=16.2114 pz=94.0050 picked=0xA9B40170
|
||||
[fcl] seed=0xA9B40170 px=155.4201 py=15.4115 pz=94.0050 picked=0xA9B40171
|
||||
[fcl] seed=0xA9B40171 px=155.4139 py=15.1135 pz=94.0050 picked=0xA9B40170
|
||||
[fcl] seed=0xA9B40170 px=155.4311 py=15.9299 pz=94.0050 picked=0xA9B40031
|
||||
[fcl] seed=0xA9B40031 px=155.4388 py=16.2898 pz=94.0050 picked=0xA9B40170
|
||||
[fcl] seed=0xA9B40170 px=155.4219 py=15.4899 pz=94.0050 picked=0xA9B40171
|
||||
[fcl] seed=0xA9B40171 px=155.4135 py=15.0863 pz=94.0050 picked=0xA9B40170
|
||||
[fcl] seed=0xA9B40170 px=155.4340 py=16.0583 pz=94.0050 picked=0xA9B40031
|
||||
[fcl] seed=0xA9B40031 px=155.4365 py=16.1738 pz=94.0050 picked=0xA9B40170
|
||||
[fcl] seed=0xA9B40170 px=155.4196 py=15.3739 pz=94.0050 picked=0xA9B40171
|
||||
[fcl] seed=0xA9B40031 px=155.3717 py=16.0283 pz=94.0050 picked=0xA9B40170
|
||||
[fcl] seed=0xA9B40170 px=155.3438 py=15.1343 pz=94.0050 picked=0xA9B40171
|
||||
[fcl] seed=0xA9B40171 px=155.3463 py=15.2186 pz=94.0050 picked=0xA9B40170
|
||||
[fcl] seed=0xA9B40170 px=155.3742 py=16.1126 pz=94.0050 picked=0xA9B40031
|
||||
[fcl] seed=0xA9B40031 px=155.3723 py=16.0516 pz=94.0050 picked=0xA9B40170
|
||||
[fcl] seed=0xA9B40170 px=155.3431 py=15.1187 pz=94.0050 picked=0xA9B40171
|
||||
[fcl] seed=0xA9B40171 px=155.3445 py=15.1641 pz=94.0050 picked=0xA9B40170
|
||||
[fcl] seed=0xA9B40170 px=155.3748 py=16.1358 pz=94.0050 picked=0xA9B40031
|
||||
[fcl] seed=0xA9B40031 px=155.3692 py=15.9583 pz=94.0050 picked=0xA9B40170
|
||||
[fcl] seed=0xA9B40170 px=155.3437 py=15.1420 pz=94.0050 picked=0xA9B40171
|
||||
[fcl] seed=0xA9B40171 px=155.3451 py=15.1874 pz=94.0050 picked=0xA9B40170
|
||||
[fcl] seed=0xA9B40170 px=155.3730 py=16.0814 pz=94.0050 picked=0xA9B40031
|
||||
[fcl] seed=0xA9B40031 px=155.3721 py=16.0571 pz=94.0050 picked=0xA9B40170
|
||||
[fcl] seed=0xA9B40170 px=155.3418 py=15.0854 pz=94.0050 picked=0xA9B40171
|
||||
[fcl] seed=0xA9B40171 px=155.3456 py=15.2085 pz=94.0050 picked=0xA9B40170
|
||||
[fcl] seed=0xA9B40170 px=155.3735 py=16.1025 pz=94.0050 picked=0xA9B40031
|
||||
[fcl] seed=0xA9B40170 px=155.3435 py=15.1454 pz=94.0050 picked=0xA9B40171
|
||||
[fcl] seed=0xA9B40171 px=155.3461 py=15.2296 pz=94.0050 picked=0xA9B40170
|
||||
[fcl] seed=0xA9B40170 px=155.3740 py=16.1236 pz=94.0050 picked=0xA9B40031
|
||||
|
|
|
|||
|
|
@ -78,18 +78,33 @@ public class ThresholdPortalCrossingReplayTests
|
|||
private static uint Low(uint id) => id & 0xFFFFu;
|
||||
|
||||
/// <summary>
|
||||
/// Documents-the-bug (GREEN while acdream diverges; FAILS when P1 lands → rewrite to
|
||||
/// per-segment Assert.Equal). The swept production path DIVERGES from retail on the
|
||||
/// indoor doorway crossings: <c>ResolveWithTransition</c> completes the move
|
||||
/// (<c>restPos == target</c>) but leaves <c>CellId</c> on the SOURCE cell — it never
|
||||
/// advances <c>curr_cell</c> across the portal the way retail's <c>change_cell</c> golden
|
||||
/// does. So the P0 finding is NOT a probe artifact: production membership genuinely lags.
|
||||
/// P1 must port retail's swept-crossing <c>curr_cell</c> advance (how the sphere crossing
|
||||
/// the doorway polygon / the leading sphere point promotes the neighbour to the membership
|
||||
/// answer mid-sweep), then this flips to all-match.
|
||||
/// P1 conformance gate. Replays the captured retail doorway golden's INDOOR
|
||||
/// (<c>0170↔0171</c>) crossings through the REAL
|
||||
/// <see cref="PhysicsEngine.ResolveWithTransition"/> and asserts acdream's swept
|
||||
/// <c>CellId</c> equals retail's committed cell on every crossing.
|
||||
///
|
||||
/// HISTORY (2026-06-03). With the FIRST capture (find-cell-list-capture.cdb) this read
|
||||
/// 0/11 and was believed to prove a "membership lags retail" bug needing a swept
|
||||
/// <c>curr_cell</c>-advance port. That was a CAPTURE ARTIFACT, not a real divergence:
|
||||
/// <c>CPhysicsObj::SetPositionInternal</c> calls <c>change_cell</c>
|
||||
/// (acclient_2013_pseudo_c.txt:283456) BEFORE <c>set_frame</c> updates <c>m_position</c>
|
||||
/// (:283458), so the cdb golden paired THIS frame's new cell with the PREVIOUS frame's
|
||||
/// position — a deterministic one-frame skew (golden_picked[i] == geom(position[i+1])).
|
||||
/// Re-capturing with the committed position read from the following <c>set_frame</c>
|
||||
/// (tools/cdb/find-cell-list-capture-aligned.cdb) makes cell+position align at the same
|
||||
/// instant, and acdream then matches retail 9/9 with NO code change: acdream's center-only
|
||||
/// <c>point_in_cell</c> pick at the swept rest position IS retail's true per-frame
|
||||
/// membership. Both pick with center-only <c>point_in_cell</c> on <c>global_sphere[0]</c>
|
||||
/// (find_cell_list @ pc:308788-308825); the foot sphere does not lead the foot in XY
|
||||
/// (cache_global_sphere @ pc:274196). See
|
||||
/// docs/research/2026-06-03-p1-membership-swept-advance-handoff.md.
|
||||
///
|
||||
/// Scope = INDOOR segments (the building-cell cache models these fully). The
|
||||
/// outdoor-involving <c>0031↔0170</c> segments need the landcell + building stab loaded
|
||||
/// (separate fixture work — verifies the outdoor→indoor entry path).
|
||||
/// </summary>
|
||||
[Fact]
|
||||
public void ProductionPath_IndoorCrossings_DivergeFromRetail_PendingP1()
|
||||
public void ProductionPath_IndoorCrossings_MatchRetail()
|
||||
{
|
||||
var datDir = ConformanceDats.ResolveDatDir();
|
||||
if (datDir is null) { _out.WriteLine("SKIP: dats unavailable"); return; }
|
||||
|
|
@ -101,6 +116,7 @@ public class ThresholdPortalCrossingReplayTests
|
|||
var picks = RetailTrace.ParseAll(File.ReadAllLines(fixturePath));
|
||||
|
||||
int match = 0, total = 0;
|
||||
var failures = new System.Collections.Generic.List<string>();
|
||||
for (int i = 0; i + 1 < picks.Count; i++)
|
||||
{
|
||||
uint fromCell = picks[i].PickedCellId;
|
||||
|
|
@ -123,6 +139,8 @@ public class ThresholdPortalCrossingReplayTests
|
|||
|
||||
bool ok = result.CellId == toCell;
|
||||
if (ok) match++;
|
||||
else failures.Add(System.FormattableString.Invariant(
|
||||
$"0x{Low(fromCell):X4}->0x{Low(toCell):X4}@({picks[i + 1].Position.X:F2},{picks[i + 1].Position.Y:F2}): acdream=0x{Low(result.CellId):X4}"));
|
||||
total++;
|
||||
_out.WriteLine(
|
||||
$"seg 0x{Low(fromCell):X4}->0x{Low(toCell):X4} " +
|
||||
|
|
@ -133,9 +151,8 @@ public class ThresholdPortalCrossingReplayTests
|
|||
_out.WriteLine($"=== production-path indoor crossings: {match}/{total} match retail ===");
|
||||
|
||||
Assert.True(total > 0, "no indoor doorway segments found in the golden");
|
||||
Assert.True(match < total,
|
||||
$"acdream's swept ResolveWithTransition now reproduces {match}/{total} retail indoor " +
|
||||
"doorway crossings. If match == total, P1's curr_cell swept-advance port landed -> " +
|
||||
"rewrite this to Assert.Equal(toCell, result.CellId) per segment. (Retail truth = the golden.)");
|
||||
Assert.True(failures.Count == 0,
|
||||
$"acdream's swept membership diverged on {failures.Count}/{total} indoor doorway " +
|
||||
$"crossings (retail truth = the aligned golden): {string.Join("; ", failures)}");
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue