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>
This commit is contained in:
parent
2b7f5a16c6
commit
8116d101bc
1 changed files with 239 additions and 0 deletions
239
docs/research/2026-06-05-shell-sealing-cellar-floor-handoff.md
Normal file
239
docs/research/2026-06-05-shell-sealing-cellar-floor-handoff.md
Normal file
|
|
@ -0,0 +1,239 @@
|
||||||
|
# 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:
|
||||||
|
|
||||||
|
```powershell
|
||||||
|
$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.**
|
||||||
Loading…
Add table
Add a link
Reference in a new issue