acdream/docs/research/2026-06-05-shell-sealing-cellar-floor-handoff.md
Erik 8116d101bc docs: SHELL-SEALING / wrong-flood-root handoff (cellar floor + interior walls grey)
The user's primary symptom (interior walls + cellar floor render as grey clear-color
with dynamic objects / outdoor slices showing through; flicker at room/cellar
transitions) is the KNOWN R1-completion problem: the PView flood roots at the CAMERA
cell (viewer cell), and when the camera is in a different interior cell than the player
(room 0171 vs cellar 0174), the flood does not seal the player's cell. Decisive
evidence: flap-cam root=0xA9B40171 playerCell=0xA9B40174. This handoff separates the
two problems I conflated, lists the disproven causes, gives the next diagnostic step
(shell/flap/vis probes in the cellar), and a kickoff prompt. HEAD 2b7f5a1.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-05 17:04:52 +02:00

16 KiB
Raw Blame History

Handoff — Indoor SHELL-SEALING / wrong-flood-root (cellar floor + interior walls drop to grey) — 2026-06-05 (PM/eve)

For the next session/model. Read this FIRST. The previous model (me) spent this session on the "viewer-cell flicker" 3-part plan, shipped two real-but-partial fixes, and conflated two distinct problems. The user's PRIMARY pain — interior walls + cellar floor render as grey background with dynamic objects / outdoor slices showing through, plus flicker when changing rooms / entering the cellar — is the KNOWN, already-documented "R1-completion" problem, NOT the boom and NOT the branch I touched. Get a SCREENSHOT + [shell] evidence EARLY; do not re-litigate the disproven causes below.

Tree: branch claude/thirsty-goldberg-51bb9b, worktree C:/Users/erikn/source/repos/acdream/.claude/worktrees/thirsty-goldberg-51bb9b. HEAD 2b7f5a1. Do NOT branch/worktree. Do NOT push without asking. NEVER git stash/gc. PowerShell on Windows; launch logs are UTF-16 (use Select-String/Get-Content, they handle it).


0. The honest TL;DR

  • The user reports (with a screenshot): standing inside the cottage, the floor draws but the walls are grey (the time-of-day clear color), with NPCs/doors/chests and a slice of the outdoor world floating in the grey. In the cellar, the floor is missing (just grey). It flickers when changing rooms / entering the cellar. This persisted through both of this session's fixes.
  • Decisive evidence (live, this session):
    [flap-cam] root=0xA9B40171  viewerCell=0xA9B40171  playerCell=0xA9B40174  eyeInRoot=Y
               eye=(153.46,6.66,94.92)  player=(153.58,8.88,92.76)  terrain=Planes outVisible=True
    [flap]     root=0xA9B40171 ... | p0->0170 proj=4 | p1->0173 proj=0 | p2->0175 proj=5 || outPolys=1 vis=4
    
    The render roots the visibility flood at the CAMERA's cell 0171 (the room, z≈95), but the PLAYER is in 0174 (the cellar, z≈93). The flood reaches vis=4 cells from the room; the player's actual cell 0174 is not sealed by it (the stair-chain portal p1→0173 is proj=0). So the cellar shell around the player isn't drawn → grey.
  • This is exactly what the 2026-06-05 Residual-A handoff already flagged as NEXT: "when the player is in the cellar but the eye is up in the room, clipRoot = room → the PVS flood from the room does NOT reach the cellar → the cellar floor drops." And the 2026-06-02 design doc §3 calls the grey a SHELL-SEALING bug ("the closed cell mesh is not covering those pixels"). The answer was in the docs the whole time.
  • Two fixes shipped this session (both real, both PARTIAL, neither is the cellar/walls fix):
    • d2212cf — Part 1 camera boom convergence snap (retail UpdateCamera 0x00456fcd). Freezes the at-rest boom drift. Test-covered. The user confirmed the at-rest room was never flickering, so this fixed a real-but-invisible thing. KEEP (faithful) or reassess.
    • 2b7f5a1 — branch inside/outside on is_player_outside (retail RenderNormalMode 0x453aa0) instead of the camera cell. Reduced the player-OUTSIDE doorway grey ("reduced a lot" — user). Test-covered. Does NOT touch the player-inside case. KEEP (no regression — see §4) or reassess.

