docs(overhaul): bind S5 c1 clean evidence exception

Correct architecture and AD-21 to the existing transaction: normal non-login world frames participate, a walk contributes its exact landscape set, null-root completes an empty set without reconstruction, and login/portal-space retain no completed view.

Record the owner-authorized exception as in progress. Historical dirty-base artifacts remain preserved but clean exact-commit hermetic and InstalledDat evidence plus narrow review are still pending; no counts or hashes are invented.

Scope proof: no src or tests diff relative to b7a7eb9e2; git diff --check clean. No lanes or graphical client run by this commit.

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
This commit is contained in:
Erik 2026-09-04 17:00:26 +02:00
parent 36569c0b00
commit ad115141ab
4 changed files with 29 additions and 7 deletions

View file

@ -150,7 +150,7 @@ readiness/requeue adaptation. See
| AD-18 | Aperture far-Z punch is two-pass stencil-gated with an invented mark bias: 0.0005 NDC capped to a 0.5 m EYE-SPACE span (`MarkBiasNdc`); retail's single DEPTHTEST_ALWAYS punch is safe only under painter's far→near order we don't have | `src/AcDream.App/Rendering/PortalDepthMaskRenderer.cs:149` | **#117** (2026-06-11): the unconditional punch erased nearer occluders, painting interiors through them; the two-pass form is the z-buffered equivalent of retail's ordering safety. **#129** (2026-06-12): the constant-NDC bias spanned ~190 m of eye depth at a landblock (non-linear depth) → distant occluders punched; the eye-space cap bounds the reach (`Issue129PunchBiasTests`). DO-NOT-RETRY: punch must stay depth-gated (ISSUES #108) | Door-plane-hugging geometry beyond the 0.5 m cap re-occludes the aperture (a **#108**-class regression at >10 m viewing range); an occluder within the cap in front of a distant aperture still punches through | `D3DPolyRender::DrawPortalPolyInternal` 0x0059bc90 (maxZ1=7 / maxZ2=6) |
| AD-19 | Under outdoor roots, ALL dynamics draw in one z-buffered final pass; retail draws objects painter-ordered per landcell inside the landscape pass (interior roots route per **#118**) | `src/AcDream.App/Rendering/RetailPViewRenderer.cs:126` | The dynamics-drawn-LAST invariant is what makes the aperture depth punch safe (first BR-2 attempt punched after dynamics and erased the player, reverted `88be519`); z-buffer substitutes for painter's order on opaque geometry | Punch/seal correctness hinges on an ordering invariant — any pass added after DrawDynamicsLast, or alpha content needing painter order, gets erased inside apertures or composites wrong | `LScape::draw``DrawBlock` 0x005a17c0 → DrawSortCell pc:430124; `PView::DrawCells` 0x005a4840 |
| AD-20 | Camera sweep fallback seeds the eye's `AdjustPosition` from the PLAYER's cell; retail re-seats at the sought eye's own tracked cell (rest of function is a verbatim `update_viewer` port) | `src/AcDream.App/Rendering/PhysicsCameraCollisionProbe.cs:97` | acdream's camera doesn't track the sought-eye's cell separately; the eye is near the player so the player-cell stab list is assumed to cover it | An eye outside the player cell's stab-list coverage (boundary corners, cross-landblock pull-back) seats in the wrong cell — and the viewer cell roots the whole render: one-frame wrong root (flap-class flash) | `SmartBox::update_viewer` 0x00453ce0, pc:92878-92883 |
| AD-21 | Null-clipRoot legacy outdoor safety path (no portal visibility, no punches/seals, no-clip terrain) for debug/streaming-gap/legacy cameras; in-world retail always has a `viewer_cell` root | `src/AcDream.App/Rendering/WorldRenderFrameBuilder.cs` (`RuntimeWorldFrameRootSource`, `WorldRenderFrame.ClipRoot`); `src/AcDream.App/Rendering/WorldSceneRenderer.cs` (null-root safety draw) | Result is null ONLY when neither an interior root nor the synthetic outdoor node exists. Login is portal-covered and draws no live sky/world; a safety draw may render resident flat terrain/entities but publishes no cell-visibility answer | If viewer-root resolution ever returns null in-world (membership bug, fly-camera edge), the frame silently degrades — interiors stop drawing through doorways, outdoor particles fail closed, and the old two-branch FLAP reappears for that frame | `SmartBox::RenderNormalMode` decomp:92635; Campaign OVERHAUL S5-c1 |
| AD-21 | Null-clipRoot legacy outdoor safety path (no portal visibility, no punches/seals, no-clip terrain) for debug/streaming-gap/legacy cameras; in-world retail always has a `viewer_cell` root | `src/AcDream.App/Rendering/WorldRenderFrameBuilder.cs` (`RuntimeWorldFrameRootSource`, `WorldRenderFrame.ClipRoot`); `src/AcDream.App/Rendering/WorldSceneRenderer.cs` (null-root safety draw) | Result is null ONLY when neither an interior root nor the synthetic outdoor node exists. Every non-login normal-world frame participates in the completed particle-visibility transaction: a walk contributes its exact landscape set when present, while a null-root safety draw completes `hasCompletedView=true` with an empty landscape set and no reconstructed fallback. Login and portal-space retain `hasCompletedView=false`; the safety draw may still render resident flat terrain/entities | If viewer-root resolution ever returns null in-world (membership bug, fly-camera edge), the frame silently degrades — interiors stop drawing through doorways, outdoor particles fail closed, and the old two-branch FLAP reappears for that frame | `SmartBox::RenderNormalMode` decomp:92635; Campaign OVERHAUL S5-c1 |
| AD-22 | Async streamed mesh loading with bounded CPU replay residency, per-frame upload budgets, and point-of-use self-heal (`EnsureLoaded` re-request in the dispatcher's mesh-missing path, **#128**); retail loads synchronously — geometry is never absent | `src/AcDream.App/Rendering/Wb/WbMeshAdapter.cs`; `src/AcDream.App/Rendering/Wb/MeshUploadCaches.cs`; `src/AcDream.App/Rendering/Wb/MeshUploadFrameBudget.cs` | Immutable preparation descriptors and the bounded CPU cache can re-stage an evicted mesh; dispatcher self-heal makes absence transient while upload budgets prevent a portal arrival from monopolizing a frame | A future consumer that neither retains an owner nor reaches the self-heal/replay path can remain invisible; under heavy admission pressure a valid mesh can pop in later than retail's synchronous path | retail synchronous content load; `docs/architecture/worldbuilder-inventory.md` portal-readiness and bounded-residency seams |
| ~~AD-23~~ | **RETIRED 2026-09-03 at Campaign OVERHAUL v2 S3 review fix round 1 (`6575cfcee`).** The mechanism this row described — `ClipSlotCull` of live entities with `ServerGuid != 0` and null `ParentCellId` "while indoor clip routing is active" — is deleted with the per-cell clip routing itself (`SetClipRouting`, `_clipRoutingActive`, `ResolveSlotForFrame`'s routing arm): the routing had ZERO callers since the walk cutover, so the culling never ran, and the walk admits every part by retail's sphere test (`DrawMeshInternal` @0x0059f360) with cell membership owned by the S2 graph. Historical text: live entities with `ServerGuid != 0` and null `ParentCellId` were culled while indoor clip routing was active; retail objects are always cell-resident (synchronous add-to-cell at creation) | (deleted) formerly `src/AcDream.App/Rendering/Wb/WbDrawDispatcher.cs` `ResolveSlotForFrame`/`ClipSlotCull` | Phase U.4 policy: parentless = unresolved indoors, equivalent to retail's not-in-any-visible-cell ⇒ not drawn, *given membership resolves promptly* | An entity whose membership lags (late CreateObject hydration, resolver hiccup) blinks invisible while the player is indoors, even in plain sight | retail per-cell object lists in PView traversal |
| AD-24 | EnvCell shell geometry content-deduplicated and instanced; retail draws each CEnvCell's own structure directly | `src/AcDream.Core/Rendering/Wb/EnvCellGeometryIdentity.cs` | Phase A8 retained WB's 31× hash; the 2026-07-24 full-DAT gate proved a real collision (`0x00030175`/`0x01BC0105`), so App+Bake now share a namespaced FNV-1a tuple identity and the bake rejects any full-tuple collision | A future collision outside the installed full-DAT gate could still merge different shells at runtime; the stronger 59-bit payload makes this extremely unlikely, and every bake fails loudly rather than publishing it | retail `PView::DrawCells` → per-cell drawing_bsp (cited at the former renderer `:319`) |