acdream/docs/research/2026-06-05-render-residual-a-shipped-core-inside-render-handoff.md
Erik 02837ad5dc docs(A): wrap Render Residual A — handoff + roadmap for the core inside render
Residual A (camera collision = verbatim SmartBox::update_viewer) is SHIPPED +
user-kept (0ffc3f5/5177b54/9e70031). Wrap it and hand off to the render session:

- New canonical handoff (docs/research/2026-06-05-render-residual-a-shipped-core-
  inside-render-handoff.md): what A shipped, what A EXPOSED (the render roots at the
  viewer cell — clipRoot=CameraCell, GameWindow.cs:7322 — and A made that cell
  accurate, so the PVS flood from the viewer cell doesn't reach the player's cell →
  cellar floor drops), the reframing (the user's "step C" = the CORE inside render /
  R1 completion, NOT R2 outside-looking-in), the evidence-first job, KEEP/DON'T, the
  kickoff prompt.
- CLAUDE.md banner: A SHIPPED; next = core inside render (R1 completion).
- Render redesign spec: 2026-06-05 sync note (A shipped; R1 is actually incomplete —
  the bleed + cellar-floor drop are the unfinished flood/seal; next is R1, not R2).

The visible problems (bleed + the floor A exposed) are the same family: the inside
path still draws the whole outdoor world instead of retail's "inside → DrawInside
only". A faithful DrawInside seals them by construction (render spec 2026-06-02 §2).

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

