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 5ab4a75e..26d348e7 100644 --- a/docs/plans/2026-09-01-campaign-overhaul-world-solidity.md +++ b/docs/plans/2026-09-01-campaign-overhaul-world-solidity.md @@ -660,7 +660,7 @@ Update immediately when a slice changes state. Chat is not the ledger. | S1 Geometry | **CLOSED — G1 PASSED 2026-09-02** | `oh2-cellstruct-surface-contract.md` (§3.5 arbitrated on the binary) | chunk A `acf17246`; chunk B `b681717c`; hygiene `0840d5fb`; review fixes `e2543d0e`; G1 regression fix `8c6563ca` (segment/batch pairing) + its pin test (next commit) | lead verified both chunks against the named pseudo-C and the paired binary; two Opus lens reviews, 8 findings all verified by the lead and fixed; the review round's own upload-order change desynchronized cell-shell index segments from batches (first G1 launch: magenta/stretched/missing walls in every dungeon) and was root-caused and fixed by the lead before the re-gate | build 0/0; Content 213/213 (incl. PreparedPackage on the recipe-8 pak); Core 4,948/4,948 (one load-sensitive allocation test outside S1 passes alone); Bake 21/21; Launcher.Core 365/365; Runtime 1,884/1,884; App hermetic 6,757/6,757 | **G1 PASS**: Facility Hub stairs/doorways, Holtburg house interior, ordinary dungeon, town portal network all whole with correct materials on `8c6563ca` + recipe 8; cathedral shows the ORIGINAL symptom family (neighbor-cell walls drawn through portals over the room), explicitly outside G1 and carried to S3/S4 | dev pak recipe 8 (597,369,112 B; `acdream.recipe7.pak` kept); TOC delta explained; corpus scan old-only 3,197 (all untextured), new-only 0, unexplained 0 | | Capture | READY | §7 + `tools/walk-oracle/oh/README.md` | scripts committed `ebaa41df` + `14d8fe64`; lead resolved DBObj::m_DID=+0x28 and the cdecl alpha-function conventions; recon attach re-confirms | — | recon dt/x/uf dumps at session start | owner session ~1 h | before S3 | | S2 World graph | CODE-COMPLETE — G2 PROVISIONAL PASS (self-gate 2026-09-03, owner double-check owed) | `s2-membership-ownership-map.md` (`e7ad25a7`) + Contracts A/B; closeout evidence §8/§9 | chunk 1a `059b8883`; chunk 1b `5a2792d6`; chunk 2 `707d2803` (render statics borrow the registry's retail array; render flood deleted); chunk 3 `afbd2410` (one flood per registration feeds collision rows and render entries; staged SetPosition carries both products); chunk 4 `75ea269d` (movement publishes from the transition's cells; children inherit at registration); chunk 5 + closeout `c94a1a40` (borrowed per-cell views, render-only registration, sweeps/fallbacks deleted; reflood forwards the part array; NON-COLLIDING DAT STATICS register render-only from both publishers; the dual-review fix batch: Suspend clears the retail product, attach/detach advance the mutation revision, an attached child never floods on its own, RemoveLandblock/RetireOwnerFromLandblock prune retail rows, render-only owners move with their destination cell (AD-117), empty part array == null, per-move closures removed, EnvCell shells out of the entity-id index, index predicate compares the id, dead per-cell scene indices deleted) | lead corrected 1a's route decision before landing; chunk 2 verified by the lead; chunk 5's agent report missed the non-colliding-static population (found by the self-gate PIXEL DIFF, not by eye: Facility wall panels grey); S2 dual review (arch + retail lens, Opus) produced 12 + 7 findings, every one lead-verified against the source before an edit; the four BLOCKING/MAJOR lifetime gaps were real | at `c94a1a40`: Core 4,984/4,984; Content 214/214; Runtime 1,884/1,884; App hermetic lane 6,760/6,760; App InstalledDat 217 pass / 1 skip / 2 pre-existing #383; App Windows 1/1 | G2 PROVISIONAL PASS. Self-gate runs (kit `ea546f38`, pwsh): `logs/selfgate-20260902-231426-baseline-g1-binary` (reference), `…231642-s2-chunk3`, `…233845-s2-chunk4` (identical), `logs/selfgate-20260903-002632-s2-chunk5-reflood` (FAIL: Facility wall panels grey, left-wall mean RGB 29,26,23 vs baseline 65,17,21 — missing non-colliding statics), `logs/selfgate-20260903-010022-s2-review-fixes-3` (candidate: panels back at 79,20,25 = chunk-3/4; cathedral 13.6% / Facility 15.0% / house 13.4% px differ vs baseline, the chunk-3/4 band; graceful logout, zero exceptions). Membership-probe run `logs/selfgate-20260903-003013-s2-chunk5-membership-probe`: `[walk-membership]` fired only on two transient Holtburg login frames, never in Facility Hub or the cathedral. Connected R6 soak on the chunk-4 build `6717a3e5` (`logs/connected-r6-soak-20260902-234016.report.json`): 9 destinations in 511 s, zero invariant failures, graceful exit — route PASS (its `-CollisionShadowEvery` referee is the obsolete I5 graph-vs-flat comparator; retire in S5). Morning handoff: `docs/research/2026-09-01-overhaul/2026-09-03-g2-morning-handoff.md` | owner double-checks G2 (handoff checklist); then the owner capture session (add a `CTransition` trace at `num_sphere == 0` to retire AD-117 item 1); then S3 | -| S3 Walk | PLANNED | built-mesh/world contracts + captures | — | — | — | folded into G3 | | +| S3 Walk | PACKET DRAFTED 2026-09-03 — implementation BLOCKED on the §7 capture session | `s3-walk-ownership-map.md` (retail table, current owners, four chunks, review lenses, gate, the three exact captures to ask for) + built-mesh/world contracts | — | — | — | folded into G3 | owner capture session first (§7 of the packet names the three traces); chunk 2 may start on the decomp oracle alone | | S4 Depth + alpha | PLANNED | depth/alpha contracts + captures | — | — | — | G3 | retires AP-34 | | S5 Consumers + closeout | PLANNED | landscape contract; AP-232 | — | — | — | G4 | retires AP-117/AP-232; deletes probes | diff --git a/docs/research/2026-09-01-overhaul/2026-09-03-g2-morning-handoff.md b/docs/research/2026-09-01-overhaul/2026-09-03-g2-morning-handoff.md index ec4b0030..bdfa0fee 100644 --- a/docs/research/2026-09-01-overhaul/2026-09-03-g2-morning-handoff.md +++ b/docs/research/2026-09-01-overhaul/2026-09-03-g2-morning-handoff.md @@ -87,7 +87,9 @@ layout sweeps (`LayoutImporterMediaBearingChildSweepTests`, 1. The owner's ~1 h retail capture session (`tools/walk-oracle/oh/`, recon attach first) — add a `CTransition` trace at `num_sphere == 0` to retire AD-117(1). -2. S3 Walk. +2. S3 Walk — the ownership packet is DRAFTED and waiting for the capture: + `docs/research/2026-09-01-overhaul/s3-walk-ownership-map.md` (§7 lists the + three exact things to capture). Open tails carried into S5: retire the obsolete `-CollisionShadowEvery` referee in `tools/run-connected-r6-soak.ps1`; the `[walk-membership]` line rides the #177 diff --git a/docs/research/2026-09-01-overhaul/s3-walk-ownership-map.md b/docs/research/2026-09-01-overhaul/s3-walk-ownership-map.md new file mode 100644 index 00000000..1a521715 --- /dev/null +++ b/docs/research/2026-09-01-overhaul/s3-walk-ownership-map.md @@ -0,0 +1,145 @@ +# S3 — Walk: exact PView views, leaf admission, and interleave — ownership map and chunk plan + +**Status:** DRAFT packet written 2026-09-03 at the S2 closeout, BEFORE the +owner's §7 capture session. Every retail claim below is decomp-verified +(named pseudo-C + Ghidra bridge, cited by address); the capture session adds +the per-frame TRANSCRIPT the automated gate needs and may amend §3 (marked +"capture-owned"). Nothing in this packet is implemented yet. + +**Plan:** `docs/plans/2026-09-01-campaign-overhaul-world-solidity.md` §9 S3. +**Binding inputs:** `oh1-retail-world-contract.md` §4–§5 (view/frame order), +`oh1-built-mesh-view-contract.md` (caller order, stamps, direct answers, +binding constraints), `2026-08-30-fw-flood-pseudocode-appendix.md`, the FW +plan's verified seam map (`docs/plans/2026-08-30-campaign-fw-frame-walk.md` +§"Verified seam map"), and S2's ownership truth +(`s2-membership-ownership-map.md` §9: the registry is the only membership +source; the walk reads `GetRetailPartEntriesInCell`). + +## 1. What S3 changes (behavior) + +`WalkPView` owns retail's exact per-frame state — the portal-view lists, the +view/update counts, the todo order, the draw list, and the stamps — and each +content category follows its retail leaf rule. Terrain is emitted as ordered +landcell events interleaved with buildings and object lists in retail +far-to-near order. `DrawBuilding` is one semantic sequence. The "all terrain +first" simplification and every generic GPU clip rule that retail does not +have are deleted. S3 ships no evidence infrastructure beyond the one +print-only transcript emitter its own gate consumes (rule §5). + +## 2. Retail truth (decomp-verified; addresses are the Sept 2013 build) + +| Retail function | Address | What it decides | Verified in | +|---|---|---|---| +| `PView::InitCell` / `InsCellTodoList` | (walk root; see flood appendix) | seeds the flood from the viewer cell, orders the todo list | flood appendix | +| `PView::ClipPortals` / `AddViewToPortals` / `ConstructView` | `PView::GetClip → polyClipFinish @0x006B6D00` | builds CHILD VIEWS by polygon-clipping PORTAL polygons — the only polygon clip in the walk | built-mesh contract §"What polygon-clips?" | +| `Render::copy_view` | `0x0054dfc0` | copies the view polygon, derives edge planes (0x48 semantic fields, prune, cap 31) | built-mesh contract ledger | +| `Render::set_view` | `0x0054d0e0` | installs the view in render globals; NO scissor, NO general mesh clip | idem | +| `Render::obj_view_set` | `0x0054b9b0` | transforms the active planes/sphere through `FrameCurrent`, publishes `local_object_center/radius` | idem (side effects unrepresented — Medium row) | +| `Render::viewconeCheck` | `0x0054c250` | the ordinary sphere admission: strict-outside / inclusive-partial | `WalkVisibilityMath` pins | +| `CPhysicsPart::Draw` | `0x0050d7a0` | outer part-stamp skip (`+0xdc` vs device `+0xb0`); force bypasses; local player bypasses the inner stamp | idem | +| `RenderDeviceD3D::DrawMeshInternal` | `0x0059f360` | first admitted view stamps the non-player part and submits the WHOLE eligible mesh once; later views return | idem | +| `RenderDeviceD3D::DrawEnvCell` | `0x0059f170` | no sphere admission; cell stamp (`+0x130`) gate; whole shell once per stamp | idem | +| `RenderDeviceD3D::DrawBuilding` | `0x0059f2a0` | detail state → `FlushAlphaList(0)` → `CPhysicsPart::Draw(part,1)` portal-only BSP pass → flag → `Draw(part,0)` ordinary shell | idem | +| `PView::DrawCells` | `0x005a4840` | outside-view branch (sunlight, `LScape::draw`, alpha flush, device-stamp advance @`0x005a4886`, counter consume/clear, exit seals) then reverse shells (`CEnvCell::setup_view @0x0052c430` per live view + `DrawEnvCell`) then reverse object lists (`DrawObjCellForDummies`) | retail-world contract §5.2 | +| `LScape::draw_check_blocks` / `landcell_check` / `grab_visible_cells` / `draw` / `calc_draw_order` | (landscape walk) | admitted land cells in retail FAR-TO-NEAR order; per admitted cell `DrawLandCell` THEN `DrawSortCell` (building pass / look-in / shell / object turn) | retail-world contract §5.2; **capture-owned:** the exact `calc_draw_order` sequence at the four poses | +| `DrawObjCellForDummies` | (object-list path) | installs the cell's top `portal_view_type` as `PortalList`, walks the cell's shadow part list (`CShadowPart::insertion_sort` by `CYpt`) and draws each part through the view loop | built-mesh contract §"object-list path" | + +Facts already PROVED and binding (do not re-derive, do not weaken): +- the built cell shell is stamped and submitted whole once after Boolean admission; +- portal polygons, not built meshes, are polygon-clipped; +- `DrawCells` draws all shells then all object lists, both in reverse + draw-list order, views ascending; +- device, cell-shell and part stamps persist with the local-player bypass; +- the "first view clips the shell" hypothesis is RETIRED. + +## 3. Current acdream owners (functions, not line numbers — re-locate at chunk time) + +| Retail mechanism | Current owner | Assessment (from the built-mesh comparison at `eaea8776`, re-checked against `c94a1a40` file list) | S3 action | +|---|---|---|---| +| view polygon / planes | `WalkViews` | strong match | keep; pin | +| viewcone sense | `WalkVisibilityMath` | exact | keep | +| flood + todo order | `WalkFrameDriver` (flood turns, `VisitedCells`, `OnLandscape`) | order proven for shells/objects; `_skyDrawnThisFrame` is a PROXY for retail's `outside_view.view_count != 0` | chunk 2 replaces the proxy with the real outside-view count | +| whole-mesh admission at slot 0 | `WbDrawDispatcher.WalkClassify` (`ResolveWalkLightSet`, part stamps, `RetailWholeMeshSlot`) | correct | keep; chunk 4 deletes the still-translated clip slots per category | +| part stamp identity | `(RenderProjectionId, PartIndex)` | retail identity is the `CPhysicsPart*`; S2 made per-cell membership registry-borrowed, so one logical part now reaches the classifier from EVERY cell it is in with the SAME projection id — the identity audit the contract asked for is now structurally answered; pin it | chunk 2 pin | +| cell shell once per stamp + mid-frame re-arm | `WalkFrameDriver` shell loop, `RetailPViewPassExecutor.WalkLeaf` | correct | keep; re-arm gate moves to the real outside-view count | +| building sequence | `WalkFrameDriver` building turn, `RetailFrameWalk` | matches alpha barrier → portal pass → shell | keep; pin as ONE sequence | +| terrain emission | `RetailPViewPassExecutor` landscape stage (whole-stage terrain event before building/object turns) | DIVERGES: retail is `DrawLandCell` then `DrawSortCell` PER admitted land cell, far-to-near | chunk 3 | +| landscape leaf's use of the installed outside-view list | `TerrainModernRenderer` visible cells + `WalkFrameDriver.VisitedLandscapeCellIds` | top-level ownership proven; per-leaf pixel use is an S3 audit item | chunk 3 audit (bounded: one pose) | +| generic GPU clip rules for categories retail never clips | Vulkan clip slots on look-in / straddling / building categories (`RetailPViewPassExecutor`, `UseIndoorMembershipOnlyRouting`) | retail clips only portal polygons | chunk 4 delete, with a CPU/GPU equivalence pin for any category that must keep a translated clip | +| `obj_view_set` side effects | not represented (world-space sphere vs captured planes) | mathematically aligned for affine transforms | out of S3 unless the capture shows a consumer | +| missing `SelectionSphere` fallback | "any view → whole mesh" | not a retail branch | keep as a corruption fallback, outside parity claims (register row if it survives S5) | + +## 4. Chunks (bounded; one Sonnet agent each; stop on a third round) + +**Chunk 1 — transcript emitter + parser + fixture import (needs §7 captures).** +One print-only flag (documented in `docs/launch-options.md` in the same +commit) emits the OH line kinds the capture templates produce +(`tools/walk-oracle/oh/*.template`: walk / parts / alpha-depth) from the +production walk; the existing FW0-style test-side parser is extended for the +new kinds; the four captured pose logs are imported as fixtures. Gate: the +emitter's lines parse with the same parser as the retail logs; NO validator, +NO canonical JSONL (rule §5, [[feedback-evidence-infrastructure-sink]]). +BLOCKED until the owner runs the capture session. + +**Chunk 2 — exact PView state.** `WalkPView` (new, App/Rendering/Walk) owns: +the live view list per cell (retail `portal_view_type` lists), the +outside-view count, the view/update counts, the todo order, the draw list and +the two stamps. `_skyDrawnThisFrame` and every other proxy for +`outside_view.view_count != 0` is replaced by the real count. Per-category +leaf contract pinned: whole-once (built shell), Boolean sphere (ordinary +part), actual polygon clip (portal polygons only), repeated submission (local +player). Part identity pin: the same logical part reached from two cells +classifies once per stamp. Can start before the capture (decomp oracle); +the capture confirms. + +**Chunk 3 — interleave.** Terrain becomes ordered landcell events: for each +admitted land cell in retail far-to-near order, `DrawLandCell` (that cell's +terrain range) then `DrawSortCell` (building pass 1 / look-in work / building +shell / land-cell object turn). Per-landcell terrain ranges come from the +existing terrain mesh layout (index ranges per landcell — verify +`TerrainModernRenderer` exposes them; if not, the chunk adds the range table +at bake/upload time, not a per-frame rebuild). The whole-stage terrain event +is deleted in chunk 4, not here (two-step so the pixel gate can bisect). +Gate: terrain pixels/mesh counts unchanged when no interleave is present; +dense-outdoor p50/p99 recorded before/after. + +**Chunk 4 — deletions.** The whole-stage terrain event; the generic clip +rules on categories retail never clips (Vulkan clip slots removed from those +categories); any residual "first view clips the shell" code path. Gate: no +duplicate draw of a stamped part across a pan/zoom replay; membership/draw +count changes only at a retail view boundary. + +## 5. Review (one Opus retail lens + one shader/perf lens at the S3 boundary) + +- retail lens on every stamp/view loop branch and on the call order against + the capture transcript and the decomp; +- shader review of clip-space sign, y inversion, W plane, plane count and + scissor for the categories that KEEP a translated clip; +- performance review: the command-count increase from interleaving is + measured (dense outdoor p50/p99), not hidden by reordering. +Lead verifies every finding against the source before an edit (S2 precedent: +19 findings, 4 blocking, all real; see `s2-membership-ownership-map.md` §9). + +## 6. Automated gate (S3 has no standalone owner gate; folds into G3) + +- transcript equality with the §7 captures at the captured depth for all four + poses plus the FW0 still fixtures; +- tests distinguish whole-shell-once, Boolean part admission and actual + polygon clipping; +- pan/zoom replay changes membership/draw count only at a retail view boundary; +- no duplicate draw of a stamped part; +- terrain pixels/mesh counts unchanged when no interleave is present; +- self-gate route (`tools/overhaul-selfgate/`) at the three owner poses + + the four capture poses, pixel-diffed against the G2 candidate run + `logs/selfgate-20260903-010022-s2-review-fixes-3` — the per-region diff, + not the eye, is the verdict ([[feedback-deleted-fallback-carried-population]]). + +## 7. Open questions for the capture session (ask for exactly these) + +1. `LScape::calc_draw_order` sequence at each of the four poses (far-to-near + land cell order) — chunk 3's oracle. +2. Per-frame `outside_view.view_count` and the device-stamp advance count at + each pose — chunk 2's oracle for the re-arm gate. +3. `CTransition` at `num_sphere == 0` (a shapeless object's cell array on a + move) — retires AD-117 item 1 (S2 residual), unrelated to S3 but cheapest + to capture in the same session.