acdream/docs/research/2026-06-06-retail-pview-renderer-replacement-attempts-handoff.md
Erik 1405dd8e90 feat(render): indoor render WORKS — terminating portal flood + every-cell seal + look-in FPS
Checkpoint of the unified retail-faithful indoor render. The two-week HANG/grey is fixed and the
interior seals (live-verified by the user). Commits the session render-rewrite foundation together
with the fixes that made it functional.

- HANG fix: PortalVisibilityBuilder.Build portal flood did not terminate (the faithful ProjectToClip
  near-side clip drifts per round, defeating the CellView dedup; the BFS had no bound after U.2a removed
  MaxReprocessPerCell). Fix = drift-tolerant snapped/canonical CellView.Add dedup (PortalView.cs) plus
  restored MaxReprocessPerCell=16 bounded re-enqueue (PortalVisibilityBuilder.cs). Re-enqueue is kept
  (load-bearing for late-slice propagation, Build_ViewGrowthAfterDoneCell_PropagatesNewSlicesToExit);
  only its count is capped. CellViewDedupTests added.
- Seal (DrawCells Task 2): RetailPViewRenderer.DrawEnvCellShells draws EVERY visible cell via
  IndoorDrawPlan.ShellPass (was gated on the ClipFrameAssembler slot filter, leaving slot-less cells grey).
- Look-in FPS: GameWindow exterior look-in candidates limited to the player landblock +-1 (was all ~81
  loaded LBs iterated every outdoor frame). No behaviour change (far cells were >48m, already culled).

