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:
Erik 2026-06-03 18:54:27 +02:00
parent db94cb1c90
commit 9017107960
7 changed files with 197 additions and 64 deletions

View file

@ -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)}");
}
}