park #177: retail cdb trace DISPROVES the portal-flood theory

Attached cdb to live retail (PDB MATCH), broke on PView::DrawCells (0x005a4840),
dumped cell_draw_num + cell_draw_list cell ids + the eye
(Render::FrameCurrent->viewer.viewpoint) while descending the Facility Hub spiral.
Retail's flood is dynamic and IDENTICAL in character to ours: from the spiral cells
it swings num 3->27 with gaze and collapses to 3 cells at many poses (cam=015d ->
{015d 015e 015f}). Our flood does the same (3->43). So retail does NOT keep the
staircase where we drop it -- the flood is exonerated as the cause.

Session trail (all in ISSUES #177): ruled out lighting, membership, camera coherence,
the collision sweep, the 0178/0182/0183 handoff cells, and edge-on eye-in-opening
(fix#1 shipped -> visual-gate-failed -> reverted, PortalVisibilityBuilder + AP-86 both
restored exactly). Freshest un-chased lead: the steps are STATIC objects (GfxObj
0x010000DE x6/cell) drawn via the viewcone cull, not cell shell.

Adds: Issue177StairDescentCameraFloodTests (real-camera+flood + composition +
flood-depth characterization pins) and a reusable retail-cdb capture toolchain
(tools/cdb/pview-verify.cdb, pview-spiral2.cdb with the correct top-level-qd detach --
qd in a CONDITIONAL bp action does NOT fire and strands cdb attached).

No production code change (fix#1 reverted). PARKED per user; M1.5 critical path next.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
Erik 2026-07-07 08:43:21 +02:00
parent c84dc49a63
commit 554af5042d
4 changed files with 678 additions and 1 deletions

View file

@ -299,7 +299,100 @@ investigation (`docs/research/2026-07-06-176-177-render-pair-investigation.md`).
## #177 — Dungeon stairs pop in/out across levels (invisible until entering the room; last step vanishes running down)
**⚠️ UPDATE 2026-07-06 (visual gate) — this is NOT lighting.** The A7 visible-cell
**🅿️ PARKED 2026-07-07** (user decision, after retail cdb disproved the portal-flood theory —
see session-3b below). NOT a blocker (cosmetic indoor pop). Ruled out with evidence: lighting,
membership, camera coherence, the collision sweep, the `0178/0182/0183` handoff cells, edge-on
eye-in-opening (fix#1 shipped→gate-failed→REVERTED), and the portal flood itself (retail's flood
collapses identically). **Freshest un-chased lead:** the steps are STATIC objects (GfxObj
`0x010000DE` ×6/cell) drawn via the separate viewcone cull, NOT cell shell — probe acdream's
step-static draw vs retail's. Characterization pins + the reusable retail-cdb capture toolchain
(`tools/cdb/pview-spiral2.cdb`, eye + `cell_draw_list` dump, clean top-level `qd` detach) are
committed. Resume from the session-3b block.
**⚠️ UPDATE 2026-07-07 (session 3b) — cdb-traced RETAIL; the PORTAL-FLOOD theory is
DISPROVEN by retail's own ground truth.** Attached cdb to live retail (PDB MATCH),
broke on `PView::DrawCells` (0x005a4840), dumped `cell_draw_num` + `cell_draw_list` cell
ids (`.data[i]->m_DID.id`) + the eye (`Render::FrameCurrent->viewer.viewpoint`) while the
user descended the spiral (`retail-spiral2.log`, 767 samples). **Retail's flood is dynamic
and IDENTICAL in character to ours** — from the spiral cells it swings `num` 3→27 with gaze
and COLLAPSES to 3 cells at many poses (e.g. cam=015d eye(60.05,-28.51,-3.66) → just
{015d 015e 015f}; cam=014b → {014b 014c 014a}). Our flood does the same (3→43, headless
`FloodDepthFrom015E_VsRetail26` = max 43 vs retail 26). So retail does NOT keep the spiral
where we drop it — the flood is EXONERATED as the cause. **The vanish must be DOWNSTREAM of
the flood** (unexplored): the steps in these spiral cells are STATIC objects (GfxObj
`0x010000DE` ×6/cell), drawn via the separate viewcone cull (`ViewconeCuller.SphereVisibleInCell`
/ `DrawCellObjectLists`), NOT the cell shell — acdream may cull those step statics where
retail doesn't. OR a per-pose clip difference at the exact descending gaze (would need
retail's gaze — not yet captured — to confirm, but the matching num RANGES argue against it).
cdb watchout CONFIRMED THE HARD WAY: `qd` in a CONDITIONAL bp action does NOT fire (stuck
cdb → had to kill it → took retail down). Reliable detach = bp action falls through to BREAK
after N (no gc), then top-level `qd` (`tools/cdb/pview-spiral2.cdb`). NEXT: probe acdream's
step-static (0x010000DE) draw/viewcone in the spiral vs the cell shell.
**⚠️ UPDATE 2026-07-07 (session 3) — fix#1 (edge-on eye-in-opening rescue) FAILED the
visual gate + REVERTED; [flood-collapse framing superseded by 3b — retail's flood collapses
the same way, so the flood is not the differentiator]. The mechanism is a GRAZING/SLIVER
FLOOD COLLAPSE in the tight SPIRAL staircase, NOT the edge-on-in-plane case.** Live [stair-clip]+[flap] capture
(`launch-177-stairclip.log`, PROBE_FLAP): the user's staircase is the `0x8A02` SPIRAL
`01C0→01C1→…→01C8→0210→…` (cells stacked z 0..6, joined by floor/ceiling portals + turning
via alternating ±Y wall portals; the recurring `0x010000DE`×6 statics are the steps). At the
vanish, root=`01C8`, vis collapses **12→3**: the DOWN floor-portal `→0210` goes OFF-SCREEN
(`clip=0`, D=3.75 — NOT edge-on) and the wall portals `→01C4/01C9` project to SLIVERS
(`clip=3`), so the flood barely spreads and 9 cells (the spiral) drop. Turning slightly
re-admits (portals swing on-screen); zoom-out gives a top-down shaft view (aligned floor
portals) → floods down → visible. **The camera is NOT collision-jammed**`[flap-sweep]`
`pulledIn=0.00` across all 103k frames, full boom, `collNormValid=False` — so it is purely
the flood/clip, from a NATURAL chase pose. This is the #119/#181 grazing/sliver-clip class.
**The retail contradiction (hit 3×):** retail draws only the flood (`PView::DrawCells`
`cell_draw_list`) and `polyClipFinish` also rejects <3-vert slivers so retail's flood
*should* collapse the same way, yet the user's retail shows the spiral. Something about
retail's viewpoint or flood in a spiral differs in a way NOT derivable from static analysis.
**NEXT: cdb-trace retail descending this spiral** (capture `PView::ConstructView`
`cell_draw_list` contents + `Render::FrameCurrent->viewer.viewpoint`) to see how retail keeps
the spiral flooded — the CLAUDE.md tool for "guessing failed twice." Characterization pins +
the [stair-clip] probe (reverted from the shipped path) live in
`Issue177StairDescentCameraFloodTests`. DO-NOT-RETRY: the edge-on eye-in-opening rescue
(fix#1) — the vanish D is never near 0; a camera-press fix — the sweep is never pulled in.
**⚠️ UPDATE 2026-07-06 (session 2) — [superseded by session 3; the edge-on sub-case below
is real but is NOT the production vanish]. ROOT CAUSE RE-DIAGNOSED with production-faithful
evidence; the two prior attributions below (lighting; then "flood-admission miss at
0178/0182/0183") are BOTH SUPERSEDED.** Findings, all evidence-backed (headless real-camera
harness `Issue177StairDescentCameraFloodTests` + production `[flap]/[flap-cam]/[vis]/[cell-transit]`
capture `launch-177-flapcell2.log`):
- **NOT membership, NOT camera coherence, NOT the collision sweep.** Across the whole
capture: `eyeInRoot=Y` on every frame (0 anomalies), the camera sweep never failed
(0 failures). The render root always contains the eye. My headless harness driving the
REAL chase camera + REAL sweep down the stairs = `collapses=0, incoherentFrames=0`.
- **The real staircase the user tests is `0x8A02015E/015F/01C1`** (stacked vertically,
joined by **floor/ceiling portals** N=(0,0,±1), 67 statics each) — NOT `0178/0182/0183`
(those have no statics, no floor portals). The handoff mis-identified the staircase.
- **The steps are cell SHELL geometry** (drawn whole/unconditionally when the cell is
admitted), so the vanish ⇒ the cell drops from the flood.
- **MECHANISM: you can flood DOWN a staircase but not UP it.** `[vis]` sets: root `01C1`
(top) ⊇ {015F,015E}; root `015F` drops `01C1`; root `015E` drops both `015F` AND `01C1`.
The up-cell dies at the **CLIP, never the side test** (root `015F``01C1`: CULL=0,
edge-on clip≤0 = 1508/1782). The chase-camera eye on a staircase sits at/near the cell
boundary = the floor/ceiling portal PLANE (local eye-z ≈ 6.0 = the ceiling, `D≈0`),
so the vertical portal projects EDGE-ON (collinear, <3 verts) `ClipPortalAgainstView`
rejects it → the stacked cell above never floods in → the whole staircase above the
camera vanishes. Descending puts the camera below the stairs (vanish); looking back
from the lower cell (vanish); zoom-out lifts the camera to a higher root that floods
DOWN (floor portals admit) → visible. It's the #119/#181 edge-on-clip class, on VERTICAL
(floor/ceiling) portals viewed from a boundary-height eye.
- **Retail complication (why the fix is NOT a naive clip relax):** `PView::DrawCells`
(0x005a4840) draws `cell_draw_list` (the portal flood), and `polyClipFinish` ALSO
rejects <3 survivors (docs/research/2026-06-11-polyclipfinish-w0-clip-pseudocode.md
lines 39,59). So retail's flood would drop an edge-on portal too — meaning retail's
eye must NOT sit edge-on with floor/ceiling portals (leading hypothesis: retail's flood
viewpoint is mid-cell / the player-eye at ~1.7 m above the floor, never in a floor
portal's plane; our chase-cam eye rides up to the ceiling portal). NEXT: confirm retail's
stair-camera eye height (cdb) OR the flood-seed viewpoint, then fix retail-faithfully
(camera-side keep-eye-off-portal-planes vs a narrow boundary-eye flood rule). DO NOT
relax `ClipToRegion`'s <3 gate (diverges from retail + risks #119/#181).
**⚠️ UPDATE 2026-07-06 (visual gate) — this is NOT lighting.** [SUPERSEDED by session-2
block above.] The A7 visible-cell
light-scoping fix shipped + was probe-validated, but the user's gate showed the stairs
STILL not visible looking back from the corridor (zoom-out changes the last-step case).
Eye-position/flood behavior ⇒ a portal-VISIBILITY miss at the stair cells