216 lines
15 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# Handoff — Render Residual A SHIPPED; next = the CORE inside render (R1 completion) — 2026-06-05
> **Canonical pickup for the next (render) session. Read this FIRST.** Residual A (camera collision)
> is a faithful verbatim port of `SmartBox::update_viewer` — shipped, tested, user-kept. It made the
> render's viewpoint *accurate*, which **exposed** the real next problem with precision: the inside
> render does not flood/seal correctly from the (now-correct) viewer cell. The "step C" the user asked
> for is therefore **not** the handoff-era "C / outside-looking-in" — it is the **core inside render
> (R1 completion)**. Branch `claude/thirsty-goldberg-51bb9b`. PowerShell on Windows; launch logs are
> UTF-16 (`Select-String` / `rg --encoding utf-16-le`, NOT GNU grep).
---
## 0. TL;DR
- **SHIPPED (A):** verbatim `SmartBox::update_viewer` — indoor start-cell seated at the head-pivot
(`AdjustPosition``find_visible_child_cell`) + the two fallbacks + cellId==0 snap-to-player.
Commits `0ffc3f5` (spec) / `5177b54` (Core primitives) / `9e70031` (SweepEye orchestration). TDD,
11 new tests, no regression. User-kept (chose "Keep it" over revert).
- **The live-capture finding that scoped A:** A's V1 sweep *already* contained the eye (`eyeInRoot=Y`
99.75%, `viewerCell` never 0, indoor collide 97.6%). So A is a faithfulness completion, not a
visible-bug fix. The dominant inside-cottage **bluish void / see-through-to-other-buildings is NOT
the camera — it is the render seal.**
- **What A EXPOSED (the handoff's whole point):** the render roots at the **viewer cell**
(`clipRoot = visibility.CameraCell`, GameWindow.cs:7322; Phase W V1 "one viewpoint"). A made that
cell *accurate* (the eye's real, collided cell). So when you stand in the cellar but the eye is up
in the room, `clipRoot = the room`, and the PVS flood from the room **does not reach the cellar**
**the cellar floor drops.** Before A, `viewerCell ≈ playerCell` (the sweep started from the feet
cell), which *accidentally masked* this. The user accepted this interim floor-drop to keep the
faithful viewpoint.
- **NEXT = the core inside render (R1 completion):** make `DrawInside` flood + seal correctly from the
viewer cell. This fixes BOTH the **bleed** (point 1) AND the **floor** A exposed — they are the same
family. The locked design already exists:
[`docs/superpowers/specs/2026-06-02-render-pipeline-redesign-design.md`](../superpowers/specs/2026-06-02-render-pipeline-redesign-design.md).
- **Test baseline:** Core **1326 pass / 4 fail (documented) / 1 skip**; App **179 pass / 0 fail**.
The 4 Core fails are pre-existing (2× `DoorBugTrajectoryReplay` LiveCompare, `BSPStepUpTests.D4`,
`DoorCollisionApparatus`).
---
## 1. What shipped — Residual A (verbatim `SmartBox::update_viewer`, pc:92761)
| Commit | What | Layer |
|---|---|---|
| `0ffc3f5` | design spec (`docs/superpowers/specs/2026-06-05-residual-a-camera-collision-design.md`) | docs |
| `5177b54` | `CellTransit.FindVisibleChildCell` (CEnvCell::find_visible_child_cell pc:311397) + `PhysicsEngine.AdjustPosition` (CPhysicsObj::AdjustPosition pc:280009) | Core |
| `9e70031` | `ResolveResult.Ok` (surfaces `find_valid_position != 0`) + `PhysicsCameraCollisionProbe.SweepEye` orchestration (start-cell seating + fallback 1 + fallback 2 + cellId==0 snap-to-player) | Core + App |
The orchestration mirrors `update_viewer` end-to-end: indoor (`objcell_id >= 0x100`) seats the sweep's
start cell at the **head-pivot** via `AdjustPosition` (the cellar lip: feet in the low connector, head
up at floor level); sweep `pivot → sought-eye` from that start; on success `set_viewer(curr_pos)`,
`viewer_cell = curr_cell`; fallback 1 = `AdjustPosition(sought_eye)`; fallback 2 / no-cell = snap to
player, `viewer_cell = null`. `SweepEye` gained a `playerPos` arg (for the snap).
**Why A's visible payoff was nil this session (don't be surprised):** the seating only differs from the
feet cell when the feet are in a *thin connector* cell while the head is in a taller neighbour (the lip
— a transient). Two live captures: in the cottage room every frame had `start == cell` (0 seated of
80,605); in the cellar the seating *did* fire (1,687 frames, `start != cell`). No fallback ever fired
(`ok=False`: 0). So A is faithful + correct; its job was to make the viewpoint accurate, which it did.
## 2. The exposure (READ THIS — it is the bridge to the next phase)
The render roots + projects from **one viewpoint = the viewer cell** (Phase W V1, GameWindow.cs:7322,
7330-7333: *"the render root (clipRoot = the viewer cell). ONE viewpoint"*). `PortalVisibilityBuilder.Build(clipRoot, viewerEye, …)`
floods the PVS from `clipRoot`.
A changed `viewerCell` from `≈ playerCell` (V1, sweep from the feet cell) to **the eye's actual cell**
(seated at the pivot). Live proof, player in the cellar (`playerCell=0xA9B40174`):
```
[flap-cam] root=0xA9B40171 viewerCell=0xA9B40171 playerCell=0xA9B40174 eye=(155,12,96.5) player=(153,9,93) ×1466 frames
```
`clipRoot = viewerCell = 0171` (the room, where the eye is) while the player is in `0174` (the cellar).
The PVS flood from the room **does not reach the cellar** → the cellar floor (the player's cell) is not
drawn → **missing floor**. This is exactly the spec's predicted symptom: §1.3 + §8 call the grey/missing
cellar floor a **sealing bug** (the closed cell mesh not covering pixels, OR the flood not reaching the
cell). **Cause unconfirmed — confirm it first (evidence-first, §4 below).**
The **bleed** (point 1: walls bluish, other buildings/particles/NPCs visible through them from inside)
is the same family: the inside path still draws the **whole outdoor world** then layers cell shells on
top, instead of retail's "inside → `DrawInside` only" (spec §2). A faithful `DrawInside` makes the bleed
impossible *by construction*.
## 3. The reframing — "C" is the CORE inside render, not outside-looking-in
The handoff-era residual letters (A camera / B particles / **C outside-looking-in**) map onto the locked
render spec's phases as: A camera (DONE), B → **R1b** (#104 particles), **C → R2** (`DrawPortal`,
street→interior). **R2 is a LATER phase.** The visible problems the user is hitting — the bleed AND the
floor A exposed — are **R1 (the core per-cell `DrawInside` flood+seal)**, which shipped only *partially*
(2026-06-03: the flap fix + basic shells + inside-looking-out, but NOT the "inside → DrawInside only"
inversion, NOT the general-case flood from `viewerCell != playerCell`). **The next session finishes R1.**
## 4. The job (next session) — evidence-first, then verbatim PView
1. **Read the locked design + its 4 research docs (in the spec's "Read first" list):**
`docs/superpowers/specs/2026-06-02-render-pipeline-redesign-design.md`
`docs/research/2026-06-02-render-pipeline-redesign-handoff.md` (root cause, the three-gate failure) →
`…-retail-render-pipeline-full-reference.md` (the PView + `DrawCells` seal) →
`…-acdream-render-pipeline-inventory-and-failures.md` (the `WbDrawDispatcher.cs:1756` bypass, the
parallel BFS, the terrain Skip model) → `…-render-reference-crosscheck.md` (why WB two-pipe is wrong).
2. **Confirm the floor cause FIRST (do NOT guess — spec §8):** launch with `ACDREAM_PROBE_FLAP=1`
`ACDREAM_PROBE_VIS=1` `ACDREAM_PROBE_SHELL=1`; stand in the cellar, get the eye up in the room
(`viewerCell=room`, `playerCell=cellar`). Read `[vis]` (does `OrderedVisibleCells` include the cellar
when rooted at the room?) + `[shell]` (does the cellar shell draw?) + dump the cellar EnvCell mesh
(is the floor polygon present + front-facing?). This decides: **PVS-flood-not-reaching** vs
**cell-mesh-not-sealing**. Get a screenshot EARLY (memory `render-one-gate`).
3. **Port the PView seal/flood verbatim (spec §2 + §4):** the binary top-level decision (inside →
`DrawInside` only — removes the global outdoor pass → kills the bleed by construction) + the per-cell
`DrawInside` loop (landscape-through-door → conditional Z-only clear → per-cell shells → per-cell
objects → per-cell particles). Retail anchors: `RenderNormalMode` 0x453aa0, `PView::DrawInside`
0x5a5860, `ConstructView` 0x5a57b0, `DrawCells` 0x5a4840 (spec §11 has the full index).
4. **VALIDATE — visual gate (spec R1 gate):** Holtburg cottage + cellar — sealed interior (opaque walls,
**solid floor**, ceiling), sky/terrain through the door only, **no bluish void, no bleed** (no other
buildings/particles/NPCs through walls), no terrain under the floor. Build + Core(1326p/4f/1s)/App(179p) green.
## 5. KEEP / DON'T-REDO
**KEEP (do not reopen):**
- **Residual A** (the 3 commits). The viewer cell is now accurate — that is the *input* the render needs.
Do NOT revert it to mask the floor (the user explicitly chose to keep the faithful viewpoint).
- The Phase W V1 "one viewpoint" (clipRoot = viewer cell, project from the eye) — GameWindow.cs:7322-7338.
- The Stage-1 membership port + the blue-hole fix (`UpdatePlayerCurrCell`, player-only render-root).
- `PortalVisibilityBuilder` / `ClipFrame` / `EnvCellRenderer` / `TerrainModernRenderer` / the WB mesh
pipeline (spec §3 KEEP).
**DON'T:**
- Don't re-add a `CurrCell` write inside `ResolveWithTransition` / `ResolveCellId` (the blue-hole clobber).
- Don't reintroduce the WB two-pipe stencil / `isInside` gate / AABB grace-frame for the root (spec §8).
- Don't relax the faithful terrain `Skip` to "fix" the grey floor (spec §1.3 — it's a sealing bug, not a
terrain-clip bug).
- Don't jump to R2 (outside-looking-in / `DrawPortal`) — R1 (the inside seal+flood) is first.
## 6. KEY FILES + ANCHORS
```
RENDER (the next phase)
src/AcDream.App/Rendering/GameWindow.cs (OnRender ~7300-7610) ← clipRoot=viewerCell (7322); binary decision lives here
src/AcDream.App/Rendering/PortalVisibilityBuilder.cs ← the PVS BFS (KEEP; the flood to harden/port)
src/AcDream.App/Rendering/InteriorRenderer.cs ← per-cell DrawInside loop (partial)
src/AcDream.App/Rendering/EnvCellRenderer.cs ← per-cell shell mesh (Render(pass,{cellId}))
src/AcDream.App/Rendering/WbDrawDispatcher.cs (~1756) ← the ParentCellId==null bypass to delete
src/AcDream.App/Rendering/ClipFrameAssembler.cs / CellVisibility.cs
docs/superpowers/specs/2026-06-02-render-pipeline-redesign-design.md ← LOCKED design (§2 model, §4 seal, §7 phases, §11 anchors)
CAMERA (A — shipped, the input)
src/AcDream.App/Rendering/PhysicsCameraCollisionProbe.cs ← SweepEye = verbatim update_viewer
src/AcDream.Core/Physics/CellTransit.cs FindVisibleChildCell ← pc:311397
src/AcDream.Core/Physics/PhysicsEngine.cs AdjustPosition ← pc:280009
PROBES
ACDREAM_PROBE_FLAP=1 [flap-cam] root/viewerCell/playerCell/eyeInRoot + [flap] PVS BFS + [flap-sweep] camera (start vs cell, ok)
ACDREAM_PROBE_VIS=1 [vis] OrderedVisibleCells + OutsideView
ACDREAM_PROBE_SHELL=1 [shell] per-cell shell draw
ACDREAM_PROBE_CELL=1 [cell-transit] player CellId changes
```
## 7. RUNNING THE CLIENT (PowerShell; `+Acdream` spawns in the Holtburg cottage)
```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_VIS="1"; $env:ACDREAM_PROBE_SHELL="1"
dotnet run --project src\AcDream.App\AcDream.App.csproj --no-build -c Debug *>&1 | Tee-Object -FilePath launch.log
```
Build green BEFORE launching. Logs are UTF-16. Close gracefully (✕ / Alt+F4) so ACE clears the session in ~3-5s.
## 8. KICKOFF PROMPT (copy-paste for the next session)
```
Continue acdream M1.5 render work: the CORE INSIDE RENDER (R1 completion) — make DrawInside flood + seal
correctly from the viewer cell so the cottage/cellar interior is SEALED: no bluish void, no see-through-to-
other-buildings BLEED, and the CELLAR FLOOR draws. This is what the user means by "step C" — it is NOT the
handoff-era "C / outside-looking-in" (that is R2, a later phase). Branch claude/thirsty-goldberg-51bb9b
(do NOT branch/worktree; do NOT push without asking; NEVER git stash/gc). PowerShell on Windows; launch
logs are UTF-16 (Select-String / rg --encoding utf-16-le, NOT GNU grep). Use superpowers:systematic-
debugging; the render redesign DESIGN is already LOCKED (read the spec), so this is execution + an
evidence-first floor-cause confirmation, not a re-brainstorm.
READ FIRST (in order):
1. docs/research/2026-06-05-render-residual-a-shipped-core-inside-render-handoff.md (THIS handoff — what
A shipped, what A EXPOSED §2, the reframing §3, the job §4, KEEP/DON'T §5, files §6).
2. docs/superpowers/specs/2026-06-02-render-pipeline-redesign-design.md (the LOCKED design — §2 the one
model, §4 the seal mechanics, §7 phases/gates, §11 decomp anchors) + its 4 "Read first" research docs.
3. memory: reference_render_pipeline_state.md, feedback_render_one_gate.md,
feedback_render_downstream_of_membership.md, feedback_verify_render_seal_before_layering.md.
STATE: Residual A (camera collision) SHIPPED + user-kept (commits 0ffc3f5/5177b54/9e70031) — verbatim
SmartBox::update_viewer; the viewer cell is now ACCURATE. That accuracy EXPOSED the next problem: the
render roots at the viewer cell (clipRoot=visibility.CameraCell, GameWindow.cs:7322), and the PVS flood
from the viewer cell does NOT reach the player's cell when they differ (eye in the room, player in the
cellar → clipRoot=room → cellar floor not drawn). Same family as the bleed (the inside path still draws
the whole outdoor world instead of "inside → DrawInside only").
THE JOB (evidence-first, then verbatim PView):
1. Confirm the floor cause FIRST (spec §8 flags it unconfirmed): launch with ACDREAM_PROBE_FLAP/_VIS/_SHELL,
stand in the cellar with the eye up in the room (viewerCell=room, playerCell=cellar), read [vis]
(is the cellar in OrderedVisibleCells when rooted at the room?) + [shell] + dump the cellar EnvCell
mesh (floor poly present + front-facing?). Decide PVS-flood-not-reaching vs cell-mesh-not-sealing.
Screenshot EARLY.
2. Port the PView seal/flood verbatim (spec §2 + §4): the binary top-level decision (inside → DrawInside
ONLY — removes the global outdoor pass → kills the bleed by construction) + the per-cell DrawInside loop
(landscape-through-door → conditional Z-only clear → per-cell shells → per-cell objects → per-cell
particles). Anchors: RenderNormalMode 0x453aa0, PView::DrawInside 0x5a5860, ConstructView 0x5a57b0,
DrawCells 0x5a4840.
3. VALIDATE — visual gate: Holtburg cottage + cellar sealed (opaque walls, SOLID FLOOR, ceiling), sky/
terrain through the door only, NO bluish void, NO bleed. Build + Core(1326p/4f/1s)/App(179p) green.
DON'T: revert A to mask the floor (user chose to keep the faithful viewpoint); re-add a CurrCell write in
ResolveWithTransition/ResolveCellId (blue-hole); reintroduce the WB two-pipe / isInside gate / AABB grace
(spec §8); relax the faithful terrain Skip (spec §1.3 — it's a sealing bug); jump to R2 (outside-looking-in)
before R1 (the inside seal+flood) is done.
TEST BASELINE: Core 1326 pass / 4 fail (documented: 2× DoorBugTrajectoryReplay LiveCompare, BSPStepUpTests.D4,
DoorCollisionApparatus) / 1 skip. App 179 pass / 0 fail. Branch HEAD 9e70031 (+ this handoff commit).
```