docs(p1): visual-gate result — membership confirmed live; flap+void are render residuals
Some checks failed
Copilot Setup Steps / copilot-setup-steps (push) Has been cancelled

Standing/pacing the Agent of Arcanum doorway in the acdream client with ACDREAM_PROBE_CELL=1:
the player [cell-transit] sequence is clean + monotonic and crosses at the same Y thresholds as
retail's aligned golden, firing only on character movement (never camera-only). So P1 membership
is correct LIVE, matching the conformance proof.

The visible flap + purple void are the RENDER half, not membership: the flap is the camera-collision
residual (chase eye drifts out of the player cell -> viewer-cell flips; master-plan P3,
SmartBox::update_viewer), the void is the unported PView seal (master-plan P4). The user's intuition
"transition feels tied to the camera" is retail-faithful: retail keys the render on the viewer
(camera) cell, physics+lighting on the player cell.

Per user direction, P2 door collision is next; the render half (P3 camera -> P4 PView) follows.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
Erik 2026-06-03 21:30:02 +02:00
parent 9017107960
commit f0d37d8955

View file

@ -0,0 +1,74 @@
# P1 visual gate — membership CONFIRMED live; the visible flap+void is the render half (P3/P4)
2026-06-03. Companion to the P1 membership finding
([`2026-06-03-p1-membership-swept-advance-handoff.md`](2026-06-03-p1-membership-swept-advance-handoff.md)
— read its RESOLVED banner first). This note records the **visual-gate result** + the
render-residual diagnosis, so the eventual P3/P4 work has a clean pickup.
## TL;DR
- **P1 membership is correct — confirmed LIVE, not just in conformance.** Standing at / pacing the
"Agent of Arcanum" doorway (`0031↔0170↔0171`) in the acdream client with `ACDREAM_PROBE_CELL=1`,
the player `[cell-transit]` sequence is **clean + monotonic** and crosses at the **same Y
thresholds as retail's captured golden**. Transitions fire only on CHARACTER movement
(`reason=resolver`), never from camera-only movement. No ping-pong.
- **The visible "flap" + purple void are the RENDER half, not membership.** They are the documented
render residuals: **camera-collision (residual A → master-plan P3)** and the **PView seal
(master-plan P4)**.
- **User's intuition "transition feels tied to the camera, not the char" is CORRECT and
retail-faithful** — for *rendering*. Retail keys the render on the camera's cell (the "viewer
cell"); physics (where you walk) + lighting key on the player's cell.
## Visual-gate evidence (the player `[cell-transit]` log)
```
spawn: 0x00000000 → 0xA9B40031 @ (155.43, 17.87) teleport
in: 0031 → 0170 @ Y15.97 → 0170 → 0171 @ Y15.08
out: 0171 → 0170 @ Y15.22 → 0170 → 0031 @ Y16.11
... repeats cleanly for ~6 round trips, boundaries stable ...
```
Retail aligned golden boundaries (for comparison): enter room ~Y15.0515.15, leave room
~Y15.1815.23, leave building ~Y16.0716.14, enter building ~Y15.9616.06. acdream live matches.
So the **player cell** is retail-faithful and camera-independent.
## What retail does (render vs physics)
- **Render → viewer (camera) cell.** `SmartBox::RenderNormalMode` (`0x453aa0` pc:92635) decides
`DrawInside(viewer_cell)` vs `LScape::draw` on which cell the **camera eye** is in, then the
`PView` portal traversal floods visibility/seal from there.
- **Physics + lighting → player cell.** Collision keys on the player's swept `curr_cell`; lighting
on the player cell (`CellManager::ChangePosition`).
So "what you SEE follows the camera" is the retail design (the V1 invariant acdream already adopts:
render on viewer, lighting on player). The bug is NOT which cell drives the render — it's that two
pieces of the camera-driven render aren't ported:
1. **The FLAP = camera-collision residual (master-plan P3 / residual A).** Retail's 3rd-person camera
sweeps a small sphere backward from the head WITH collision (`SmartBox::update_viewer`
`0x453ce0` pc:92761), so the eye stays snug to walls and inside a sensible cell. acdream's chase
eye doesn't collide → it drifts through/behind the wall → when it crosses a cell boundary the
viewer-cell flips → the doorway flap. Intermittent because it depends on where the eye lands.
The handoff called camera-collision "the highest-leverage next step."
2. **The VOID = PView seal not ported (master-plan P4 / residual C).** Retail's `PView::DrawCells`
draws opaque cell walls + clips terrain/sky to the doorway opening (sealed interior). acdream's
render half isn't ported, so when the viewer-cell is wrong/unsealed you see the clear-color void
with NPCs + brazier floating in it.
## Pickup for the render half (when P3/P4 are scheduled)
- **P3 first (kills the flap):** port `SmartBox::update_viewer` (`0x453ce0` pc:92761) — the
spring-arm viewer-sphere sweep with collision → stable `viewer_cell`; + `find_visible_child_cell`
(`0x52dc50` pc:311397). Master-plan §2 C1/C3.
- **P4 (kills the void):** port `PView` (`ConstructView`/`InitCell`/`ClipPortals`/`GetClip`/
`DrawCells`), replacing `PortalVisibilityBuilder`/`ProjectToNdc`/`ScreenPolygonClip`. Master-plan
§2 D2D9.
- Apparatus ready: `ACDREAM_PROBE_CELL` (player `[cell-transit]`), `ACDREAM_PROBE_FLAP` (camera/viewer),
the aligned golden + conformance gate (`tests/AcDream.Core.Tests/Conformance/`).
## Status / next
P1 membership: **DONE** (correct by conformance + live visual gate). Per user direction (2026-06-03),
**P2 door collision is next** (the 3 failing Core door tests + 2 BSPStepUp, issue #97 — the
push-back bounce at the threshold; master-plan B3/B4). The render half (P3 camera → P4 PView) is the
path to "indoor world feels right" and follows P2.