diff --git a/docs/plans/2026-09-01-campaign-overhaul-world-solidity.md b/docs/plans/2026-09-01-campaign-overhaul-world-solidity.md index 70fd9b33..50f88c32 100644 --- a/docs/plans/2026-09-01-campaign-overhaul-world-solidity.md +++ b/docs/plans/2026-09-01-campaign-overhaul-world-solidity.md @@ -680,7 +680,8 @@ Update immediately when a slice changes state. Chat is not the ledger. | S4-c2 attempts 1–5 | **ATTEMPT 1/5 CONSUMED; ATTEMPT 2/5 PASSED AND LANDED 2026-09-04** — reviewed implementation `daaeab0ba`; campaign stack `89f1e2676` → `9ccb61a8e` → `0aa166aa0` → `252886e84`; packet §17 | G3/G4 UNPASSED | Sequential retail/evidence then production/gate-honesty PASS. Fresh: Release 0W/0E; shader 32/32; affected 37/37; real allocation 2/2 at 0 B; production 239/239. Official no-retry hermetic 16,734/1: sole unchanged global `Console.Out` capture race, exact theory 2/2 isolated. InstalledDat 255/10 documented/1. Validation routes `selfgate-20260904-115818-s4c2-landed-route` and `selfgate-20260904-120025-s4c2-landed-g3b` PASS provisional. First soak failed on known #461/#462; retry and S4-c1 control both 9/9 graceful; stationary averages CPU p95 −0.01 ms, GPU p95 +0.16 ms, alloc p50 +1.2 KiB, update p95 −0.12 ms. Three attempts remain unused. | | S4-c3a | **LANDED 2026-09-04 after the owner-authorized §21 evidence exception.** Reviewed scratch stack `44e2bc227b` → `b6bf6c131` → `eea5793d2` → `14397b14c` → `359061b82` → `255194e90` → `9cfddf301`; campaign cherry-picks `a86ec73ec` → `8e0c6fb14` → `01674bcc7` → `8bd75ba31` → `b6b015604` → `316193043` → `67c76026e`. The earlier stop remains in history at `06b986622`. | G3/G4 UNPASSED | Final retail lens PASS; production behavior/lifecycle/allocation/scope clean. The narrow independent gate-honesty re-review PASS reproduced the exact first failure (AP-table-boundary `Assert.True`, `rowIndex=-1`, before `Assert.Single`), restored AP-241 byte-identically, and passed the pin 1/1. Fresh campaign: Release 0W/0E; focused class lane 96/96; no-surface 1/1; AP pin 1/1; real allocation 2/2 at 0 B; shader 32/32; `git diff --check` clean. No client launched. NEXT: write c3b's deletion-only contract from the landed code; G3 stays locked until c3b lands. | | S4-c3b | **LANDED 2026-09-04** — implementation `26e97ba41`, provenance contract `5110bf676`, packet-only correction `3f2f00c9f`; packet §22–§25. Dead classic-group `LocalSortCenters`/`CachedBatch.LocalSortCenter` storage and the alpha camera-parameter/digest chain are deleted. Live per-cell/particle CYpt keys, opaque `SortDistance`, building/private/portal distances, two FIFO lists, all state/barriers, and AP/AD rows remain. | **G3 LEAD SELF-GATE PROVISIONAL PASS; owner acceptance/owner-only rows pending. G4 UNPASSED.** | Retail/deletion lens PASS. Production lens found no code defect and one artifact-provenance omission; packet-only fix round 1 passed its narrow re-review. Fresh campaign: Release 0W/0E; App 132/132; Core 29/29; allocation 2/2 at 0 B; shader 32/32. G3: route 1 13/13, route 2 4/4, route 3 retry 3/3, all exit 0/graceful. The first route-3 attempt stopped before Nanto on registered #462. Exact PNG paths: packet §25. | -| S5 | — | G4 | fill | +| S5-c1 | **CONTRACTED 2026-09-04; implementation pending.** Packet `s5-consumers-material-closeout-packet.md` §§1–6. Exact landscape land-cell publication is separated from EnvCells; particle update ports `CLandCell::IsInView` vs constant-true `CEnvCell::IsInView`; AP-117's null-root frustum/AABB reconstruction and the dead point-light feedback seam are deleted; AP-85/AD-21 are corrected in the same implementation commit. | G4 UNPASSED | Lead verified the named pseudo-C and paired executable/PDB (GUID `{9E847E2F-777C-4BD9-886C-22256BB87F32}`, age 1): `ShouldDrawParticles @0x0050FE60`, `UpdateParticles @0x0051D180`, `CLandCell::IsInView @0x00532CB0`, and the CEnvCell vtable's ICF body `0x005269F0`. Directional shadows, building degrade, AP-232, probes, and closeout are later bounded chunks. | +| S5 | IN FLIGHT — c1 contracted; c2–c5 and closeout remain | G4 | Packet §7 is the bounded decomposition; never merge main before G4. | --- diff --git a/docs/research/2026-09-01-overhaul/s5-consumers-material-closeout-packet.md b/docs/research/2026-09-01-overhaul/s5-consumers-material-closeout-packet.md new file mode 100644 index 00000000..f8da7118 --- /dev/null +++ b/docs/research/2026-09-01-overhaul/s5-consumers-material-closeout-packet.md @@ -0,0 +1,259 @@ +# Campaign OVERHAUL v2 — S5 consumers, material, and closeout packet + +**Status:** S5-c1 CONTRACTED 2026-09-04; implementation not yet landed. +**Branch:** `claude/campaign-w-retail-frame-walk`. +**Gate:** G4 remains unpassed. Nothing merges to `main` before G4. + +This packet decomposes plan S5 into bounded chunks. The lead writes each +contract, a Sonnet implementer changes only that contract, the lead verifies +every retail claim against the named pseudo-C and the paired executable/PDB, +and the sequential review lenses run before landing. A chunk that needs a +third fix round stops and is written up. Every surviving deviation is entered +or corrected in the divergence register in the same implementation commit. + +## 1. Current boundary after S4 + +S4-c3b is landed and the lead G3 matrix is a provisional PASS; owner inspection +and the owner-only G3 rows remain. S5 must not reopen the green walk, portal +depth, or two-FIFO alpha ports without new evidence. + +The landscape half is already present and exact: + +- `WalkLandscape.CheckBlocks` / `LandCellCheck` port + `LScape::draw_check_blocks @0x00505F80` and + `LScape::landcell_check @0x005050A0`; +- `WalkVisibilityMath` owns the ported `get_clip_height` / `block_check` math; +- `WalkFrameDriver.VisitedLandscapeCellIds` is populated by the same one walk + that emits the retail-ordered terrain/object stream. + +S5-c1 therefore changes the consumers and deletes the competing fallback. It +does not rewrite the landscape calculation. + +## 2. Retail facts for S5-c1 (lead-verified 2026-09-04) + +The executable is `C:\Users\erikn\Downloads\acclient.exe`. Its CodeView record +is GUID `{9E847E2F-777C-4BD9-886C-22256BB87F32}`, age 1, matching +`refs/acclient.pdb`. + +### 2.1 `ShouldDrawParticles` is distance AND the cell virtual + +Named pseudo-C at `CPhysicsObj::ShouldDrawParticles @0x0050FE60` reads: + +```text +if examination: true +if CYpt > degrade_distance: false +if cell == null: false +if cell->IsInView() == 0: false +true +``` + +The paired bytes are the same: `fld [ecx+0x24]`, `fcomp [esp+4]`, the x87 +`test ah,0x41` gate, null-check of `[ecx+0x90]`, then the virtual call through +vtable slot `+0x68`. `ParticleEmitter::UpdateParticles @0x0051D180` calls that +function at `0x0051D1A1`; false enters the `SetNoDraw(1)` / `degraded_out=1` +arm, while true clears that state and updates/emits particles. + +Preserve the existing x87-compatible comparison, including inclusive equality, +unordered admission, raw negative/zero/NaN/infinity authored distances, and the +deliberate AP-116 range multiplier (`Retail=1`, default `Extended=2`). + +### 2.2 outdoor and indoor cells have different `IsInView` semantics + +- `CLandCell::IsInView @0x00532CB0` returns the 32-bit field at `+0x104`. + The paired body is exactly `mov eax,[ecx+0x104]; ret`. Landscape drawing + stamps that field, so particle update consumes the previous completed + render frame's landscape answer. +- `CEnvCell::IsInView` is the PDB-vtable slot at `0x007C8D00`, pointing to the + ICF-folded body `0x005269F0`. The paired body is exactly `mov eax,1; ret`. + Thus an indoor cell with a non-null owner is always `PARTIALLY_INSIDE` for + the update-time check; its particle drawing remains separately controlled + by the cell walk. + +AC cell identity already has a production-pinned discriminator: +`low = cellId & 0xFFFF`; outdoor land cells have `0 < low < 0x0100`, EnvCells +have `low >= 0x0100`, and zero is no cell. + +### 2.3 point lights do not consume the camera walk + +Retail collects point lights from the DBObj-load/flush-bounded resident +`CEnvCell::visible_cell_table`, not from the current camera portal flood. +Current `LightManager.BuildPointLightSnapshot(playerWorldPos)` likewise uses +the resident registry. `RuntimeWorldFrameEnvironmentPreparation`'s +`ObserveDrawableCells` / `ClearDrawableCells` methods are now no-ops, while +AP-85 still describes the deleted last-frame filter. The methods and the stale +claim are tombstones, not behavior. + +### 2.4 the null-root terrain reconstruction is not a retail answer + +In-world retail has a viewer-cell root. acdream's null-root path is the AD-21 +streaming-gap/debug safety draw. `TerrainModernRenderer.CollectVisibleCells` +manufactures 64 land-cell ids per retained landblock from camera-frustum AABBs +and publishes them through `TerrainVisibleCellIds`. That is the only remaining +AP-117 reconstruction. A safety draw with no walk product must publish no +outdoor `IsInView` answer; it must not invent one. + +## 3. S5-c1 contract — typed `IsInView` consumers and fallback deletion + +### 3.1 C1 — publish the landscape half explicitly + +Extend the borrowed `RetailPViewFrameResult` with the exact landscape land-cell +set from `WalkFrameDriver.VisitedLandscapeCellIds`. Keep `DrawableCells` for +EnvCell shell preparation and keep the existing union `VisibleCells` only for +diagnostics that compare the two products. Do not re-filter, re-walk, sort, or +derive the landscape set from projection/entity ids. + +Rename the particle handoff to make the type visible in the API, for example +`MarkVisibleLandscapeCells`. It accepts only outdoor land-cell ids and copies +them into the controller's building frame. Passing zero or an EnvCell id is a +contract violation, not something to silently reinterpret. + +The completed frame remains the sole retained owner. `AbortFrame` preserves +the prior completed product, `CompleteFrame` publishes the new product, and +`Reset` removes both generations. The update thread continues to call `Apply` +before the next render, preserving retail's previous-frame timing. + +### 3.2 C2 — evaluate the correct virtual by cell family + +Change `ParticleSystem.ApplyRetailView` so a world-policy emitter is eligible +only when all of the following are true: + +```text +hasCompletedView +ownerCellId != 0 +(owner is EnvCell OR exact completed landscape set contains ownerCellId) +retail x87-compatible distance predicate +``` + +EnvCell means `low >= 0x0100`; landscape means `0 < low < 0x0100`. +Examination and dedicated-pass policies keep their existing bypass. This is an +update/degrade correction only: do not alter emitter-own-cell draw membership, +per-cell particle turns, cone admission, queue routing, alpha order, lifetime, +or tick order. + +A completed null-root safety frame has an empty landscape set. EnvCell owners +still see their constant virtual result; outdoor owners fail closed. Login and +portal-space frames still carry `hasCompletedView=false` and reject ordinary +world-policy emitters. + +### 3.3 C3 — delete AP-117's remaining reconstruction + +Delete the complete `TerrainModernRenderer.CollectVisibleCells` route, +including `_visibleCellIds`, `VisibleCellIds`, `BeginVisibilityFrame`, +`IWorldScenePassExecutor.TerrainVisibleCellIds`, the null-root publication in +`WorldSceneRenderer`, and the reconstruction-only tests. The flat terrain draw +itself remains; only its fabricated visibility side channel goes. + +After this deletion, AP-117 is retired: the walk path publishes the ported +landscape product, and frames without that product publish none. Update AD-21 +in the same commit so it no longer claims the login screen shows live sky and +states that the safety draw cannot publish cell visibility. + +### 3.4 C4 — delete the dead point-light feedback seam + +Delete `ObserveDrawableCells` and `ClearDrawableCells` from +`IWorldRenderFrameBuilder`, `IWorldFrameEnvironmentPreparation`, their runtime +implementations, all calls, fakes, and tests. Keep point-light snapshot +selection exactly resident-registry based. Correct AP-85 in the same commit to +the code that actually remains: one resident, player-nearest 128-cap pool +instead of retail's separate 7-dynamic/40-static pools and DBObj-granular +residency. AP-68's owner-approved always-lit-interior policy is unchanged. + +### 3.5 Explicit non-changes + +S5-c1 must not change: + +- `WalkLandscape`, `WalkVisibilityMath`, block/cell order, landscape event + order, terrain draws, membership, portal flood, depth, alpha, shaders, RHI, + DAT/package code, or streaming ownership; +- point-light capacity, sort anchor, curves, cell/object selection, or AP-68; +- directional-shadow selection (S5-c2 owns that consumer and its retained + topology/per-frame visibility design); +- building degrade/complete-body selection (later S5 chunk); +- translucent-detail material combine/AP-232 (later S5 chunk); +- Facility probe and broader cleanup inventory (later S5 cleanup chunk). + +No graphical client is launched from the implementation or review worktree. + +## 4. Allowed files + +Production changes are limited to the directly affected files: + +- `src/AcDream.Core/Vfx/ParticleSystem.cs`; +- `src/AcDream.App/Rendering/Vfx/ParticleVisibilityController.cs`; +- `src/AcDream.App/Rendering/RetailPViewRenderer.cs`; +- `src/AcDream.App/Rendering/WorldSceneRenderer.cs`; +- `src/AcDream.App/Rendering/WorldScenePassExecutor.cs`; +- `src/AcDream.App/Rendering/WorldRenderFrameBuilder.cs`; +- `src/AcDream.App/Rendering/TerrainModernRenderer.cs`; +- comment-only truth correction in `WalkFrameDriver.cs` if required. + +Tests may change in the directly affected Core/App VFX, renderer, frame-builder, +and terrain-visibility files, plus compile-fallout fakes for the deleted +interfaces. Documentation is limited to this packet, the plan ledger, +`acdream-architecture.md`, `oh1-construction-landscape-contract.md`, and the +divergence register. If implementation requires another production owner or a +new deviation, stop and return the fact before expanding scope. + +## 5. Tests and mutation evidence + +Extend production-facing tests to prove: + +1. an outdoor emitter is admitted only by the exact completed landscape set; +2. an EnvCell emitter remains update-eligible at authored range even when no + indoor cell is in that set; +3. zero cell and no completed world view reject both cell families; +4. inclusive/unordered/raw-distance behavior and AP-116 Retail/Extended + multipliers remain unchanged; +5. `WorldSceneRenderer` hands only `RetailPViewFrameResult`'s landscape set to + the particle owner, never the EnvCell set or diagnostic union; +6. abort/complete/reset preserve the previous-frame transaction; +7. no production `CollectVisibleCells`, `TerrainVisibleCellIds`, + `ObserveDrawableCells`, or `ClearDrawableCells` symbol remains; +8. point-light snapshots still include resident lights regardless of the + removed feedback set; +9. the warmed production particle-view path allocates 0 managed bytes. + +Every new pin gets a real sabotage and exact first failure in the implementer +commit body. At minimum mutate independently and restore exactly: + +- make EnvCell eligibility depend on set membership; +- make outdoor eligibility constant true; +- feed the union instead of the landscape set at the renderer call site; +- restore one `CollectVisibleCells` production symbol; +- restore one `ObserveDrawableCells` production symbol; +- invert or exclude the inclusive authored-distance boundary. + +## 6. Automated return and reviews + +Implementer return: + +- `git diff --check`; +- Release solution build, 0 warnings / 0 errors; +- focused Core VFX and App particle/frame/renderer/terrain tests; +- the real warmed 0-B particle-view pin; +- official hermetic lane; +- InstalledDat lane with exactly the documented global failure/skip set and no + new failure; +- one clean commit, exact files/counts, and all mutation first failures. + +Sequential review 1 — retail fidelity: re-check the named pseudo-C and paired +bytes above, the CEnvCell vtable/ICF identity, previous-frame timing, cell-id +discriminator, and every preserved x87/AP-116 edge. Review 2 — architecture, +production, and gate honesty: prove one retained product, typed call-site +reachability, no reconstructed/null-root answer, no point-light behavior +change, reset/abort/lifecycle correctness, 0-B steady state, allowed scope, all +register prose, all gate counts, and at least three mutation claims. A failed +lens receives one bounded fix contract; a third fix round stops the chunk. + +## 7. Remaining S5 decomposition after c1 + +1. S5-c2: exact landscape visibility consumption by directional-shadow caster + selection without creating a second set or rebuilding retained topology on + every camera-only change. +2. S5-c3: retail `DrawBuilding` degrade selection and complete-body null gate. +3. S5-c4: translucent detail single-stage framebuffer equivalence; retire + AP-232. +4. S5-c5: delete Facility probes, production `PortalVisibilityBuilder` + residue, obsolete fallbacks/flags/tests/claims; add architecture guards. +5. S5 closeout: full automated/lifecycle/performance program, G4 owner matrix, + documentation closeout, then and only then merge to `main`.