1. The two problems (do NOT conflate them — I did, and it cost the session)

Problem A — doorway transition grey Problem B — interior shell not sealed (THE user's pain)
When Player fully outside (landcell <0x100), camera lags inside the doorway Player inside cell X, camera inside a DIFFERENT cell Y (camera in room, player in cellar)
Why Branch keyed on camera → wrongly ran DrawInside rooted at the threshold Flood roots at the camera's cell Y; the player's cell X isn't in/sealed by the flood from Y
Symptom Whole screen grey at the in↔out threshold Walls/cellar-floor grey while standing inside; flicker at room/cellar transitions
Status Reduced by 2b7f5a1 (retail-verified) UNSOLVED — this is the real target
Evidence outPolys=0 while the exit portal projects full-screen (proj=6 clip=8) root=0171 vs playerCell=0174; vis=4 from the room excludes the cellar

Problem B is the one to fix. Problem A's fix is a genuine retail-faithful improvement that happens to share a "grey" symptom, which is what made me conflate them.


2. Problem B — what we know, and the core open question

The render roots the PView flood at clipRoot = visibility.CameraCell (the VIEWER/camera cell)GameWindow.cs:7322 (now wrapped by the ShouldRenderIndoor branch, but still the viewer cell when indoor). Retail RenderNormalMode (0x453aa0:92675) literally calls DrawInside(this->viewer_cell). So rooting at the viewer cell is retail-faithful on its face.

But when the 3rd-person camera is in a different interior cell than the player (room vs cellar), the flood from the camera's cell does not seal the player's cell → the geometry around the player (cellar floor, near walls) isn't drawn → grey. The decisive [flap-cam] line (root=0171, playerCell=0174) is the whole story.

The core open question the next model MUST resolve against the decomp (don't guess — this is the crux): how does retail avoid this? Candidate mechanisms, each needs decomp verification:

  • (a) Retail's collided camera stays in (or floods to) the player's cell. Residual A (SmartBox::update_viewer 0x00453ce0, swept viewer_sphere) is shipped, but verify: does retail's viewer_cell actually equal the player's cell when the player is in the cellar and the boom would put the eye up in the room? The spring arm sweeps from the head-pivot — if the pivot is the player's head in the cellar, the swept eye may be stopped by the cellar ceiling and stay in 0174. Check whether acdream's viewer_cell SHOULD be 0174 here and isn't (i.e. the camera-collision/cell- resolution is putting the eye in 0171 when retail would keep it in 0174).
  • (b) Retail's flood from the viewer cell DOES reach the player's cell, because retail's portal clip is robust and the stair-chain portals don't go proj=0. Here p1→0173 proj=0 stops the flood. Is 0174 reachable only through 0173 (which is culled)? If so, the flood-reach is the bug, not the root.
  • (c) The design doc §5 intent: visibility roots at the PLAYER's physics cell (CellGraph.CurrCell), eye drives projection only. The 2026-06-05 viewer-cell handoff said don't switch the root to the player cell ("retail roots DrawInside at viewer_cell"). This is a real contradiction in our own docs — design doc §5 says player-cell-roots-visibility; the later handoff says viewer-cell-roots. The next model should settle it from the decomp: in RenderNormalMode, viewer_cell is the argument to DrawInside — but WHAT sets viewer_cell, and is it ever != the player's cell in normal play? If retail's viewer_cell is always the player's cell (because the camera collision keeps it there), then (a) and (c) converge and acdream's bug is that its viewer_cell drifts to the camera's room cell.

Strong hypothesis to test first (cheap): acdream's viewer_cell (visibility.CameraCell) is wrong here — it's the room because the eye is geometrically up in the room, but retail's collided viewer_cell would be the cellar (the swept sphere from the head-pivot is stopped by the cellar ceiling / the pivot is in the cellar). I.e. this is a camera-cell-resolution bug, not a flood/root bug. Verify by reading how visibility.CameraCell / viewerCellId is computed (CellVisibility. FindCameraCell + PhysicsCameraCollisionProbe.SweepEye) and whether the pivot/sweep should keep the cell in 0174.


3. The next diagnostic step (do this BEFORE any fix — evidence first)

The apparatus is committed and ready. Stand the player in the cellar with the camera up in the room (the exact repro), and capture:

$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 launch.log

Pin these three things from the log while standing in the cellar:

  1. Is the player's cell (0174) in the visible set? [flap-cam] shows root= vs playerCell=; [vis]/[flap] shows vis= count + (turn on ACDREAM_PROBE_VIS for the cell-id list). If 0174 is NOT in the set → flood-reach / wrong-root problem (§2 a/b/c).
  2. If 0174 IS in the set, does its shell DRAW? [shell] probe (ACDREAM_PROBE_SHELL) reports per-cell shell draw (geometry/texture/depth). If 0174 is visible but its shell is skipped / a polygon is back-facing / depth-culled → mesh-seal problem (design doc §3: dat-dump the 0174 EnvCell mesh, look for a missing/back-facing floor polygon).
  3. What viewer_cell SHOULD it be? Compare the live viewerCell= to where the player is. If the camera collision (Residual A) is failing to keep the eye's cell == the player's cell, that's §2(a).

This single capture discriminates root-vs-flood-vs-mesh. Don't pick a fix until it does.


4. Exactly what's committed this session (and why each is safe to keep)

SHA What Keep?
d2212cf Part 1 boom convergence snap — RetailChaseCamera.ApplyConvergenceSnap + wiring; retail UpdateCamera 0x00456fcd (SnapEpsilon=2×0.000199999995, RotCloseEpsilon=0.000199999995). 4 new App tests. Keep — retail-faithful, fixes at-rest boom drift, no regression. Not the visible fix.
2b7f5a1 Branch inside/outside on is_player_outside (RenderingDiagnostics.ShouldRenderIndoor + GameWindow.cs:7322). 5 new Core tests. Keep — retail-faithful, reduced Problem A. Provably no Problem-B regression: for the player-inside case it yields clipRoot = CameraCell, identical to the pre-fix visibility?.CameraCell.

Plan doc (Part 1's TDD steps; Parts 2/3 there are SUPERSEDED by this handoff — see §5): docs/superpowers/plans/2026-06-05-indoor-viewer-cell-flicker-fix.md.

Working tree is clean (the TEMP w-stat probe added to PortalVisibilityBuilder.cs was stripped; git status shows nothing under src/tests). Test baseline: App 187p/0f, Core 1331p / 4f / 1s, build green. The 4 Core fails are the documented set (2× DoorBugTrajectoryReplay.LiveCompare_*, BSPStepUpTests.D4, DoorCollisionApparatusTests).


5. DO NOT RE-LITIGATE (evidence-disproven this session)

  • The flicker is NOT viewer-cell oscillation / cell-membership instability. Captured the render gate (terrain=Skip/Planes, outVisible) flapping with the viewer cell STABLE at 0171. The planned Part 2 (point_inside_cell_bsp ±0.2 mm dead-zone) was NOT implemented and is NOT the fix.
  • The doorway grey is NOT the portal PROJECTION degenerating. At the grey frame the exit portal p0→0170 projects full-screen (proj=6 clip=8, ndc spans ±1) while outPolys=0. So ProjectToNdc is fine; the OutsideView/flood assembly (and, per §2, the root/flood-reach) is the issue. Do not "harden the w-clip" (5f596f2 already did the clip-space side-plane clip; the 9f95252 eye-in-portal flood band-aid is still in — reassess only after Problem B is understood).
  • The boom drift (Part 1) was real but is NOT the visible flicker. Freezing the boom did not change the user-visible symptom.
  • The 3-part plan's framing (flicker = boom + cell dead-zone; void = clip) was the previous-session hypothesis; this session's live evidence reassigns the dominant symptom to Problem B (shell sealing / flood root). Treat the plan's Parts 2-3 as superseded.

6. Canonical prior art (already documents Problem B — read these)

  • docs/research/2026-06-05-render-residual-a-shipped-core-inside-render-handoff.md"player in cellar, eye in room → clipRoot=room → flood doesn't reach the cellar → cellar floor drops. NEXT = the CORE inside render (R1 completion)." THE pointer.
  • docs/superpowers/specs/2026-06-02-render-pipeline-redesign-design.md §2 (the binary RenderNormalMode model), §3 (grey = SHELL-SEALING bug; [shell] probe + dat dump), §5 (the two-camera invariant — and the doc/handoff contradiction to settle, §2 above).
  • memory/reference_render_pipeline_state.md — Residual A made the viewer cell accurate, which exposed that the flood doesn't reach the player's cell. (This session is more evidence for that.)
  • memory/feedback_render_one_gate.md + memory/feedback_verify_render_seal_before_layering.md — get a SCREENSHOT + [shell] evidence EARLY; one gate for all geometry.
  • memory/feedback_render_downstream_of_membership.md — a transition flicker can be a membership/ flood-root bug, not a render bug.

7. Kickoff prompt (copy-paste)

Continue acdream M1.5 indoor render in worktree thirsty-goldberg-51bb9b (branch
claude/thirsty-goldberg-51bb9b, HEAD 2b7f5a1). Do NOT branch/worktree; do NOT push without asking;
NEVER git stash/gc. PowerShell on Windows; launch logs are UTF-16. Running the client: see CLAUDE.md;
+Acdream spawns at the Holtburg cottage.

TARGET BUG (the user's real pain, with a screenshot): standing INSIDE the cottage, the floor draws but
the WALLS are grey (the time-of-day clear color) with NPCs/doors/outdoor-slices showing through; in the
CELLAR the FLOOR is missing (grey); flicker when changing rooms / entering the cellar. This is the KNOWN
"R1-completion" SHELL-SEALING / wrong-flood-root problem, NOT the camera boom and NOT the inside/outside
branch (both partially fixed this session).

READ FIRST (in order):
1. docs/research/2026-06-05-shell-sealing-cellar-floor-handoff.md  (THIS handoff — the two problems §1,
   the decisive root=0171/playerCell=0174 evidence §2, the next diagnostic step §3, the DO-NOT-RETRY §5).
2. docs/research/2026-06-05-render-residual-a-shipped-core-inside-render-handoff.md (the R1-completion
   pointer) + docs/superpowers/specs/2026-06-02-render-pipeline-redesign-design.md (§2/§3/§5).
3. memory: reference_render_pipeline_state, feedback_render_one_gate,
   feedback_verify_render_seal_before_layering, feedback_render_downstream_of_membership.

DO (evidence first — this bug has burned many speculative fixes; do NOT add a workaround):
- Reproduce + capture with ACDREAM_PROBE_FLAP=1 ACDREAM_PROBE_SHELL=1 ACDREAM_PROBE_VIS=1, player in the
  CELLAR with the camera up in the room. Pin: (1) is the player's cell (0174) in the visible set? (2) if
  so, does its shell DRAW ([shell] probe) or is a floor polygon missing/back-facing (dat-dump the 0174
  EnvCell mesh, design doc §3)? (3) is acdream's viewer_cell wrong — should retail's collided viewer_cell
  be the cellar (0174), not the room (0171)? (See §2 a/b/c — settle the design-doc-vs-handoff
  viewer-cell-vs-player-cell contradiction against the decomp: RenderNormalMode 0x453aa0 / update_viewer
  0x00453ce0 / what sets viewer_cell.)
- THEN fix the actual cause (camera-cell-resolution keeping the eye in the player's cell, OR the flood
  reaching the player's cell, OR the mesh seal) — retail-faithful, TDD where the logic is pure,
  visual-verify with the user.

DON'T (§5, evidence-disproven): the flicker is NOT viewer-cell oscillation (Part 2 dead-zone is NOT the
fix); the doorway grey is NOT the portal projection (it projects full-screen while OutsideView is empty);
the boom (Part 1) is not the visible bug. Get a SCREENSHOT/[shell] evidence EARLY; don't declare a fix
before the user's eyes confirm it.

TEST BASELINE: App 187p/0f. Core 1331p / 4f (documented) / 1s. Build green.

8. A note from the outgoing model (honest)

I repeatedly presented fixes with too much confidence and conflated Problem A (doorway grey, which I did reduce) with Problem B (the cellar/walls shell-sealing, which I did not touch). The user called this out correctly. The two committed changes are real and test-backed, but the next model should treat the user's screenshot symptom (walls + cellar floor grey, interior-transition flicker) as Problem B from the start, gather [shell]/[flap] evidence in the cellar BEFORE proposing anything, and get the user's eyes on a sealed result before claiming success.