Remaining dominant issue = the FLAP at transitions: viewer-cell metastability (render roots at the
camera-eye cell, which oscillates outdoor-indoor as the 3rd-person boom drifts across the doorway,
confirmed in render-sig). SEPARATE fix, NOT the DrawCells port. Full handoff + flap fix plan + tracked
follow-ups (#78 terrain, look-in-from-inside, look-in FPS, L-spotlight):
docs/research/2026-06-07-indoor-render-session-handoff.md.

Baselines: build 0 err; App.Tests 210/210; Core.Tests 1331 pass / 4 fail (pre-existing) / 1 skip.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-07 10:14:43 +02:00

22 KiB

Handoff - M1.5 Indoor Render / Retail PView Replacement Attempts - 2026-06-06

This is a stop-and-handoff note for the next agent. It records what was tried, what changed on disk, what the user still sees, and what evidence should drive the next step.

The user explicitly stopped this thread after repeated visual regressions. Do not continue the same patching loop. Treat all current uncommitted render work as suspect until re-audited against named retail.

Worktree And Rules

  • Worktree: C:\Users\erikn\source\repos\acdream\.claude\worktrees\thirsty-goldberg-51bb9b
  • Branch: claude/thirsty-goldberg-51bb9b
  • Starting HEAD called out by the user: 8116d10
  • Do not branch or create a new worktree.
  • Do not push without asking.
  • Never run git stash or git gc.
  • PowerShell on Windows.
  • Launch logs are UTF-16.
  • Build before launching.
  • Use apply_patch for manual edits.
  • Do not revert dirty changes unless the user explicitly asks.

Current child handoff thread created before this file:

  • Child thread id: 019e9d5c-bb34-7fe3-85cc-6b9065b4e882
  • It was forked same-directory, not a new worktree.
  • A follow-up prompt was sent there with the immediate evidence and constraints.

User-Visible State At Stop

The latest user report, after the most recent relaunch:

  • Transition flaps still happen between outdoor/indoor, room/room, and cellar.
  • Ground floor became transparent instead of sealed.
  • Cellar remains broken.
  • Prior screenshots showed grey or black background filling cell openings.
  • Prior screenshots showed indoor walls losing texture or drawing as clear/background color.
  • Prior screenshots showed character cut in half on the cellar stairs.
  • User explicitly says we are back to old bugs and nothing feels solid.

Important: do not claim any current code is fixed. Build/tests passed for some pieces, but visual acceptance failed.

Current Dirty State

git status --short --branch showed these tracked files modified:

  • src/AcDream.App/Rendering/ClipFrameAssembler.cs
  • src/AcDream.App/Rendering/ClipPlaneSet.cs
  • src/AcDream.App/Rendering/GameWindow.cs
  • src/AcDream.App/Rendering/InteriorEntityPartition.cs
  • src/AcDream.App/Rendering/InteriorRenderer.cs
  • src/AcDream.App/Rendering/ParticleRenderer.cs
  • src/AcDream.App/Rendering/PortalView.cs
  • src/AcDream.App/Rendering/PortalVisibilityBuilder.cs
  • src/AcDream.App/Rendering/Wb/ObjectMeshManager.cs
  • src/AcDream.App/Rendering/Wb/WbDrawDispatcher.cs
  • src/AcDream.Core/Rendering/RenderingDiagnostics.cs
  • src/AcDream.Core/World/WorldEntity.cs
  • tests/AcDream.App.Tests/Rendering/ClipFrameAssemblerTests.cs
  • tests/AcDream.App.Tests/Rendering/ClipPlaneSetTests.cs
  • tests/AcDream.App.Tests/Rendering/InteriorEntityPartitionTests.cs
  • tests/AcDream.App.Tests/Rendering/PortalVisibilityBuilderTests.cs
  • tests/AcDream.App.Tests/Rendering/Wb/WbDrawDispatcherClipSlotTests.cs
  • tests/AcDream.Core.Tests/Rendering/RenderingDiagnosticsTests.cs
  • tools/TextureDump/Program.cs

Important untracked files include:

  • src/AcDream.App/Rendering/RetailPViewRenderer.cs
  • docs/research/2026-06-05-retail-pview-indoor-render-pseudocode.md
  • many probe logs and local scripts/images, including launch-flap-shell-capture-relaunch.log, launch-pview-watermark-probe.log, a8-current-room-cellar-audit.txt, texture-current-room-surfaces.txt, analyze_*.py, retail-*-trace.log, and several screenshots.

Diff size before this handoff file:

  • 19 tracked files changed.
  • About 1593 insertions and 773 deletions.

Validation That Passed But Did Not Prove Visual Correctness

After the last attempted PortalVisibilityBuilder patch:

dotnet test tests\AcDream.App.Tests\AcDream.App.Tests.csproj -c Debug --filter "FullyQualifiedName~PortalVisibilityBuilderTests|FullyQualifiedName~PortalProjectionTests"

Passed: 29/29.

dotnet build -c Debug --no-restore

Succeeded, with 9 known warnings.

dotnet test tests\AcDream.App.Tests\AcDream.App.Tests.csproj -c Debug --no-build

Passed: 196/196.

These results only prove the pure/tested slices compile and pass. They did not solve the live render.

Retail PView Reference Already Written

New pseudocode note exists:

  • docs/research/2026-06-05-retail-pview-indoor-render-pseudocode.md

It summarizes:

  • SmartBox::RenderNormalMode @ 0x00453aa0
  • RenderDeviceD3D::DrawInside @ 0x0059f0d0
  • PView::DrawInside @ 0x005a5860
  • PView::ConstructView @ 0x005a57b0
  • PView::DrawCells @ 0x005a4840
  • RenderDeviceD3D::DrawObjCellForDummies @ 0x005a0760

Core retail model from that note:

  • Outdoor: LScape::draw, then portal/interior peering through PView portal paths.
  • Indoor: DrawInside(viewer_cell).
  • PView::ConstructView builds cell_draw_list, per-cell portal_view, and outside_view.
  • PView::DrawCells draws outside landscape through outside_view, then reverse cell_draw_list exit masks, reverse shells, reverse object lists.
  • No global indoor terrain/entity/particle pass should bypass PView membership.

Retail Functions That Still Matter

Re-read named retail before more code:

  • PView::AddViewToPortals @ 0x005a52d0
  • PView::ConstructView @ 0x005a57b0
  • PView::ClipPortals @ 0x005a5520
  • PView::FixCellList @ 0x005a5250
  • PView::AdjustCellView @ 0x005a5770
  • PView::OtherPortalClip @ 0x005a5400
  • PView::GetClip around 0x005a4320
  • SmartBox::RenderNormalMode @ 0x00453aa0
  • SmartBox::update_viewer @ 0x00453ce0
  • RenderDeviceD3D::DrawObjCellForDummies @ 0x005a0760

The critical retail detail not faithfully settled yet:

  • Retail tracks view_count and update_count.
  • When a cell view grows after the cell was already processed, retail calls FixCellList / AdjustCellView.
  • Current acdream code only approximates this. It may not match draw-list ordering or downstream propagation.

What We Tried

1. Treated symptoms as separate render leaks

The session started with symptoms that looked separate:

  • dynamic objects and particles visible through ground when looking out from inside;
  • outside ground texture covering cellar entrance when looking in;
  • grey flaps when crossing cell boundaries;
  • missing cellar floor / grey cellar;
  • transparent or textureless interior walls.

The user correctly pushed back that these are probably one render-pipeline failure: indoor/outdoor, cells, shells, terrain, objects, particles, and doors must all agree on one visible-cell graph.

2. Gated dynamic objects and particles by ownership

Attempt:

  • WorldEntity.ParentCellId was populated for player/spawns/teleports/motion updates.
  • InteriorEntityPartition was changed so live dynamic entities with an indoor ParentCellId go into their cell bucket instead of a global live-dynamic overlay.
  • WbDrawDispatcher.ResolveEntitySlot was changed so ServerGuid != 0 no longer always means "draw unclipped indoors".
  • Particles were moved toward PView-scoped / owner-scoped behavior instead of a global indoor scene pass.

Effect:

  • User reported this stopped much of the obvious dynamic-object/particle bleeding when looking out.
  • It did not fix grey/background transition flaps.
  • It did not fix cellar/floor/walls.

Current risk:

  • This direction is probably correct, but the exact routing must be audited. A later attempt also cleared clip routing to avoid character/shell cutting, so "PView membership" and "GPU clip slot routing" are currently mixed/confused.

3. Added/used a RetailPViewRenderer

Attempt:

  • Added src/AcDream.App/Rendering/RetailPViewRenderer.cs.
  • Moved part of indoor draw orchestration into RetailPViewRenderer.DrawInside.
  • Added DrawPortal for outdoor-looking-in through PortalVisibilityBuilder.BuildFromExterior.
  • The renderer currently does:
    • PortalVisibilityBuilder.Build
    • ClipFrameAssembler.Assemble
    • _envCells.PrepareRenderBatches(filter: drawableCells)
    • InteriorEntityPartition.Partition
    • landscape through outside slices
    • exit masks
    • EnvCell shells
    • object buckets

Effect:

  • This is not a full retail replacement yet.
  • User repeatedly saw unchanged or worse symptoms.
  • FPS was reported drastically down after one iteration.
  • Subsequent attempts produced missing textures / white or grey wall panels.

Current risk:

  • RetailPViewRenderer is not truly verbatim retail. It keeps modern infrastructure and approximates PView with GPU clip slots and callbacks.
  • The user asked "have you ported retail verbatim?" and the honest answer remains no.
  • GameWindow still has a lot of orchestration, diagnostics, and render routing around this. It is not a small caller yet.

4. Reworked ClipFrameAssembler from one clip per cell to per-slice clip slots

Attempt:

  • ClipFrameAssembler was rewritten toward per-polygon/slice output:
    • CellIdToViewSlices
    • OutsideViewSlices
    • per-slice ClipViewSlice
    • TerrainClipMode for outside-view landscape
  • The goal was to represent retail portal_view slices more closely.

Effect:

  • The code is plausible as a draw assist, but it is not retail membership.
  • User saw regressions including black covers during transitions.

Current risk:

  • The next agent must ensure ClipFrameAssembler never decides PView membership.
  • It should be draw-assist only.
  • Several failures looked like GPU clip slots cutting shells or characters at door/stair boundaries.

5. Disabled clip routing for shells/entities to stop character/stair cutting

Attempt:

  • RetailPViewRenderer.UseIndoorMembershipOnlyRouting clears _envCells.SetClipRouting(null) and _entities.ClearClipRouting().
  • Comment says retail portal views decide eligibility, but feeding those 2D views into GL clip distances slices characters and shells at stair/door boundaries.

Effect:

  • This was a reaction to user screenshots where the character was cut in half on stairs.
  • It may reduce character slicing.
  • It may also mean shells/objects are currently only membership-gated, not portal-view clipped.

Current risk:

  • This is not a settled retail copy. It is an emergency compromise.
  • Retail does use per-view setup (CEnvCell::setup_view) around shell/object drawing. We need to know whether our GL clip-plane model is simply the wrong mechanism for that setup.

6. Tried EnvCell / DAT polygon side handling changes

Attempt:

  • ObjectMeshManager changed CellStruct polygon side handling:
    • DAT CullMode interpreted as retail CPolygon::sides_type.
    • 0 = pos
    • 1 = pos twice with reversed winding
    • 2 = pos + neg surface
    • NoPos / NoNeg still suppress faces.
  • Added explicit normal inversion / winding reversal logic.

Effect:

  • User saw missing textures/white/grey interior panels after some launches.
  • The attempt did not fix the cellar or transition flaps.

Current risk:

  • This may be correct retail interpretation or may be partially wrong.
  • Audit with DAT dumps and retail/ACME references before keeping.
  • a8-current-room-cellar-audit.txt and texture-current-room-surfaces.txt may contain useful surface/cell evidence.

7. Tried outside-looking-in via BuildFromExterior

Attempt:

  • PortalVisibilityBuilder.BuildFromExterior seeds interior cell views through outside-facing exit portals.
  • RetailPViewRenderer.DrawPortal calls it from outdoor branch.
  • Tests were added:
    • seeds interior cell through outside portal;
    • does not seed when camera is on interior side;
    • traverses deeper interior portals;
    • max seed distance skips distant exit portal.

Effect:

  • User initially reported walls became visible looking in from outside, but ground/cellar entrance composition stayed wrong.
  • Later launches regressed to transparent/grey panels and missing textures.

Current risk:

  • This is probably needed, but the exterior portal path is not proven retail-faithful.
  • BuildFromExterior may now have duplicated-looking test diff context; inspect file carefully.

8. Tried broad "no hybrid" render routing in GameWindow

Attempt:

  • GameWindow was changed so indoor path should call RetailPViewRenderer.DrawInside.
  • Outdoor path should draw world and call DrawPortal.
  • Global indoor terrain/entity/particle passes were reduced or bypassed.
  • New render signature diagnostics log:
    • branch
    • root
    • viewerRoot
    • playerRoot
    • viewerCell
    • playerCell
    • gate
    • terrain
    • skyGate
    • zclear
    • sceneParticles
    • outSlices
    • outPolys
    • ids
    • draw
    • object partition counts

Effect:

  • User explicitly asked whether the hybrid was totally gone.
  • It is not safe to answer "yes" without auditing GameWindow.
  • Symptoms persisted, so either the routing is still hybrid or the PView graph/draw setup is wrong enough that "no hybrid" alone does not solve it.

Current risk:

  • GameWindow.cs has a very large diff, around 1000 lines touched.
  • Next agent should not blindly keep it.
  • Audit all remaining global passes while clipRoot != null.

9. Tried PView update_count-style reprocessing

Attempt in the last aborted step:

  • PortalView.CellView.Add now returns bool and deduplicates near-identical polygons.
  • PortalVisibilityBuilder.Build replaced seen with:
    • queued
    • drawListed
    • processedViewCounts
  • A cell can be requeued when its view grows.
  • Each processing pass clips portals against only newly added view polygons.
  • Similar logic was added to BuildFromExterior.
  • Added tests:
    • Build_CollapsedInteriorPortalNearEyeBeyondHalfMeter_FloodsNeighbour
    • Build_ViewGrowthAfterDoneCell_PropagatesNewSlicesToExit

Effect:

  • Focused tests passed.
  • Live probe after patch still showed outPolys toggling near root 0xA9B40172.
  • User then reported transition flaps still there and now ground floor transparent.

Current risk:

  • This patch is unaccepted and may be wrong.
  • It approximates retail update_count, but does not necessarily implement FixCellList, AdjustCellPlace, or retail draw-list ordering correctly.

10. Widened eye-standing-in-portal fallback

Attempt:

  • EyeStandingPerpDist widened from 0.5f to 1.75f.
  • Motivation: live cellar capture had 0174 -> 0175 traversable with D=-1.41 but ProjectToNdc returned zero vertices.
  • The fallback still requires the perpendicular projection to land inside the portal opening.

Effect:

  • It made one unit test pass for the cellar-style collapsed portal.
  • It did not solve live transitions.

Current risk:

  • This may be a bandaid, not retail.
  • It should be validated against OtherPortalClip / GetClip in named retail before keeping.

11. Tried reciprocal clip fallback for eye-in-opening

Attempt:

  • Before ApplyReciprocalClip, code clones clippedRegion when eyeInsideOpening.
  • If reciprocal clipping empties the region, it restores the pre-reciprocal region.

Effect:

  • Tests passed.
  • Live visual did not.

Current risk:

  • This may over-include.
  • It is not proven retail-faithful.

Critical Evidence From Logs

Cellar startup: root 0174 only sees itself

From launch-flap-shell-capture-relaunch.log:

[flap] root=0xA9B40174 eye=(154.50,4.99,92.25) localEye=(7.43,2.51,-1.77) |
p0->0x0175 D=-1.41 TRV proj=0 clip=-1 || outPolys=0 vis=1

[flap-cam] root=0xA9B40174 viewerCell=0xA9B40174 playerCell=0xA9B40174
... terrain=Skip outVisible=False

[render-sig] frame=49 branch=RetailPViewInside root=0xA9B40174
... terrain=Skip/skip sky=n zclear=n sceneParticles=none
outSlices=0 outPolys=0 ids=[0xA9B40174] draw=[0xA9B40174]

Meaning:

  • The player/viewer/root are in cellar cell 0174.
  • The only visible portal to stair connector 0175 is traversable.
  • Projection produces zero vertices.
  • The PView flood stops at the cellar.
  • Only the cellar draws; stair/main-floor cells are not in the visible set.

This is a direct candidate cause for missing floor/grey composition.

Root 0172: outside view toggles on/off

From launch-pview-watermark-probe.log:

frame=3625 root=0xA9B40172
p0->0x0173 D=... TRV proj=4 clip=4
p1->0x016F D=5.28 TRV proj=0 clip=-1
outPolys=1 vis=6
ids include 0xA9B40170
terrain=Skip/draw sky=Y zclear=Y

frame=3626 root=0xA9B40172
p0->0x0173 D=... TRV proj=5 clip=5
p1->0x016F D=5.39 TRV proj=0 clip=-1
outPolys=0 vis=5
ids missing 0xA9B40170
terrain=Skip/skip sky=n zclear=n

frame=3647 root=0xA9B40172
outPolys=1 ids include 0xA9B40170 terrain draw

frame=3648/3649 root=0xA9B40172
outPolys=0 ids missing 0xA9B40170 terrain skip

Meaning:

  • The same root cell can alternate between seeing outside and not seeing outside.
  • 0x016F is involved in the root flap line but projects to zero.
  • Sometimes 0x0170 becomes reachable and outside terrain/sky/depth clear run; sometimes it disappears.
  • The visible-cell list and outside-view list are not stable.

Open question:

  • Is 0x016F an outdoor/land cell, an env cell lookup miss, or a portal that retail handles differently?
  • Is the toggling caused by projection/clip degeneracy, wrong portal reciprocal handling, update-count propagation, or camera/viewer-cell root?

Earlier known evidence: root 0171 vs player 0174 contradiction

From the older 2026-06-05-shell-sealing-cellar-floor-handoff.md:

[flap-cam] root=0xA9B40171 viewerCell=0xA9B40171 playerCell=0xA9B40174
...
[flap] root=0xA9B40171 ... p1->0173 proj=0 ...

Meaning:

  • Earlier, camera/root was the room while player was cellar.
  • The flood did not seal the player's cell.
  • Later, after branch/viewer changes, there are also frames where root/player/viewer are all 0174 but the flood still fails on 0174 -> 0175.

This means the problem is probably not only "wrong root"; it also includes projection/portal traversal/flood propagation or mesh-shell handling.

What Not To Retry Blindly

Do not simply:

  • switch the root to player cell as a workaround;
  • widen EyeStandingPerpDist further;
  • globally draw all indoor shells;
  • globally draw terrain/entities/particles while inside;
  • turn off all clipping and hope depth sorts it;
  • keep adding if cellar or Holtburg-cottage-specific handling;
  • claim "no hybrid" without auditing all GameWindow indoor/outdoor passes;
  • equate unit-test pass with visual correctness.

The user has explicitly asked for retail smoothness, not a new patch stack.

Likely Root Problem Space

The next fix probably lives in one of these, but evidence must decide:

  1. PView graph construction is not retail-faithful.

    • Missing or wrong update_count / FixCellList / AdjustCellView.
    • Wrong draw-list ordering when a processed cell receives new views.
    • Downstream portal propagation incomplete.
  2. Portal projection/clip behavior differs from retail.

    • 0174 -> 0175 traversable but proj=0.
    • 0172 -> 016F traversable but proj=0.
    • OtherPortalClip / GetClip may not match retail.
  3. Outdoor/exit portal classification is wrong.

    • OtherCellId=0xFFFF is treated as exit/outside, but 0x016F may be another kind of outside/land portal or missing env cell.
    • OutsideView may be created through a downstream path that acdream sometimes drops.
  4. Renderer draw setup is still hybrid or ordered wrong.

    • GameWindow may still draw or skip global passes inconsistently.
    • Sky/terrain/depth clear decisions are visibly flapping with outside_view.
  5. EnvCell shell mesh/surface handling is wrong.

    • Missing/transparent/white walls and floors may be mesh/surface/cull-side regressions.
    • Audit ObjectMeshManager side handling against retail and DAT dumps.
  6. GPU clip slots are being used as membership or hard clipping when retail uses view setup differently.

    • Character cut in half on stairs strongly suggests hard clip-plane use on avatars/shells is wrong or applied at wrong pass.

Suggested Next Procedure

  1. Stop patching. Inspect the dirty diff first.
  2. Read docs/research/2026-06-05-retail-pview-indoor-render-pseudocode.md.
  3. Re-read named retail functions listed above.
  4. Parse launch-flap-shell-capture-relaunch.log and launch-pview-watermark-probe.log around the cited frames.
  5. Add better probes if needed:
    • cell id;
    • portal index;
    • other cell id;
    • portal flags;
    • other portal id;
    • traversable decision;
    • standing distance;
    • projection vertex count;
    • clip vertex count;
    • reciprocal clip result;
    • outside-view add/skip reason;
    • cell view count / processed count / update count;
    • queue/requeue reason;
    • draw-list insertion/reorder.
  6. Decide from evidence whether 0174 -> 0175 and 0172 -> 016F fail because of projection, reciprocal clip, cell lookup/classification, or update propagation.
  7. Patch only the retail mismatch.
  8. Build/test before launch.
  9. Launch with probes once.
  10. Then launch clean for FPS/visual feel.
  11. Do not call it done until the user visually confirms retail smoothness.

Launch Command

Use PowerShell:

Get-Process -Name AcDream.App -ErrorAction SilentlyContinue | Stop-Process -Force
Start-Sleep -Seconds 3

$env:ACDREAM_DAT_DIR   = "$env:USERPROFILE\Documents\Asheron's Call"
$env:ACDREAM_LIVE      = "1"
$env:ACDREAM_TEST_HOST = "127.0.0.1"
$env:ACDREAM_TEST_PORT = "9000"
$env:ACDREAM_TEST_USER = "testaccount"
$env:ACDREAM_TEST_PASS = "testpassword"
$env:ACDREAM_PROBE_FLAP = "1"
$env:ACDREAM_PROBE_SHELL = "1"
$env:ACDREAM_PROBE_VIS = "1"
dotnet run --project src\AcDream.App\AcDream.App.csproj --no-build -c Debug 2>&1 |
  Tee-Object -FilePath "launch-next-pview.log"

For clean visual/FPS run, remove the probe env vars.

Minimal Prompt For Next Agent

Continue acdream M1.5 indoor render in SAME worktree:
C:\Users\erikn\source\repos\acdream\.claude\worktrees\thirsty-goldberg-51bb9b
branch claude/thirsty-goldberg-51bb9b. Do NOT branch/worktree. Do NOT push. NEVER stash/gc.

The current dirty render code is not visually accepted. The user stopped the prior agent after repeated regressions.
Read docs/research/2026-06-06-retail-pview-renderer-replacement-attempts-handoff.md first.

Current symptoms: transition flaps still happen indoor/outdoor, room/room, cellar; ground floor is now transparent; cellar broken; prior runs showed grey/black clear color, missing wall textures, and character cut on stairs.

Do not patch first. Audit dirty diff, read named retail PView, parse launch-flap-shell-capture-relaunch.log and launch-pview-watermark-probe.log. Determine exactly why:
1) cellar root 0174 fails to traverse 0174 -> 0175 when proj=0;
2) root 0172 toggles outside_view/0170 reachability while 0172 -> 016F has proj=0;
3) shell/object/terrain/depth-clear decisions disagree.

Patch only the retail mismatch. Build/test before relaunch. Do not claim success before user visual confirmation.