The plan's BR-1 ('implement the skipNoTexture draw-time surface gate')
died on its pre-check: acdream ALREADY suppresses every portal fill.
ReplicateProductionEmission_OnPortalFills replicates the exact emission
conditions of the production extractors on the hall/cottage fills:
pos=False neg=False for every one (Stippling.NoPos skips the positive
side at ObjectMeshManager.PrepareGfxObjMeshData:1046,
PrepareCellStructMeshData:1394, CellMesh.Build:44, GfxObjMesh.Build:71;
the fills have no negative surface). There is nothing to gate.
What ships instead: StipplingSurfaceEquivalenceTests - 2,607 polys across
13 building models + 13 environments, ZERO violations both directions:
NoPos <=> untextured-surface. Our build-time skip is proven equivalent to
retail's draw-time skipNoTexture rule (Ghidra 0x0059d4a4, default on
@0x00820e30) on this content. The pin fails loudly if future content
breaks the invariant - the cue to implement the draw-time gate then.
Corrections folded into the plan + comparison docs:
- The #113 phantom residual CANNOT be GfxObj fills (they never reach a
vertex buffer). Plausible true sites are cell-side: flood-admitted
cells drawn with the pass-all NoClipSlice when slot-less
(RetailPViewRenderer.cs:71), and/or cell statics drawn unclipped +
un-viewcone'd (object-lists-skip-portal-view-gate, confirmed).
BR-2 opens with the probe that pins which.
- The e46d3d9 user-gate observations (filter removed phantom/doors) were
confounded - the filter was a provable mesh no-op on shells AND doors.
- Ledger rows solid-surface-skip-missing + the acdream half of
portal-polys-baked-unconditional re-marked REFUTED-for-fills; the
retail mechanism descriptions and the un-consumed PortalIndex->
CBldPortal pairing (BR-4) stand.
Suites: Core 1398 green (1392 baseline + 6 new facts) + the 4 pre-existing
#99-era failures + 1 skip. No production code.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
438 lines
28 KiB
Markdown
438 lines
28 KiB
Markdown
# acdream vs retail — building/interior render architecture comparison
|
||
|
||
**Phase A deliverable of the holistic building-render investigation**
|
||
(mandate 2026-06-11: *"map acdream's way vs retail, then make a plan how to port
|
||
retail's way of doing it once and for all"*; charter:
|
||
[2026-06-11-building-render-holistic-port-handoff.md](2026-06-11-building-render-holistic-port-handoff.md)).
|
||
|
||
**Branch:** `claude/thirsty-goldberg-51bb9b`. **Method:** two ultracode workflow
|
||
fan-outs — 12 mapping areas (11 completed; transparency/sorting re-running),
|
||
~90 agents, every retail claim cited to Ghidra decompile (port 8081, verified
|
||
PDB program) / named pseudo-C (`pc:LINE`) / `acclient.h`, every acdream claim
|
||
cited `file:line`, one adversarial verifier per claimed divergence
|
||
(Ghidra-first; BN pseudo-C distrusted per project history). Raw per-area
|
||
mapping outputs (the full evidence record) live in
|
||
[`2026-06-11-holistic-map/`](2026-06-11-holistic-map/).
|
||
|
||
**Companion deliverable (Phase B):** the phased port plan at
|
||
[`docs/plans/2026-06-11-building-render-port-plan.md`](../plans/2026-06-11-building-render-port-plan.md)
|
||
— awaiting user approval before any implementation.
|
||
|
||
---
|
||
|
||
## 1. Executive summary
|
||
|
||
The investigation **confirms the mandate's premise and overturns two of our
|
||
working theories.** Retail has one drawing discipline; we have fragments of it
|
||
plus three mechanisms it doesn't use. The headline findings:
|
||
|
||
1. **Retail flattens GfxObjs and cells at load, exactly like we do.**
|
||
`CGfxObj::InitLoad` builds a flat D3D mesh from the *full* polygon
|
||
dictionary (`D3DPolyRender::ConstructMesh`, Ghidra 0x0059dfa0) and then
|
||
**deletes every non-portal node from the drawing BSP**
|
||
(`BSPTREE::RemoveNonPortalNodes`, Ghidra 0x0053a040). There is no per-frame
|
||
BSP traversal of ordinary geometry. Our flatten-at-decode global-VAO
|
||
pipeline is retail-faithful as a *base* — the bindless MDI architecture
|
||
survives the port intact.
|
||
|
||
2. **The phantom staircase and the vanished doors are one mechanism, and it is
|
||
a draw-time *surface* gate, not a poly filter.** Building/cell meshes skip
|
||
surface batches whose `CSurface.type` has neither `BASE1_IMAGE` (0x2) nor
|
||
`BASE1_CLIPMAP` (0x4) — the `skipNoTexture` rule (D3DPolyRender inner draw,
|
||
Ghidra 0x0059d4a0; default on, data 0x00820e30). Dat-confirmed on our side
|
||
(commit `e223325` + `DumpPortalFillSurfaceTypes`): **every** portal-fill
|
||
quad on all 13 Holtburg-area building models — door fills, window fills,
|
||
*and* the meeting-hall phantom stair-ramp — is `Base1Solid` (untextured).
|
||
Retail draws none of them, ever. The doors players see are **door
|
||
entities**. *(Execution-day correction, §5: acdream's extractors already
|
||
skip all of these via `NoPos` — proven equivalent to retail's rule by
|
||
`StipplingSurfaceEquivalenceTests`. The phantom residual is cell-side,
|
||
not these fills; see the §5 banner.)*
|
||
|
||
3. **Retail never geometrically clips cell or shell geometry. Pixel exactness
|
||
at apertures is a DEPTH discipline.** Production cell draws are whole
|
||
prebuilt meshes (`use_built_mesh`, `DrawEnvCell` pc:427905); the famous
|
||
`planeMask=0xffffffff` per-poly path is a legacy fallback whose mask means
|
||
*skip all clip edges*. What makes doorways pixel-perfect is:
|
||
**(a)** an invisible *depth punch* — the portal polygon, software-clipped
|
||
against the accumulated view, drawn depth-always/z-write/alpha-0 at far-Z
|
||
(`maxZ1`, opens a building aperture before its interior draws) or at its
|
||
true depth (`maxZ2`, seals indoor exits after the landscape draws);
|
||
**(b)** far→near cell order with a draw-once frame stamp; **(c)** the
|
||
z-buffer. This **reframes #114**: our `gl_ClipDistance` shell chop was
|
||
chasing retail's fallback path. The accumulated portal views exist for
|
||
*admission*, *object culling*, and *punch shapes* — never to cut geometry.
|
||
|
||
4. **Per-frame portal machinery is the heart, and we half-have it.** Building
|
||
shells draw in two passes (`DrawBuilding`, Ghidra 0x0059f2a0): a
|
||
portal-only BSP walk that dispatches each aperture through
|
||
`PView::DrawPortal` → `ConstructView(CBldPortal)` (eye-side vs
|
||
`portal_side` at ε=0.0002 → screen-clip vs the current view → cell-loaded
|
||
check) — flood + punch on success, *nothing* on failure — then the whole
|
||
shell mesh. The `PortalRef.PortalIndex` in the dat indexes the building's
|
||
`CBldPortal` array via `outdoor_portal_list` (pc:433920). Our flood port
|
||
(R-A1/A2/A2b, keep-listed) already implements faithful analogues of the
|
||
admission gates; what's missing is the *trigger* (we use a 48 m seed
|
||
constant instead of the shell's own draw), the *depth machinery* (punch
|
||
path exists as an unwired no-op), multi-view union (first-wins drops
|
||
second apertures), and per-view object culling (`viewconeCheck`).
|
||
|
||
5. **The adjunct systems diverge in ways users feel.** Camera: retail's boom
|
||
damping interpolates *from the published collided viewer* each frame —
|
||
shorten-fast/ease-out is emergent; we damp from our own previous damped
|
||
eye, severing that feedback (**#115 root cause, verified**). Lighting:
|
||
retail bakes *all* static cell lights per-vertex and adds a viewer light;
|
||
we cap at 8 viewer-nearest dynamic lights and sun-light interiors when the
|
||
player-cell gate says "outside" (unverified, high-confidence). Collision:
|
||
retail registers objects into per-cell shadow lists via a sphere-overlap
|
||
portal flood at registration; our landblock-wide registry is the #99/A6.P4
|
||
debt (**verified**, design corrections noted in the area file).
|
||
|
||
**Bug attribution coverage:** #113 phantom class → finding 2; #114 indoor crop
|
||
→ finding 3; doors-vanish mystery → finding 2 (solved, `e223325`); #108
|
||
grass-sweep → missing aperture depth seal + scissored AABB clear (finding 3);
|
||
#109 far-door oscillation → 48 m flood pop + first-wins view loss + missing
|
||
punch (findings 3–4); particles-through-walls → scissor-AABB gating instead of
|
||
per-view cone culling (finding 4); #99 doors run-through → finding 5
|
||
(collision); #115 camera drag → finding 5 (camera).
|
||
|
||
---
|
||
|
||
## 2. The retail architecture (2013 client, decomp-cited)
|
||
|
||
What follows is the synthesis; each area file in
|
||
[`2026-06-11-holistic-map/`](2026-06-11-holistic-map/) carries the full
|
||
call-chains and citations.
|
||
|
||
### 2.1 Load time: flatten + prune
|
||
|
||
- `CGfxObj::InitLoad` (Ghidra 0x005346b0): `BSPTREE::RemoveNonPortalNodes`
|
||
prunes the drawing BSP to a skeleton of portal-bearing nodes, then
|
||
`D3DPolyRender::ConstructMesh` flattens **all** polygons (portal fills
|
||
included) into a surface-batched mesh. EnvCells get the same at
|
||
`CEnvCell::UnPack` (ConstructMesh at pc:311085).
|
||
- Portal polys live in the same polygon array; `BSPPORTAL` nodes reference
|
||
them as `CPortalPoly { portal_index, CPolygon* }` (acclient.h:39075) — the
|
||
dat's `PortalRef { PolyId, PortalIndex }` (our `e223325` finding).
|
||
|
||
### 2.2 Frame composition (outdoor root)
|
||
|
||
`SmartBox::RenderNormalMode` (0x453aa0): viewer in an EnvCell →
|
||
`DrawInside(viewer_cell)`; viewer outdoors → full-screen view + `LScape::draw`
|
||
→ per landblock `DrawBlock` → per land cell in view: `DrawLandCell` (terrain)
|
||
then `DrawSortCell` = `DrawBuilding(cell->building)` + `DrawObjCell(cell)` —
|
||
**a building draws exactly when its host land cell draws** (per-cell
|
||
interleave, far→near blocks; `CSortCell.building` is the one-building-per-cell
|
||
slot, acclient.h:31880).
|
||
|
||
### 2.3 The building two-pass + portal machinery
|
||
|
||
`RenderDeviceD3D::DrawBuilding` (0x0059f2a0):
|
||
1. `outdoor_pview->outdoor_portal_list = building->portals` — installs the
|
||
CBldPortal lookup the shell's portal polys index.
|
||
2. **Pass 1 (portals):** `CPhysicsPart::Draw(part, 1)` → the pruned BSP walk
|
||
(`build_draw_portals_only` modes 1 then 2) submits each portal poly →
|
||
`PView::DrawPortal` (0x005a5ab0) resolves
|
||
`outdoor_portal_list[portal_index]`, pushes fresh `portal_view` slots onto
|
||
every stab-list cell, and runs `ConstructView(CBldPortal)` (0x005a59a0):
|
||
- eye side vs `portal_side` at ε=0.0002 — in-plane rejects outright;
|
||
- `GetClip` — the portal polygon software-clipped against the **current**
|
||
view (full screen outdoors; a doorway slot if this building is itself
|
||
seen through a portal); empty → fail, *no distance constant exists*;
|
||
- `CEnvCell::GetVisible` — target cell loaded;
|
||
- success mode 1 → **far-Z depth punch** of the clipped aperture
|
||
(`DrawPortalPolyInternal`, alpha-0, depth-always, z-write, `maxZ1`);
|
||
- success mode 2 → recurse `ConstructView(CEnvCell)` (the BFS flood) and
|
||
`DrawCells` draws the interior into the punched aperture.
|
||
The `building_view` latch binds nested floods to the view slot they were
|
||
discovered under (saved/-1/restored around `DrawPortal`, pc:427906-427914).
|
||
3. **Pass 2 (shell):** `ObjBuildingOrBuildingPart=1`;
|
||
`CPhysicsPart::Draw(part, 0)` draws the whole constructed mesh — with
|
||
`skipNoTexture` skipping every untextured (solid) surface batch. Interior
|
||
pixels survive only inside the punched aperture.
|
||
|
||
### 2.4 The indoor flood + DrawCells
|
||
|
||
`PView::DrawInside` (0x005a5860): root view = full-screen quad;
|
||
`ConstructView(CEnvCell)` floods via `InitCell` (eye-side per portal,
|
||
ε=0.0002; entered-portal back-walk block) + `ClipPortals` (per accumulated
|
||
view: project portal, homogeneous Sutherland-Hodgman `polyClipFinish` —
|
||
near-W clip first, then each view edge; pixel-exact, no plane budget) +
|
||
`AddViewToPortals` (first discovery enqueues; growth propagates **in place**
|
||
via `AddToCell`/`FixCellList`/`AdjustCellView` with the `update_count`
|
||
watermark; termination from `copy_view`'s 1-pixel vertex dedup, not a cap).
|
||
A multi-portal cell accumulates a **list** of view polygons — union-as-list,
|
||
all views consumed downstream.
|
||
|
||
`PView::DrawCells` (0x005a4840):
|
||
1. If any outside views: `PortalList=&outside_view` → **`LScape::draw`** (the
|
||
landscape through the accumulated doorway views) → conditional full
|
||
**depth clear** (gated on `portalsDrawnCount`) → far→near per cell per
|
||
view: **z-seal** every portal leading outside (`other_cell_id==0xFFFF`) at
|
||
its true projected depth (`maxZ2`) — terrain seen through the door keeps
|
||
its pixels; interior geometry farther than the door plane z-fails inside
|
||
the aperture.
|
||
2. Cells far→near per view via `DrawEnvCell` — whole prebuilt mesh, drawn
|
||
once (`GetDrawnThisFrame` frame-stamp), **never clipped**.
|
||
3. Per cell: `PortalList = cell's view stack` → `DrawObjCell` — every object
|
||
sphere-tested per view by `Render::viewconeCheck` (0x0054c250: sphere vs
|
||
eye plane + each `view_vertex.plane`); objects are **culled, never
|
||
clipped**. Translucent batches defer to the AlphaList and flush sorted.
|
||
|
||
### 2.5 The adjuncts
|
||
|
||
- **Camera** (`wf2-camera-viewer.md`): `CameraManager::UpdateCamera`
|
||
interpolates the sought pose **from the published collided viewer**
|
||
(`PlayerPhysicsUpdatedCallback` passes `&this->viewer`) with
|
||
α = stiffness·dt·10 (stiffness 0.45); `SmartBox::update_viewer` re-sweeps
|
||
pivot→sought *every frame* (0.3 m sphere) and publishes the raw collided
|
||
stop + `viewer_cell = sphere_path.curr_cell`. No explicit boom smoothing
|
||
exists — the feel is emergent from the collided-feedback loop. Player mesh
|
||
fades over the 0.45→0.20 m approach band
|
||
(`SetTranslucencyHierarchical`).
|
||
- **Lighting** (`wf2-indoor-lighting.md`, unverified): per-cell static lights
|
||
burn into vertices; interiors are never sun-lit; a white viewer light rides
|
||
above the player; per-object light selection against object bounds.
|
||
- **Sky/weather/scenery** (`wf2-sky-weather-scenery.md`, unverified): weather
|
||
gates on `is_player_outside`; rain cylinder at world-absolute z; scenery
|
||
draws per land cell, participating in the same per-cell interleave.
|
||
- **Collision** (`wf1-interior-collision.md`, verified): registration builds
|
||
the cell set by a sphere-overlap **portal flood** (`add_shadows_to_cells` /
|
||
`find_cell_list` family); queries iterate per-cell `shadow_object_list`;
|
||
buildings dispatch through `CSortCell.building` (per-cell channel);
|
||
`check_building_transit` gates `other_portal_id >= 0` (sign-extension
|
||
Ghidra-proven — BN renders it unsigned, the invented-sign failure mode).
|
||
- **Picking** (`wf2-picking-selection.md`, unverified): object-sphere/poly
|
||
arbitration inside the draw traversal's visibility, not a parallel ray.
|
||
|
||
---
|
||
|
||
## 3. The acdream architecture today
|
||
|
||
Mapped in full in the area files; the short form, with keep/replace verdicts:
|
||
|
||
| Subsystem | Today | Verdict |
|
||
|---|---|---|
|
||
| Mesh pipeline (flatten → global VAO → bindless MDI) | `ObjectMeshManager` → `WbDrawDispatcher`, ~12-15 GL calls/frame | **KEEP** — matches retail's flatten-at-load |
|
||
| PView flood (admission) | `PortalVisibilityBuilder` — faithful homogeneous clipper, side tests, reciprocal clip, exact-match skip | **KEEP** (R-A1/A2/A2b + dac8f6a, conformance-gated) — adjust constants/heuristics per ledger |
|
||
| Flood trigger | 48 m per-building seed over Chebyshev≤1 landblocks, outdoor roots only | **REPLACE** with shell-draw-driven `DrawPortal` (retail has no distance constant) |
|
||
| Aperture enforcement | `gl_ClipDistance` shell chop (outdoor-scoped, #114) + scissored AABB depth clear + unwired `DrawExitPortalMasks` | **REPLACE** with retail depth punch/seal/clear discipline; shells draw whole |
|
||
| Portal-fill suppression | GfxObjs: none (fills drawn — phantom class); cells: build-time `NoPos`/`NoNeg` stippling drop | **REPLACE/ALIGN** with draw-time `skipNoTexture` surface gate (dat-confirmed equivalent on audited cells) |
|
||
| Object/particle visibility | Cell-membership buckets; particles scissor-AABB | **EXTEND** with per-view `viewconeCheck`; route particles through the same gate |
|
||
| Building physics/collision | Landblock-wide `ShadowObjectRegistry` + `b3ce505` gate (#99) | **REPLACE** per A6.P4 (verified, with corrections: signed `OtherPortalId` + `>=0` gate, per-cell building channel) |
|
||
| Membership / straddle gate / streaming / camera collision / znear / texture flush | P1 9/9 golden; `414c3de`; A.5; verbatim `update_viewer`; 0.1; `c787201` | **KEEP** (charter keep-list, re-confirmed by verifiers) |
|
||
| Visibility computations | **TWO live systems**: `CellVisibility.ComputeVisibilityFromRoot` (ACME BFS) *and* `PortalVisibilityBuilder` (verified) + legacy remnants (`InteriorRenderer`, `IndoorDrawPlan`, dual frustum impls) | **CONSOLIDATE** to one gate (PView) + delete dead paths |
|
||
| Camera boom | Damps from own previous damped eye; fade computed, never applied | **FIX** feedback anchor (#115, verified) + apply fade |
|
||
| Lighting | Single scene UBO, 8 viewer-nearest lights, player-cell sun gate | **EXTEND** per lighting area (burn-in, viewer light, interior sun mask) — pending verification |
|
||
|
||
---
|
||
|
||
## 4. The divergence ledger
|
||
|
||
76 divergences across 11 mapped areas (the 12th, transparency/sorting, is
|
||
re-running). Ranked within area; verification = adversarial re-derivation
|
||
(Ghidra-first). `UNVERIFIED` rows had their verifier interrupted by the
|
||
session token limit — a resume is in flight; treat them as high-confidence
|
||
mapped claims, not yet adversarially proven. Full evidence per row in the
|
||
area files.
|
||
|
||
### Where each open bug lands
|
||
|
||
| Bug | Primary divergences |
|
||
|---|---|
|
||
| #113 phantom geometry class | `solid-surface-skip-missing` (gfxobj), `portal-polys-baked-unconditional` (shells) |
|
||
| Door-vanish mystery | **SOLVED** — `e223325` + surface-type dump; same rows as #113 |
|
||
| #114 indoor crop | `shell-chop-vs-depth-discipline`, `missing-aperture-depth-punch`, `multiview-loss-first-wins`, `knife-edge-epsilon-and-rescue` (interior-cells) |
|
||
| #108 grass-sweep | `missing-portal-depth-fence` (culling, **confirmed**), `depth-clear-shape-and-order`, `eight-plane-budget-passall` |
|
||
| #109 far-door oscillation | `building-flood-seeding-48m-cutoff` (adjusted: pop mechanism confirmed, 48 m linkage unmeasured), `multiview-loss-first-wins`, `missing-portal-depth-fence` |
|
||
| particles-through-walls | `particles-not-cell-resident` (statics), `object-particle-gating` (interior-cells), `particles-third-gate-tier` (gates) |
|
||
| #99 door run-through | `registration-cell-set-not-portal-flood`, `flat-object-query-not-per-cell` (collision, both **confirmed**) |
|
||
| #115 camera drag | `boom-no-collided-feedback` (**confirmed**) |
|
||
| Indoor "feels right" (M1.5) | the six `indoor-lighting` rows (unverified) |
|
||
|
||
### Ledger (severity / verdict / one-line)
|
||
|
||
**Area 1 — GfxObj draw** (`wf1-gfxobj-draw.md`)
|
||
| Sev | Verdict | Divergence |
|
||
|---|---|---|
|
||
| CRIT | adjusted | `portal-poly-conditional-pass-missing` — no per-frame z-punch/z-seal/ConstructView pass on portal polys |
|
||
| HIGH | **REFUTED for fills** (BR-1 pre-check, §5 banner) | `solid-surface-skip-missing` — acdream's NoPos build-time skip already covers them, proven equivalent |
|
||
| MED | confirmed | `degrade-lod-scoped-to-humanoids` — retail degrades every non-player part per frame |
|
||
| MED | adjusted | `no-per-view-entity-pass` — no per-portal-view re-cull of objects |
|
||
| MED | confirmed | `stippling-semantics-divergence` — WB's NoPos/NoNeg side-drop vs retail batch flag + sides_type |
|
||
| LOW | adjusted | `no-frame-dedup` — no GetDrawnThisFrame frame-stamp |
|
||
|
||
**Area 2 — Building shells** (`wf1-building-shells.md`)
|
||
| Sev | Verdict | Divergence |
|
||
|---|---|---|
|
||
| CRIT | **acdream half REFUTED** (BR-1 pre-check); retail half + missing PortalIndex→CBldPortal pairing stand | `portal-polys-baked-unconditional` — fills are NOT drawn (NoPos skip); the un-consumed pairing remains real (BR-4) |
|
||
| CRIT | unverified | `no-per-slot-building-draw` — building never draws per view slot; floods not shell-draw-driven |
|
||
| HIGH | adjusted | `flood-gate-shape` — 48 m seed + 0.01 ε + eye-inside rescue vs retail's no-distance chain (analogues otherwise faithful) |
|
||
| HIGH | unverified | `aperture-depth-machinery` — far-Z punch missing; particles scissor-only |
|
||
| MED | confirmed | `building-not-in-physics-cell-graph` — per-cell building channel missing; `other_portal_id>=0` gate missing (sign-extension proven) |
|
||
| LOW | unverified | `leaf-cells-unported` — retail path itself appears dormant; do not port without runtime proof |
|
||
|
||
**Area 3 — Interior cells** (`wf1-interior-cells.md`)
|
||
| Sev | Verdict | Divergence |
|
||
|---|---|---|
|
||
| CRIT | unverified | `shell-chop-vs-depth-discipline` — we clip shell geometry; retail clips nothing (depth discipline) |
|
||
| CRIT | unverified | `missing-aperture-depth-punch` — DrawExitPortalMasks unwired; AABB far-clear wrong shape/value |
|
||
| HIGH | unverified | `multiview-loss-first-wins` — MergeBuildingFrame drops views; CellIdToSlot keeps slices[0] |
|
||
| HIGH | unverified | `eight-plane-budget-passall` — >8 edges → slot-0 PASS-ALL; scissor fallback unimplemented |
|
||
| HIGH | unverified | `knife-edge-epsilon-and-rescue` — 0.01 vs 0.0002 ε + non-retail 1.75 m full-view rescue |
|
||
| MED | unverified | `growth-requeue-vs-in-place` — re-enqueue + cap-16 vs retail in-place propagation + 1-px dedup floor |
|
||
| MED | unverified | `object-particle-gating` — membership-only culling; particles scissored |
|
||
| MED | unverified | `portal-poly-suppression-criterion` — build-time stippling vs retail draw-time surface gate |
|
||
|
||
**Area 4 — Statics + dynamics** (`wf1-statics-dynamics.md`)
|
||
| Sev | Verdict | Divergence |
|
||
|---|---|---|
|
||
| CRIT | unverified | `building-portal-polys-unconditional` — (cross-ref Area 2) |
|
||
| CRIT | adjusted | `particles-not-cell-resident` — owner-bucket + 2D scissor vs emitter-cell residency + per-slot cone |
|
||
| HIGH | confirmed | `single-cell-buckets-vs-shadow-parts` — one ParentCellId bucket vs register-in-every-overlapped-cell + draw-once |
|
||
| HIGH | confirmed | `shells-drawn-whole-in-retail-production` — the #114 reframe anchor |
|
||
| MED | confirmed | `no-per-slot-viewcone-for-meshes` |
|
||
| MED | **refuted** | `livedynamic-dropped-indoors` — claim did not survive; see area file |
|
||
| LOW | adjusted | `outdoor-objects-redrawn-per-slice` |
|
||
| LOW | adjusted | `per-cell-depth-sort-missing` |
|
||
|
||
**Area 5 — Culling/frame composition** (`wf1-culling.md`)
|
||
| Sev | Verdict | Divergence |
|
||
|---|---|---|
|
||
| CRIT | confirmed | `missing-portal-depth-fence` — the maxZ2 fence after the clear is absent; hook unwired |
|
||
| CRIT | adjusted | `approximate-portal-clip-for-landscape` — ≤8 GL planes + AABB scissor vs exact software clip |
|
||
| HIGH | adjusted | `depth-clear-shape-and-order` — per-slice scissored clears after all slices vs one gated full clear |
|
||
| HIGH | unverified | `portal-poly-conditional-draw` — (cross-ref Areas 1/2) |
|
||
| HIGH | adjusted | `building-flood-seeding-48m-cutoff` — pop mechanism confirmed; #109@48 m unmeasured |
|
||
| MED | confirmed | `entity-cull-no-portal-viewcone` |
|
||
| MED | adjusted | `weather-gate-player-vs-viewer` — rain through doorways while inside |
|
||
| MED | adjusted | `unattached-particles-dropped-outdoors` |
|
||
| LOW | confirmed | `global-passes-vs-per-cell-interleave` |
|
||
|
||
**Area 6 — Interior collision** (`wf1-interior-collision.md`)
|
||
| Sev | Verdict | Divergence |
|
||
|---|---|---|
|
||
| CRIT | confirmed | `registration-cell-set-not-portal-flood` — XY grid vs sphere-overlap portal flood |
|
||
| CRIT | confirmed | `flat-object-query-not-per-cell` — one radial query vs per-cell shadow-list iteration |
|
||
| HIGH | adjusted | `building-shell-as-shadow-object` — landblock-wide entries vs per-LandCell building channel |
|
||
| HIGH | confirmed | `check-other-cells-env-only` — retail runs env AND shadow objects per other cell |
|
||
| MED | adjusted | `a6p5-topology-widening` — wider than retail's straddle gate (pending A6.P4) |
|
||
| MED | confirmed | `single-landblock-grid-clamp` — registration clamps to own landblock |
|
||
| LOW | confirmed | `movement-reregistration-source` — fresh grid vs transition's own cell array |
|
||
|
||
**Area 2.1 — Camera/viewer** (`wf2-camera-viewer.md`)
|
||
| Sev | Verdict | Divergence |
|
||
|---|---|---|
|
||
| HIGH | confirmed | `boom-no-collided-feedback` — sought eye never re-anchors to published collided viewer (#115 root cause) |
|
||
| MED | confirmed | `player-fade-computed-not-applied` |
|
||
| LOW | confirmed | `sought-position-lacks-cell-identity` |
|
||
| LOW | adjusted | `camera-input-scalars-unverified` |
|
||
|
||
**Area 2.2 — Indoor lighting** (`wf2-indoor-lighting.md`) — all unverified
|
||
| Sev | Divergence |
|
||
|---|---|
|
||
| CRIT | `interior-sun-bleed` — interiors sun-lit when player-cell gate says outside |
|
||
| HIGH | `no-static-light-burnin` — interiors capped at 8 viewer-nearest lights vs all static lights baked |
|
||
| MED | `no-per-object-light-selection`; `no-viewer-light`; `surface-luminosity-diffuse-ignored` |
|
||
| LOW | `dynamic-entity-lights-unregistered` |
|
||
|
||
**Area 2.3 — Sky/weather/scenery** (`wf2-sky-weather-scenery.md`) — all unverified
|
||
| Sev | Divergence |
|
||
|---|---|
|
||
| CRIT | `outside-portal-zstamp-missing` — (same family as the depth fence) |
|
||
| HIGH | `weather-indoor-gate`; `particles-not-portal-clipped` |
|
||
| MED | `no-nested-building-flood-through-outside-view` |
|
||
| LOW | `outdoor-objects-flat-bucket`; `rain-anchor-z-relative`; `weather-enabled-toggle-absent` |
|
||
|
||
**Area 2.5 — Visibility-gates audit** (`wf2-visibility-gates-audit.md`)
|
||
| Sev | Verdict | Divergence |
|
||
|---|---|---|
|
||
| HIGH | confirmed | `object-lists-skip-portal-view-gate` |
|
||
| HIGH | confirmed | `indoor-shell-clip-disabled` — indoor roots have NO draw-side discipline today |
|
||
| HIGH | unverified | `particles-third-gate-tier` |
|
||
| MED | confirmed | `dual-live-visibility-computations` — ACME BFS + retail flood both run per frame |
|
||
| MED | adjusted | `landscape-redrawn-per-outside-slice` |
|
||
| MED | unverified | `flood-convergence-heuristics`; `drawportal-membership-rule-mismatch`; `livedynamic-invisible-under-interior-roots` |
|
||
| MED | confirmed | `exit-portal-mask-pass-dormant` |
|
||
| MED | adjusted | `legacy-outdoor-branch-remnant` — clipRoot==null second path |
|
||
| LOW | unverified | `dual-frustum-implementations` |
|
||
|
||
**Area 2.6 — Picking** (`wf2-picking-selection.md`) — all unverified, all ≤ medium
|
||
`pick-outside-draw-traversal`; `occluder-stricter-and-looser-than-retail`;
|
||
`no-poly-stage-no-poly-beats-sphere`; `no-selected-in-view-tracking`.
|
||
|
||
---
|
||
|
||
## 5. Mysteries resolved this session
|
||
|
||
> **⚠ EXECUTION-DAY CORRECTION (2026-06-11, BR-1 pre-check).** The claim that
|
||
> acdream *draws* the solid portal fills is **FALSE** — all four extraction
|
||
> paths skip `Stippling.NoPos` positive sides
|
||
> (`ObjectMeshManager.PrepareGfxObjMeshData:1046`,
|
||
> `PrepareCellStructMeshData:1394`, `CellMesh.Build:44`,
|
||
> `GfxObjMesh.Build:71`), and the fills have no negative surface
|
||
> (`ReplicateProductionEmission_OnPortalFills`: pos=False/neg=False for every
|
||
> fill). The equivalence pin (`StipplingSurfaceEquivalenceTests`, 2,607
|
||
> polys, 0 violations) proves our build-time skip ⇔ retail's draw-time
|
||
> `skipNoTexture` on this content. Consequences: the ledger rows
|
||
> `solid-surface-skip-missing` (Area 1) and the acdream half of
|
||
> `portal-polys-baked-unconditional` (Area 2) are **REFUTED for the fills**
|
||
> (the retail-side mechanism descriptions stand); the e46d3d9 user-gate
|
||
> observations were confounded (the filter was a provable mesh no-op on
|
||
> shells and doors); and the **#113 phantom residual is cell-side** —
|
||
> flood-admitted cells drawn with the pass-all `NoClipSlice` when slot-less
|
||
> (`RetailPViewRenderer.cs:71`) and/or unclipped un-viewcone'd cell statics
|
||
> (`object-lists-skip-portal-view-gate`, confirmed). BR-2 opens with the
|
||
> probe that pins which. The mapping agents missed the `:1046` skip — score
|
||
> one for "verify what call sites actually pass."
|
||
|
||
1. **Door-vanish (charter §4.1)** — SOLVED, dat-proven (`e223325` +
|
||
`DumpPortalFillSurfaceTypes`): the e46d3d9 filter walked only
|
||
`node.Polygons`, never `node.Portals` (`PortalRef`); every dropped poly was
|
||
a portal fill; all fills are `Base1Solid`; retail skips them via
|
||
`skipNoTexture`; visible doors are entities. **No static filter can be
|
||
correct** — and per the execution-day correction above, no filter was
|
||
*needed*: the fills were never drawn, and the gate's "doors vanished"
|
||
observation was confounded.
|
||
2. **#114's real shape (charter §4.2)** — retail does not crop indoor
|
||
geometry; it punches/seals depth at apertures and draws far→near. The
|
||
"admission-quality vs draw-quality regions" framing dissolves: regions
|
||
only ever needed to be admission-quality (+ punch shapes).
|
||
3. **#115 (charter §4.5)** — root cause confirmed: missing collided-viewer
|
||
feedback into the damping origin; plus the player fade is computed but
|
||
never applied.
|
||
4. **#108/#109 (charter §4 re-test list)** — concrete mechanisms named (depth
|
||
fence, clear shape, flood pop, view loss) — see ledger.
|
||
5. **Charter §4.3 (cottage entry transparency)** — not separately
|
||
investigated; the straddle gate + flood stability work landed earlier;
|
||
re-test after the port phases land.
|
||
|
||
## 6. Open questions carried into the port plan
|
||
|
||
The area files carry ~30 open questions; the load-bearing ones:
|
||
|
||
1. ~~Where does retail draw the textured fill of a building portal poly?~~
|
||
**Answered**: nowhere at Holtburg — all fills untextured
|
||
(`DumpPortalFillSurfaceTypes`). A dat-wide sweep should pin the invariant
|
||
before relying on it globally (plan P1 acceptance).
|
||
2. `LScape::draw` internals — does retail clip terrain polys against
|
||
outside views or only cull blocks/cells per view? (Affects how faithful
|
||
our per-slice terrain clip needs to be once the punch exists.)
|
||
3. `PView::DrawPortal` mode 3 (seal-on-failure) — who calls it; matters for
|
||
unstreamed interiors.
|
||
4. Window-type CBldPortals — do they flood (stab lists + GetVisible-able
|
||
targets)? Decides window treatment in P1/P4 gates.
|
||
5. `cdstW` near-W constant; `CBldPortal.sidedness` semantics; the
|
||
`DrawMesh` skipNoTexture else-branch latch — pin during P1/P2
|
||
implementation.
|
||
6. Dungeon same-volume overlap sweep — z-only indoor compositing assumes
|
||
non-overlapping cell volumes; one-off dat sweep before declaring P3 done.
|
||
|
||
## 7. Verification status + how to finish it
|
||
|
||
- 40/76 divergences adversarially verified (1 refuted, 11 adjusted with
|
||
corrected claims — the corrections are folded into this doc's ledger).
|
||
- Both workflows are resumable; a resume was launched for the remaining
|
||
verifiers, the transparency/sorting map, and both completeness critics
|
||
(run IDs `wf_475e012b-f74`, `wf_dd8381c7-c0a`). This doc's ledger should be
|
||
refreshed from the final JSONs when they land.
|