fix(render): DynamicLast admits only the walk''s own root flood

The [dyn-route] trace pinned the through-wall remote player (visible
from 0xF4180101 AND outdoors while parented at 0xF4180112 - a cell
with no retail sightline chain from either): the legacy visibility
builder invents cross-building cell views at the cathedral (REAL
3-5-plane cones for 0x112, not the zero-plane trapdoor), the viewcone
admits his sphere, and he rides the last dynamics pass - post-clear on
interior roots (walls'' depth wiped) and post-world outdoors.

The stage-set split (synthesis plan step 4): an interior-parented
dynamic may ride DynamicLast ONLY when its parent cell is in THE
WALK''S OWN ROOT FLOOD (oracle-trace-conformant; retail draws look-in
occupants inside the landscape stage through the composed portal
chain, and unreachable cells'' occupants not at all). The frame
product''s build input gains RootFloodCells (the driver''s
InteriorFloodCells as a per-frame set); non-walk/diagnostic frames and
the comparison wrapper keep the legacy drawableCells meaning. The
[dyn-route] probe logs the new rootflood-excluded state.

Hermetic 6,762/0; InstalledDat walk conformance 40/1.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
Erik 2026-08-30 22:13:48 +02:00
parent 4686a1ac74
commit fc2e6b79bc
3 changed files with 61 additions and 7 deletions

View file

@ -71,6 +71,10 @@ public sealed class RetailPViewRenderer
private readonly HashSet<uint> _cellParticleOwnerScratch = new();
private readonly HashSet<uint> _dynamicParticleOwnerScratch = new();
// The walk's TRUE root flood as a set, rebuilt per frame for the
// DynamicLast stage gate (the stage-set split — synthesis plan step 4).
private readonly HashSet<uint> _rootFloodSetScratch = new();
// MP-Alloc (2026-07-05): the frame's entity partition (ByCell/OutdoorStatic/
// Dynamics), reused across frames instead of `new`ing a Result (a Dictionary
// + 2 Lists, plus one List<WorldEntity> per visible cell) every DrawInside
@ -507,6 +511,16 @@ public sealed class RetailPViewRenderer
HashSet<uint> outsideStageFlood =
walkActive ? walkDriver!.VisitedCells : drawableCells;
// The stage-set split: the walk's TRUE root flood (never the
// visited union) keys which interior-parented dynamics may ride
// the last pass — see BuildOutsideDynamicRoutes' sibling gate.
_rootFloodSetScratch.Clear();
if (walkActive)
{
foreach (uint cellId in walkDriver!.InteriorFloodCells)
_rootFloodSetScratch.Add(cellId);
}
if (_sceneFrameProduct is not null)
{
frameView = _sceneFrameProduct.BuildAndBorrow(
@ -517,7 +531,11 @@ public sealed class RetailPViewRenderer
outsideStageFlood,
ctx.Cells,
ctx.AnimatedEntityIds,
ctx.RootCell.IsOutdoorNode);
ctx.RootCell.IsOutdoorNode,
// Non-walk frames (diagnostic fakes / legacy fallback)
// keep the pre-split admission: drawableCells WAS the
// flood in the legacy meaning.
walkActive ? _rootFloodSetScratch : drawableCells);
frameViewBorrowed = true;
frameEntityPasses!.BeginEntityFrame(in frameView);
entityFrameOpen = true;