docs(render): R-A2b plan — back-portal side-cull (Option B), verify-first B1/B2 pin
Reading retail InitCell (:432896) side test during writing-plans showed retail's flood is acyclic (the back portal fails the side test, so 0171<->0173 can't cycle). Our flood traverses the back portal -> the cycle -> the churn. Option B (user-chosen): cull the back portal like retail, keep the forward-portal void rescue, remove the dead cap. Phase 1 pins WHY the back portal is traversed (B1 eyeInsideOpening bypass vs B2 CameraOnInteriorSide convention) before the fix; spec REVISION updated A->B. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
3fd71a123c
commit
7b8a490da9
2 changed files with 321 additions and 6 deletions
|
|
@ -14,6 +14,34 @@
|
|||
|
||||
---
|
||||
|
||||
> ## ⚠️ REVISION (2026-06-09, writing-plans decomp pass): approach changed A → B (back-portal side-cull)
|
||||
> Reading retail `PView::InitCell` (`:432896`; side test at `:432962`) + `AddToCell` (`:433050`) during
|
||||
> plan-writing showed WHY retail never churns: its per-portal **side test culls the "back" portal** (the
|
||||
> doorway just flooded through — the viewpoint is on its exit side), so retail's flood is an acyclic tree
|
||||
> and the `0171↔0173` mutual cycle **cannot form**. Retail has **no** eye-in-opening bypass of that cull.
|
||||
>
|
||||
> Our flood forms the cycle because the back portal `0173→0171` **is traversed** where retail culls it
|
||||
> (`[pv-trace]`: `pop 0173 p0->0171 grew=True`). The re-enqueue churn (what §4 Option A targeted) is a
|
||||
> *consequence* of that non-retail cycle. The user chose the more-faithful **Option B**: cull the back
|
||||
> portal like retail (kill the cycle at its source), **keep** the forward-portal clip-empty void rescue,
|
||||
> and remove the now-dead `MaxReprocessPerCell` cap. **§4 (Option A coverage test) is superseded by §4-B
|
||||
> below.**
|
||||
>
|
||||
> **Open — WHY is the back portal traversed (this pins the exact fix; plan Phase 1 verifies before code):**
|
||||
> - **(B1) the bypass:** `EyeInsidePortalOpening` switches off the side-cull (`Build` lines ~208-216:
|
||||
> `!CameraOnInteriorSide(...) && !eyeInsideOpening`) when the eye is within 1.75 m of a doorway → fix:
|
||||
> drop `&& !eyeInsideOpening` from the side-cull (back portals cull; the *separate* clip-empty rescue at
|
||||
> `Build` ~241-250 still rescues FORWARD portals, so the 2026-06-05 void fix is preserved).
|
||||
> - **(B2) the side test itself:** `CameraOnInteriorSide` (`PortalVisibilityBuilder.cs:717-724`) returns
|
||||
> true for the back portal where retail's `InitCell` test (`eax_9 == portal_side`, `:432962`) culls it →
|
||||
> fix: align our side test to retail's convention.
|
||||
> - **Discriminator:** the back portal's signed distance `D` to the doorway plane at the churn frames —
|
||||
> `> 1.75 m ⇒ B2` (bypass is off; the side test passed on its own); `≤ 1.75 m ⇒ B1` (bypass in play).
|
||||
> At `root=0171`, `p1->0173` was measured at `D=-2.73 m` (bypass off) — *indicating B2* — but the churn
|
||||
> cluster was at a different eye pose with no captured `D`, so Phase 1 confirms before the fix.
|
||||
|
||||
---
|
||||
|
||||
## 1. Summary
|
||||
|
||||
The indoor **flap** (grey/background flashing through doorways while *moving*) is a portal-flood
|
||||
|
|
@ -25,12 +53,17 @@ the neighbour re-enqueues. It ping-pongs to the `MaxReprocessPerCell=16` cap, wh
|
|||
**arbitrary depth**. Because the cut depth depends on the exact eye position, sub-cm eye creep makes the
|
||||
visible cell set swing (2↔4 cells) frame-to-frame → the grey flap.
|
||||
|
||||
**The fix (Option A — approved):** port retail's *bounded* propagation. A candidate contribution that is
|
||||
**already covered by the neighbour's accumulated view does not count as growth** (no re-enqueue); only the
|
||||
**uncovered remainder** propagates. This mirrors retail, where a redundant contribution **clips to empty
|
||||
before `copy_view` appends it**, so the flood terminates structurally. Remove the `MaxReprocessPerCell` +
|
||||
`popCounts` band-aid (termination is now by construction). Keep re-processing of genuinely-new slices.
|
||||
Scope: `PortalVisibilityBuilder` only — no camera, rooting, clip-math, or seal change.
|
||||
**The fix — see the REVISION banner above: Option B (back-portal side-cull), not the Option A coverage
|
||||
test described in this paragraph.** Retail's flood is acyclic because its per-portal side test culls the
|
||||
back portal; our flood cycles because the back portal is traversed (sub-mechanism B1/B2 pinned by plan
|
||||
Phase 1). Fix: cull the back portal like retail (kill the cycle), keep the forward-portal clip-empty void
|
||||
rescue, remove the now-dead `MaxReprocessPerCell` + `popCounts` cap. Scope: `PortalVisibilityBuilder` only
|
||||
— no camera, rooting, clip-math, or seal change.
|
||||
>
|
||||
> _(Original Option A text, superseded — kept for the record:)_ port retail's *bounded* propagation: a
|
||||
> candidate contribution already covered by the neighbour's accumulated view does not count as growth; only
|
||||
> the uncovered remainder propagates. Mirrors retail's "redundant → empty before `copy_view`". This is a
|
||||
> non-retail mechanism bounding a cycle retail never forms — Option B removes the cycle instead.
|
||||
|
||||
---
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue