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>
12 KiB
Indoor Render — Session Handoff: HANG fixed + interior SEALS; the FLAP is next — 2026-06-07
Worktree
thirsty-goldberg-51bb9b, branchclaude/thirsty-goldberg-51bb9b. PowerShell on Windows; launch logs UTF-16; build before launch; acceptance is the user's eyes. Live ACE127.0.0.1:9000,testaccount/testpassword, char+Acdream(spawns near the Holtburg / "Arcanum" cottage — landblock0xA9B4, cottage cells0xA9B4016F–0175). Do NOT branch/worktree, push, orgit stash/gc.
TL;DR
The two-week indoor-render HANG is FIXED and the interior SEALS (walls/floor/ceiling draw, textured) — both committed this session and live-verified by the user ("Ok now it runs!"). A structured live test pinned the remaining dominant visible issue, the FLAP at transitions, as viewer-cell metastability: the render roots at the camera-eye cell, which oscillates outdoor↔indoor as the 3rd-person boom drifts across the doorway plane. The flap is a SEPARATE, already-designed fix — it is NOT the verbatim DrawCells port; finishing the port will not fix it. Next session: fix the flap (camera-boom stability + viewer-cell dead-zone). Tracked follow-ups: #78 terrain gating, look-in-from-inside sealing, look-in FPS, L-spotlight.
What shipped this session (committed — see git log on this branch)
1. The HANG fix (the blocker)
Indoor frames froze (AppHangB1; not a crash — captured the spinning managed stack via a
dotnet-stack hang-watcher). Root cause: PortalVisibilityBuilder.Build's portal-visibility flood
did not terminate for real cottage geometry. Two layers, two fixes (both kept):
- A — drift-tolerant
CellView.Adddedup (src/AcDream.App/Rendering/PortalView.cs). The flood re-queues a cell every time its view GROWS; growth only stops when the dedup recognises a re-clipped region as a duplicate. The faithfulProjectToClipnear-side clip drifts per round, so the old exact index-by-index match (eps 1e-4) never caught the near-duplicate → unbounded growth → O(n²) CPU-spin inCellView.Add. Fix: key each polygon by its vertices snapped to a 1e-3 NDC grid, consecutive-dedup'd, canonically rotated to a lex-min start → finite key space → convergence. Tests:tests/AcDream.App.Tests/Rendering/CellViewDedupTests.cs(3). - B — bounded re-enqueue (
src/AcDream.App/Rendering/PortalVisibilityBuilder.cs). A alone did not fully converge (the spin relocated toScreenPolygonClip.ClipByEdge— bounded loops — inside the still-non-terminating BFS). Restored theMaxReprocessPerCell = 16hard cap that Phase U.2a deleted ("fixpoint termination" left the loop with NO bound). Kept the re-enqueue — it is load-bearing for late-slice propagation (Build_ViewGrowthAfterDoneCell_PropagatesNewSlicesToExit). Pure enqueue-once was tried and broke that test, so re-enqueue is kept and merely bounded. - Deep diagnosis + the reassessment that led to B:
docs/research/2026-06-06-indoor-render-hang-rootcause.md. - Verified: clean exit (255→0); runs indoors with no freeze; the indoor flood converges in ~1 round/cell at normal positions (measured 3–5 pops/frame, 1 view-poly/cell). The cap only bites at the metastable doorway.
2. The SEAL (verbatim DrawCells port — Task 2)
RetailPViewRenderer.DrawEnvCellShells now iterates IndoorDrawPlan.ShellPass(pvFrame) — every
visible cell's shell draws (was gated on ClipFrameAssembler's slot filter → cells without a slot
were silently dropped → grey clear-color void). Verified: interior seals + textured. (Task 1
IndoorDrawPlan + its test committed earlier as bff1955.)
3. Look-in FPS
GameWindow exterior-look-in candidate cells limited to the player's landblock ±1 (was all
~81 loaded landblocks iterated every outdoor frame just to discard them via the 48 m seed cutoff).
Provably no behavior change (excluded cells are >48 m, already culled). Outdoor FPS improved but
still ~110 fps / ~9 ms (was ~200) — DrawPortal still draws ~12 building interiors/frame (see
follow-up).
Baselines (must hold at next session start)
dotnet build -c Debug0 errors.- App.Tests 210/210 (205 baseline + IndoorDrawPlanTests 2 + CellViewDedupTests 3).
- Core.Tests 1331 pass / 4 fail / 1 skip — the 4 are pre-existing Physics door/step-up, unrelated.
Structured live test — findings (Holtburg/Arcanum cottage, 2026-06-07)
User walked a 6-step protocol (inside-still → camera-pan → doorway-threshold → just-outside →
looking-at-cottage → cellar) and reported 8 behaviours; ACDREAM_PROBE_FLAP [render-sig]
correlated each.
| # | Observed | Cause | Bucket |
|---|---|---|---|
| 2,3,6,8 | walls briefly transparent / window+entrance "covered by the world background" / abrupt "teleport" through the doorway — all at transitions (camera crossing a threshold) | THE FLAP | viewer-cell stability (NEXT) |
| 1 | outdoor grass covers the cellar-entrance hole (steady, looking in from outside) | outdoor terrain not gated over the indoor floor opening | #78 terrain gating |
| 7 | from inside, a building seen through the doorway has transparent walls (world-bg shows); pops back when you step outside | look-out shows other buildings unsealed | look-in/look-out completeness |
| 5 | spotlight blobs on textures from the ceiling lamp (always been there) | point-light artifact | L-spotlight (separate) |
| FPS | inside very high; outside 110 fps / ~9 ms (was ~200) | DrawPortal draws ~12 interiors/frame |
look-in cost |
| 4 | cellar transitions stable ✓ | vertical transition doesn't cross the outdoor boundary | — |
The FLAP — pinned (render-sig evidence)
[render-sig] over the doorway shows the render branch + the cell it roots at flip-flopping while the
player cell stays inside:
50× branch=OutdoorRoot viewer=0xA9B40031 (outdoor) player=0xA9B40171 (indoor) gate=in
16× branch=RetailPViewInside viewer=0xA9B40170 (indoor) player=0xA9B40171 gate=in
113× branch=RetailPViewInside viewer=0xA9B40171 (indoor) player=0xA9B40171 gate=in
... oscillates 0x0031 ↔ 0x0170 ↔ 0x0171 frame-to-frame ...
Mechanism: the render roots at the viewer (camera-eye) cell (clipRoot = viewerRoot, Phase W
"one viewpoint"). The 3rd-person boom drifts the eye across the doorway plane; acdream re-resolves the
viewer cell fresh each frame with no hysteresis → it flips between outdoor 0x0031 and indoor
0x0170/0x0171 → the render flips OutdoorRoot↔RetailPViewInside → the indoor seal drops (walls
transparent, outdoor world/grass shows) then re-seals → flapping. This is exactly the 2026-06-05
viewer-cell-flicker diagnosis, now confirmed against the live render branch.
RECOMMENDED NEXT WORK — fix the FLAP (separate, already-designed)
Per docs/research/2026-06-05-viewer-cell-flicker-rootcause-and-fix-plan-handoff.md, 3 retail-faithful parts:
- Viewer-cell dead-zone (do this first) — ±0.2 mm cell hysteresis so a sub-mm eye drift can't flip
the cell (
PhysicsCameraCollisionProbe.SweepEye; retailpoint_inside_cell_bsp0x53c1f0). Highest leverage — likely kills most of the flap on its own. - Camera-boom stability — stop the boom drifting at rest (
RetailChaseCamera.UpdateCamera; retailUpdateCamera0x456660). - w-space (w=0) portal clip — close-portal projection degeneracy (
PortalProjection/PortalVisibilityBuilder; retailGetClip0x5a4320 /polyClipFinish0x6b6d00). Lower priority.
Apparatus ready: ACDREAM_PROBE_FLAP emits [render-sig] (branch/viewer/player/gate per frame),
[flap], [flap-cam], [flap-sweep] — light enough to launch with (the heavy ACDREAM_PROBE_SHELL
firehose is what previously caused an I/O stall; avoid it).
Tracked follow-ups (logged; not yet fixed)
- #78 terrain gating — outdoor terrain (grass) draws over the indoor cellar-entrance hole (and likely
other indoor floors). Decomp anchor
CEnvCell::find_visible_child_cell(acclient_2013_pseudo_c.txt:311397). - Look-in-from-inside — buildings seen through your door/window from inside render unsealed (transparent walls); the look-out pass doesn't draw other buildings' shells. DrawCells port Task 5/7 territory (or R2 "outside-looking-in").
- Look-in FPS —
DrawPortaldraws ~12 building interiors every outdoor frame (~110 vs ~200 fps). Optimize: only look into buildings whose exit portals are frustum-visible; skip when no door is in view. - L-spotlight — ceiling-lamp point light makes spotlight blobs on textures. Pre-existing, separate.
verbatim DrawCells port — remaining tasks (deferred)
Plan: docs/superpowers/plans/2026-06-06-verbatim-retail-indoor-render-port.md. Task 1 + Task 2 done.
Task 3 (objects no-clip) is effectively already satisfied (objects draw membership-gated with no
clip; no half-characters observed). Tasks 4–8 (per-slice trim, look-out, delete ClipFrameAssembler,
look-in, final) are cleanup with no current visible payoff — the seal works and there is no visible
bleed (the "glitches between cells" were the FLAP, not bleed). Task 4 (trim) is intricate (its
per-slice _clipFrame.Reset() is coupled with the landscape/particle passes that still read
clipAssembly slots) and risks re-slicing the working seal — do it carefully, fresh, and only when
clean architecture is the priority.
DO NOT re-litigate
- The HANG fix (A drift-dedup + B bounded re-enqueue) is correct + verified. Do NOT try pure
enqueue-once — it breaks
Build_ViewGrowthAfterDoneCell_PropagatesNewSlicesToExit(late-slice propagation needs the re-enqueue; the cap, not removal, is the termination guarantee). - The grey was the
drawableCells/ClipFrameAssemblerslot filter; Task 2 fixed it. The clip math is faithful — do not "harden the w-clip". - The FLAP is NOT the DrawCells port. It is viewer-cell metastability (camera/membership). Tasks 4–8 will NOT fix it.
- The render roots at the VIEWER (camera-eye) cell intentionally (Phase W "one viewpoint"). The flap fix is to STABILISE the viewer cell (dead-zone + boom), NOT to re-root at the player cell (superseded).
Copy-paste pickup prompt (next session)
Pick up the indoor-render work in worktree thirsty-goldberg-51bb9b (branch
claude/thirsty-goldberg-51bb9b). PowerShell; launch logs UTF-16; build before launch; acceptance is
the user's eyes. Do NOT branch/worktree, push, git stash/gc, or revert the dirty tree.
Read first: docs/research/2026-06-07-indoor-render-session-handoff.md (state, what shipped, the FLAP
diagnosis, do-not-relitigate). Then docs/research/2026-06-05-viewer-cell-flicker-rootcause-and-fix-plan-handoff.md
(the flap fix plan).
Confirm baselines: build 0 errors; App.Tests 210/210; Core.Tests 1331 pass / 4 fail (pre-existing) / 1 skip.
The indoor HANG is fixed and the interior SEALS (shipped + committed last session). The remaining
dominant visible issue is the FLAP at transitions — viewer-cell metastability: the render roots at the
camera-eye cell, which oscillates outdoor↔indoor as the 3rd-person boom drifts across the doorway (no
hysteresis), confirmed in [render-sig]. FIX THE FLAP, starting with the viewer-cell dead-zone
(PhysicsCameraCollisionProbe.SweepEye; retail point_inside_cell_bsp 0x53c1f0), then camera-boom
stability (RetailChaseCamera.UpdateCamera; retail UpdateCamera 0x456660). Launch with ACDREAM_PROBE_FLAP
only (NOT ACDREAM_PROBE_SHELL — it stalls on I/O). Gate on the user's eyes at the cottage doorway.
Do NOT: retry pure enqueue-once (breaks late-slice propagation); re-root render at the player cell
(viewer-cell rooting is intentional); finish DrawCells port Tasks 4-8 expecting it to fix the flap (it
won't). Tracked follow-ups (not the flap): #78 terrain gating (grass over cellar hole), look-in-from-
inside sealing, look-in FPS (DrawPortal ~12 interiors/frame), L-spotlight.