fix(phys): #112 residual - retail straddle gate for outdoor-cell admission (live-binary verified)
The oracle read the #112 residual was waiting on, settled against the LIVE 2013 client (cdb attach, CEnvCell::find_transit_cells @ 0052c820; BN pseudo-C was ambiguous and partly wrong per feedback_bn_decomp_field_names - it invented portal_side tests in this branch): retail admits outdoor transit cells from an indoor cell IFF a path sphere STRADDLES an exterior portal polygon plane, |dist| < radius + F_EPSILON(0.000199999995, @ 007c8c70). The flag at [esp+18h] (set 0052c925, x87 decode fcompp/test ah,41h + fcomp/test ah,5/jp) gates the add_all_outside_cells call (0052c9d6 je). Graph reachability alone NEVER admits outdoor cells in retail. Port (CellTransit): - FindTransitCellsSphere: exitOutside now carries the retail straddle semantics; new hasExitPortal out carries the old topology-only flag. - BuildCellSetAndPickContaining: the collision cell SET keeps the A6.P5 topology widening on hasExitPortal (outdoor-registered doors must stay findable from indoor cells until #99/A6.P4 ships per-cell shadow lists - the 2026-05-25 door capture scenario), but the membership PICK's outdoor branch is gated on the retail flag. Membership is now retail-identical in both regimes: straddle -> outdoor candidates valid; no straddle -> outdoor ignored -> retail keep-curr. This is what stops deep-interior containment gaps in ANY house from demoting to outdoor (the #112 transparent-interior shape) - the systemic protection the user asked for, without house-by-house verification. The at-doorway A9B3 gap demote is RETAIL-FAITHFUL (gap point is 0.23m from 0x104s door plane < 0.48 foot radius -> retail straddles + demotes + self-heals inward): DocumentsResidual renamed to ...DemotesRetailFaithfully, expectation unchanged. New conformance pins: deep-gap keep-curr (A9B3Cottage_GapBeyondStraddleDistance_KeepsCurrCell) + function-level gate semantics on real dat geometry (FindTransitCellsSphere_ExitPortalStraddleGate_MatchesRetail). Tests: Core 1391 green (+2) / App 224 / UI 420 / Net 294; pre-existing 4 #99-era failures unchanged; P1 membership goldens + A6.P5 door-set tests explicitly green. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
parent
927fd8fde2
commit
414c3deaf4
3 changed files with 173 additions and 47 deletions
|
|
@ -1,3 +1,4 @@
|
|||
using System.Collections.Generic;
|
||||
using System.Numerics;
|
||||
using AcDream.Core.Physics;
|
||||
using DatReaderWriter;
|
||||
|
|
@ -37,7 +38,7 @@ public sealed class Issue112MembershipTests
|
|||
}
|
||||
|
||||
[Fact]
|
||||
public void A9B3CottageGap_IndoorSeed_DemotesViaOutdoorCandidates_DocumentsResidual()
|
||||
public void A9B3CottageGap_AtDoorway_StraddlesExitPlane_DemotesRetailFaithfully()
|
||||
{
|
||||
var datDir = ConformanceDats.ResolveDatDir();
|
||||
if (datDir is null) { _out.WriteLine("dats unavailable — skipped"); return; }
|
||||
|
|
@ -51,19 +52,73 @@ public sealed class Issue112MembershipTests
|
|||
uint picked = CellTransit.FindCellList(cache, gap, FootRadius, 0xA9B30104u);
|
||||
_out.WriteLine($"pick(seed 0x104) at gap -> 0x{picked:X8}");
|
||||
|
||||
// DOCUMENTS THE #112 RESIDUAL (flips loudly when fixed): the gap sits
|
||||
// in the doorway region, so the BFS from 0x104 reaches the exterior
|
||||
// portal and outdoor cells enter the candidate array → the NORMAL
|
||||
// outdoorResult path demotes (not the removed escape hatch — its
|
||||
// removal fixed the deep-room stranding; re-promotion now happens at
|
||||
// the doorway cells on the way back in). Open question for the fix:
|
||||
// retail's CEnvCell::find_transit_cells gate for add_all_outside_cells
|
||||
// (pc:317499 region) — if it requires sphere proximity to the exterior
|
||||
// portal POLYGON (not just graph reachability), this demote disappears
|
||||
// and the assert below should become Assert.Equal(0xA9B30104u, ...).
|
||||
// RESOLVED 2026-06-10 (#112 rider, live-binary oracle): retail's
|
||||
// CEnvCell::find_transit_cells admits outdoor cells IFF a path sphere
|
||||
// STRADDLES an exterior portal's plane (|dist| < radius + F_EPSILON;
|
||||
// acclient.exe 0052c8e5-0052c9f0). The gap point sits 0.23 m from
|
||||
// 0x104's exit-door plane (x=184.684) with foot radius 0.48 — it
|
||||
// STRADDLES, so retail admits the outdoor column and demotes here too.
|
||||
// This at-doorway demote is RETAIL-FAITHFUL, not a divergence; it
|
||||
// self-heals one step inward via doorway re-promotion. The former
|
||||
// "DocumentsResidual" framing is closed — see the deep-gap test below
|
||||
// for the behavior that DID change with the straddle gate.
|
||||
Assert.Equal(0xA9B3003Cu, picked);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void A9B3Cottage_GapBeyondStraddleDistance_KeepsCurrCell_RetailGate()
|
||||
{
|
||||
var datDir = ConformanceDats.ResolveDatDir();
|
||||
if (datDir is null) { _out.WriteLine("dats unavailable — skipped"); return; }
|
||||
using var dats = new DatCollection(datDir, DatAccessType.Read);
|
||||
var cache = LoadLandblockInteriors(dats, 0xA9B30000u);
|
||||
|
||||
// A no-cell point past the straddle window: 0.66 m beyond 0x104's
|
||||
// exit-door plane (x=184.684 + 0.48 + 0.18), still in no interior cell
|
||||
// (inside the shell-wall band). Pre-gate, the A6.P5 topology widening
|
||||
// let the outdoor column WIN the pick here → outdoor demote deep in a
|
||||
// containment gap (#112's transparent-interior shape). Retail keeps
|
||||
// curr_cell: no sphere straddles any exterior portal plane, so the
|
||||
// outdoor cells never become pick candidates (live-binary verified).
|
||||
var deepGap = new Vector3(185.345f, 82.464f, 116.48f);
|
||||
|
||||
uint picked = CellTransit.FindCellList(cache, deepGap, FootRadius, 0xA9B30104u);
|
||||
_out.WriteLine($"pick(seed 0x104) at deep gap -> 0x{picked:X8}");
|
||||
Assert.Equal(0xA9B30104u, picked);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void FindTransitCellsSphere_ExitPortalStraddleGate_MatchesRetail()
|
||||
{
|
||||
var datDir = ConformanceDats.ResolveDatDir();
|
||||
if (datDir is null) { _out.WriteLine("dats unavailable — skipped"); return; }
|
||||
using var dats = new DatCollection(datDir, DatAccessType.Read);
|
||||
var cache = LoadLandblockInteriors(dats, 0xA9B30000u);
|
||||
|
||||
// Cottage north room 0x102 has an exterior door at x=186 (portal poly
|
||||
// plane n=(±1,0,0), |d|=186 — dat dump 2026-06-10). Function-level pin
|
||||
// of the retail gate semantics on real dat geometry:
|
||||
var cell102 = cache.GetCellStruct(0xA9B30102u)!;
|
||||
|
||||
// (a) Deep inside the room, 3 m from the door plane: the cell HAS an
|
||||
// exterior portal (topology flag) but no straddle → no outdoor
|
||||
// admission flag (retail: var_44 stays 0, add_all_outside skipped).
|
||||
var farCandidates = new List<uint>();
|
||||
CellTransit.FindTransitCellsSphere(
|
||||
cache, cell102, 0xA9B30102u, new Vector3(183.0f, 86.5f, 117.0f),
|
||||
FootRadius, farCandidates, out bool farStraddle, out bool farHasExit);
|
||||
Assert.True(farHasExit);
|
||||
Assert.False(farStraddle);
|
||||
|
||||
// (b) At the door plane (0.30 m away < 0.48 radius): straddle fires.
|
||||
var nearCandidates = new List<uint>();
|
||||
CellTransit.FindTransitCellsSphere(
|
||||
cache, cell102, 0xA9B30102u, new Vector3(185.70f, 85.5f, 117.0f),
|
||||
FootRadius, nearCandidates, out bool nearStraddle, out bool nearHasExit);
|
||||
Assert.True(nearHasExit);
|
||||
Assert.True(nearStraddle);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ThresholdCottage_AdjacentClaim_LaterallyRecovers_ViaStabGraph()
|
||||
{
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue