acdream/docs/plans/2026-09-01-campaign-overhaul-world-solidity.md
Erik e2543d0ef0 fix(content): S1 review round - retail default sides shape, mask hoist, upload order
Campaign OVERHAUL S1 review fixes (two Opus lens reviews, findings verified
by the lead against the decomp):

- a raw sides_type outside 0/1/2 constructs retail's default single-side
  shape (ConstructMesh @0x0059DFA0 loop bounds default to 1) instead of
  dropping the polygon; still counted as a data anomaly (corpus has none);
- the positive-surface stippling mask OR runs once per polygon before the
  degenerate-fan guard, as retail's count loop does (pseudo-C 426859-426866);
- untextured slots keep their mask accounting but bake no texture and no
  vertices (contract §9 item 3); the dev pak shrinks by 114 KB;
- failed surface-override / Surface / texture-dependency lookups are
  attempted and logged once per slot, not once per candidate;
- cell-shell batches upload in ascending source surface index, retail's
  built-EnvCell subset draw order (ConstructMesh attribute-range scan,
  DrawMesh @0x0059D4A0); ordinary GfxObj meshes keep storage order;
- CellMesh.HasDrawableGeometry documented as the admission rule without
  texture-dependency resolution (a conservative superset of emission);
- the stippling/surface equivalence sweep's cell half is pinned at zero
  again; InAscendingSurfaceOrder is marked bake/upload/test-only;
- plan §5: reviewer findings are verified by the lead, one skeptic at most
  for a blocking finding, never more than five agents per step.

Three new Content tests pin the mask hoist, the vertex-free untextured
slot, and the single-side fallback. Content 213/213, Core Meshing and
Conformance green, App hermetic 6,757/6,757, Release build 0/0.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-02 19:37:25 +02:00

40 KiB
Raw Blame History

Campaign OVERHAUL — retail world construction and render solidity

Status: ACTIVE — v2 rescope 2026-09-02. Five production slices replace the twelve-stage v1 plan. S1 is the current slice. See §13 for the ledger and §15 for what v2 changed and why.

Campaign code: OH.

Worktree (binding): C:\Users\erikn\source\repos\acdream\.claude\worktrees\peaceful-blackburn-5333f0

Branch (binding): claude/campaign-w-retail-frame-walk. This is the long-lived renderer integration branch. It carries all of Campaign FW (101 commits over origin/main at e102fb36). Nothing merges to main until the final gate passes; origin/main is merged INTO this branch at every slice boundary so it never drifts.

v2 base: 5d907ae9 (docs(render): define OH1 retail world contract), tree clean. The uncommitted OH1/T3 evidence grammar (~32K lines) is parked verbatim on quarantine/oh1-evidence-grammar-2026-09-02 (see its QUARANTINE-README.md). Do not merge that branch.

Recovery anchors: b3b7d922 is the checkpoint that committed the pre-overhaul investigation candidates, including the Facility Hub stair fix (recipe 7 authored drawing sphere, static render-shadow membership, per-part stamps). b8befded is the user-gated FW closeout. Both are history, not permission to discard later work. No history rewrite, ever.

One-sentence goal: recreate retail's single coherent world-cell graph and its exact per-frame world walk up to a narrow Vulkan translation boundary, so walls, terrain, buildings, objects, particles, transparency, and portal transitions remain stable at every camera position without scene-specific suppression, guessed tolerances, or corrective overdraw.


1. Why this campaign exists

Campaign FW replaced the legacy visibility product with a retail-derived frame walk and fixed several defects. It did not make the world pipeline retail-identical. The client still reconstructs relationships retail owns directly:

  • prepared cell meshes are separate from portal topology;
  • building shells are separate from building portal ownership;
  • render projections are separate from physics CELLARRAY membership;
  • static visual membership is rebuilt from visual bounds in an App-owned model that competes with the physics registry;
  • terrain is submitted as a complete slice before per-cell object turns;
  • alpha uses a modern scope-global queue rather than retail's exact cell/list ownership;
  • the interior depth clear is unconditional although retail latches it on the previous frame's portalsDrawnCount;
  • CellStruct face selection uses the AP-234 NoPos proxy rather than the surface-type decision retail makes;
  • some accepted object parts are duplicated through Vulkan clip slots without proof that retail clips them.

These explain why local fixes oscillate between opposite failure modes. The precedent is physics: incremental collision patching never converged; the faithful retail port did. The renderer gets the same treatment.

Owner-observed symptom family: cathedral walls/wall-textured triangles over floating stairs; stair slabs appearing/disappearing by camera angle; the cathedral exterior ramp absent; textures bleeding through opaque surfaces; the local character chopped at cathedral and Facility Hub seams; remote actors and particles through walls; waterfalls vanishing by angle; outdoor groups disappearing after small turns; landscape draw-range regressions; spell effects lingering.


2. Definition of success

  1. One authoritative, generation-scoped cell graph supplies portal topology, building ownership, drawable CellStruct identity, and render/physics cross-cell part membership. No production consumer rebuilds a competing answer.
  2. CellStruct mesh extraction selects sides and subsets from the same authored data retail uses, including exact surface-type handling. AP-234 is retired.
  3. The per-frame transcript matches retail's captured transcript for the same root and camera pose at the depth the capture records: landscape/building order, portal views, cell order, object-list turns, shell/part draws, depth events, alpha inserts and flushes.
  4. Every leaf category has a proven retail contract: EnvCell shell, building shell, landblock static, indoor static, dynamic object, particle, terrain, punch, seal, transparent subset.
  5. Vulkan receives an ordered list of already-decided retail draw operations. It may batch adjacent compatible work; it decides nothing.
  6. No scene-specific suppression, shell lift, bias, fallback flood, corrective redraw, or behavior-changing diagnostic flag remains in production.
  7. The owner acceptance matrix (§10) passes.
  8. The complete Release suite, installed-DAT lane, connected lifecycle route, R6 route, and performance checkpoint pass on the exact gated binary.
  9. Architecture, inventory, divergence register, launch options, memory, and milestone ledgers describe the code that ships.

"Looks fixed at one camera angle" is never a completion condition.


3. Scope and non-goals

In scope: CellStruct/EnvCell geometry construction; the canonical cell/building/portal/part-membership graph; static and dynamic cross-cell render membership; retail PView view ownership and leaf contracts; landscape, building, cell-shell, object, particle, depth, and alpha ordering; portal punch and exit-seal lifecycle; retail landscape in_view and its particle/light/ shadow consumers; material behavior needed for solid composition (AP-232 residual); minimal per-slice instrumentation; deletion of superseded reconstruction and diagnostic apparatus; docs and regression coverage.

Out of scope: replacing Vulkan; recreating C++ pointer layouts; changing streaming strategy, budgets, reveal radii, the mmap package model, or GPU resource lifetime except the S1 recipe bump; increasing draw distance; a lighting redesign; physics not required for exact membership; new graphics features; removing the user-requested Extended particle-range option.


4. Binding engineering rules

  1. Retail makes every world decision. Modern code may represent a result differently but may not invent an additional visibility, membership, ordering, clipping, or depth decision.
  2. A slice ships a production behavior change or it is not a slice. Evidence tooling is built inside the slice that consumes it, to the depth that slice needs, never as its own stage.
  3. Evidence before code, contract already written. The OH1 research contracts (§6) and the retail capture (§7) are the evidence. No slice starts from a screenshot theory; no slice builds a new evidence language.
  4. Named retail first; Ghidra arbitrates branch sense. Any condition whose polarity affects admission, clipping, depth, ordering, or lifetime is cross-checked in Ghidra (patchmem, port 8081) before implementation.
  5. DAT identity is exact. A trace reaches owner → Setup → part → GfxObj → polygon/surface before assigning a visual carrier. Aggregate owner IDs do not identify content.
  6. No symptom-site fixes. Cell/building/GfxObj IDs and camera poses are for diagnosis only.
  7. No silent drop. Every rejected cell/view/part/mesh has a diagnostic reason available during a slice; production diagnostics are removed or made print-only at slice close.
  8. No competing production owner. A cutover slice deletes the route it replaces within the slice.
  9. Whole-mechanism fixes. Never patch a downstream draw when retail owns the decision upstream.
  10. Build before launch; exact binary for gates. Commit hash, package recipe, flags, and log path are recorded before every owner gate.
  11. Client process safety. Never kill the client.
  12. Preserve unrelated work. No reset --hard, checkout --, clean, or bare stash. Rollback is a normal revert of a named commit.
  13. Register discipline. Deviations filed/retired in the same commit.
  14. Docs are tested truth. Architecture text and code agree at slice close.
  15. Time-box. A chunk that needs a third fix round stops and goes to the user with its evidence. No agent decides it needs more infrastructure.

5. Working model

The v1 failure was one agent given the whole campaign for eighteen hours. v2 keeps the lead in the loop at every chunk.

Role Who Does Never
Lead / architect the main session (Fable) writes each chunk contract (files, retail functions + addresses, acceptance tests); dispatches one bounded chunk; verifies every claim against source; runs gates; commits; merges main in at slice boundaries hands off "complete the slice"
Implementer Sonnet, one dispatch per chunk one file cluster + its tests; build and test green is the return condition; returns a diff summary and open questions commits; adds evidence infrastructure; starts a third fix round; touches files outside its contract
Retail reviewer Opus, one pass per slice on the production port checks each ported branch against the named decomp with addresses; findings as file:line + decomp citation reviews tooling
Architecture reviewer Opus, only at the two cutover slices (S2, S5) one owner per fact; layering; lifetime; performance shape
Finding verification the lead, against the source each reviewer finding is checked by the lead against the decomp/contract/code before it is acted on; at most one Opus skeptic, and only for a blocking finding the lead cannot settle spawns a skeptic per finding (the S1 review fanned out to ~30 agents this way on 2026-09-02; never again)

Agent budget per slice: implementers as needed (one per chunk, serial for coupled files); reviewers two (retail lens, and the architecture lens only at S2/S5); skeptics at most one per blocking finding. Anything that would spawn more than five agents in one step is wrong and stops.

Chunk contracts state explicit stop conditions: build red after two attempts → return; contract ambiguity → return with the question; any need for a third round → return. Coupled files go to one agent serially against a pinned contract; only genuinely independent chunks run in parallel worktrees. Agents write incremental output to disk; a silent agent is stopped and inspected, not waited on.


6. Evidence hierarchy and products

When sources disagree, in this order:

  1. Live retail binary behavior captured at named functions (§7).
  2. Named retail PDB/header identity and Ghidra-arbitrated decompilation.
  3. Byte-exact installed DAT structure and geometry.
  4. Existing FW0 cdb traces in docs/research/2026-08-30-fw-walk-oracle/.
  5. Deterministic acdream replay of the same input.
  6. Render/API captures.
  7. acdream diagnostic logs.
  8. Visual observation — to discover symptoms and accept final pixels, never to infer identity or branch logic.

Research contracts already written (committed at 5d907ae9, binding): oh1-retail-world-contract.md, oh1-construction-landscape-contract.md, oh1-built-mesh-view-contract.md, oh1-alpha-list-contract.md, oh1-depth-lifecycle.md, oh2-cellstruct-surface-contract.md, and the corrected 2026-08-30-fw-flood-pseudocode-appendix.md. The retail facts the v1 T3 reviews established are carried in 2026-09-02-campaign-overhaul-handoff.md §5.3 and are binding inputs to S3/S4.

Evidence products, minimal by design:

Product Form Used by
Geometry conformance installed-DAT scans + synthetic fixtures + a two-run SHA-256 over the emitted CellStruct subset records S1
Membership conformance typed expected cell lists per fixture object + installed-DAT comparator between the canonical graph and the old builders (comparator lives and dies inside S2) S2
Frame transcript the FW0 line format (F/P/LS/BLD/DI/DC) extended with the OH line kinds the capture scripts emit; parsed by the existing test-side WalkOracleTrace parser, extended in place; acdream emits the same lines behind ONE print-only flag inside the slice that needs it S3, S4
Framebuffer equivalence offscreen fixture renders compared to the retail formula S5

Pointer values, Vulkan handles, and allocation addresses are excluded from equality. No canonical JSONL, no semantic validator: structure is checked in the parser, semantics in the port and in the compare against retail.


7. Retail capture session (owner action, before S3)

The one owner action in the campaign apart from gates. Scripts live in tools/walk-oracle/oh/ (recon, three capture templates, runner, README).

Pose Root Why
holtburg-doorway-still interior a9b4013f the flap scene; three consecutive look-in punches of one cell
terrace-edge outdoor the #456 pose; far building drawn and depth-covered
cathedral-arrival interior f4180106 interior root, landscape through the exit view, culled roster
foundry-deep interior a9b40176 deep chain with ov=1; landscape and 12 buildings drawn from the basement

Per pose, three short attaches in order, each auto-detaching after its frame budget: walk (cell granularity: FW0 lines plus DrawEnvCell and object-cell turns, 5 frames), parts (CPhysicsPart::Draw candidates and DrawMeshInternal actual draws with GfxObj ids, 3 frames), alpha/depth (AddMeshToAlphaList, FlushAlphaList with site, depth-clear latch and portalsDrawnCount, 5 frames). Still poses repeat bit-for-bit per frame (FW0 finding 6), so few frames suffice and the ACE-timeout risk from per-hit .printf stays bounded. Budget: one hour.

Procedure: recon attach first (no breakpoints; dt/x dumps verify every offset the templates assume); PDB pairing check before every attach; qd only at top level after the terminal-hit fall-through. Logs land in docs/research/<date>-oh-walk-oracle/ and become S3/S4 fixtures.

If a static fact is later found unrecoverable from these captures, request one more exact capture with pose, action, duration, and expected trace. Never an open-ended "run around and report".


8. Target architecture (unchanged from v1)

DAT + prepared package
  └─ S1  CellStruct subset construction (surface-index owned, recipe 8)
World-cell graph (generation-scoped, S2)
  ├─ portal topology, building ownership, drawable cell identity
  ├─ static part-shadow membership (init_static_objects/AddPartsShadow)
  └─ dynamic/child membership (add_shadows_to_cells, one transaction)
Frame walk (per frame, S3)
  ├─ LScape::draw order → DrawBuilding sequence → look-ins
  ├─ PView views/todo/draw-list/stamps → DrawCells two-pass
  └─ leaf admission per category (whole-once / Boolean sphere / real clip)
Depth + alpha (S4)
  ├─ portalsDrawnCount latch, conditional clear, punches, seals, mid-frame stamp
  └─ retail alpha lists, per-cell insertion, FIFO flush sites, 0.75 valve
Consumers (S5)
  └─ landcell in_view → particles/lights/shadows; material/degrade policy
Vulkan encoder: ordered immutable stream; merges adjacent compatible runs only

Required properties: render and physics adapters never mutate canonical topology/membership; dynamic updates replace one object's membership transactionally with exact incarnation identity; children inherit the root's CELLARRAY by one rule; the walk owns per-frame views/todo/draw lists/stamps/ latches and never persists them in projections; the encoder cannot enlarge the visible set or reorder across a semantic boundary.


9. The five slices

Each slice: plan packet (already written or one short note) → implementation in bounded chunks → retail review (+ architecture review at S2/S5) → fix → automated gate → owner gate where listed → ledger update → merge origin/main in.

S1 — Geometry: exact CellStruct construction (was OH2)

Spec: oh2-cellstruct-surface-contract.md, sections 3, 8, 9, 10, 12 are the implementation contract verbatim. Retail anchors: CEnvCell::UnPack 0x0052D470, CPolygon::UnPack 0x00538650, copyVert 0x0059C080, D3DPolyRender::ConstructMesh 0x0059DFA0, D3DPolyRender::DrawMesh 0x0059D4A0, RenderDeviceD3D::DrawEnvCell 0x0059F170.

Behavior change: side candidates come only from sides_type; NoPos/ NoNeg mean UV absence only; subsets are owned and ordered by source surface index; built-EnvCell admission is (Surface.Type & 6) != 0 after surface resolution; authored sides_type is not GPU cull. AP-234 retired.

Chunks:

  1. Core side-candidate descriptor (pure, allocation-free) + MeshExtractor. PrepareCellStructMeshData rewrite against it + §10.1/§10.2 tests.
  2. Prepared subset record fields (source surface index, raw type, retail mask, fixed cell-shell cull) + ObjectMeshDataSerializer round-trip + PakFormat.CurrentBakeToolVersion = 8, launcher recipe 8, 7 → 8 FullRebuild step + §10.5 tests. Container format stays 2, with a test saying so.
  3. CellMesh.Build routed through the same descriptor or its render role deleted; full installed-DAT scan with every admission delta explained by Surface.Type & 6; two-run deterministic hash; §10.3 canonical pins (0xF4180104: eight ST_DOUBLE clip-map polygons, 44 drawable side calls); AP-234 row deleted with addresses; inventory/architecture text.

Review: retail lens on the descriptor, mask, winding, and admission; data lens that no ordinary-GfxObj rule leaked into cells or vice versa; Surface lookup stays in Content/bake.

Automated gate: Content, Bake, Core, Launcher.Core, focused App suites green in Release; installed-DAT scan reports zero unexplained deltas; full solution build green; no per-frame allocation or DAT lookup added.

Package: rebuild the dev pak (Documents\Asheron's Call\acdream.pak) to recipe 8 through the supported bake flow; keep the recipe-7 file beside it as acdream.recipe7.pak. Note the launcher-installed pak under %LOCALAPPDATA%\acdream\pak is still recipe 6; it is not the gate binary's pak.

Owner gate G1 — geometry integrity. One exact build: cathedral exterior ramp and every floating stair slab; cathedral walls at the 0x104/0106 and 0x107/0112 seams; Facility Hub bottom/top stairs and doorway walls; two ordinary dungeons with solid-color and textured surfaces; Holtburg/Nanto shells. Pass = no missing/new wall faces, no invisible ramp/slab, no gross material substitution. Camera-dependent occlusion is not adjudicated here.

Rollback: revert the S1 behavior/schema commits; restore acdream.recipe7.pak.

S2 — World graph: one membership owner (was OH3)

Spec: oh1-construction-landscape-contract.md §construction/ownership; retail: CEnvCell::init_static_objects, CPhysicsObj::calc_cross_cells_static, CPartArray::AddPartsShadow, CPhysicsObj::add_shadows_to_cells, find_bbox_cell_list, child-list propagation and removal counterparts. Starting point: the b3b7d922 candidates (WalkProductionWorldData render index, ShadowShapeBuilder.FromStaticRenderParts, ShadowObjectRegistry.ComputeStaticRenderCells, the Facility stair pin FacilityStairAssembly_RegisterAcross015FTo015EWithoutCollisionRows). They use retail's mechanism in the wrong owner; S2 moves them, it does not delete the mechanism.

Behavior change: one generation-scoped WorldCellGraphSnapshot owns portal topology, building ownership, drawable cell identity, and typed per-part render-shadow plus object-level physics CELLARRAY outputs from one registration transaction. Every consumer borrows it; the App-owned render index, visual-AABB fallbacks, origin-cell fallbacks, and duplicate cell buckets are deleted.

Chunks:

  1. Read-only graph snapshot beside existing owners from the same accepted publication; equality test against source publication; zero pixel change.
  2. Static AddPartsShadow parity: ordered membership vector per visual part; old index retained as comparator only inside this chunk; cut render lookup after the installed-DAT comparator is zero-mismatch. Fixtures: cathedral ramp/stairs/walls, Facility stairs, a 24 m cell-edge crosser, a landblock-edge object, a non-colliding decoration, a multi-part Setup whose parts cross different cells.
  3. Dynamic/child parity: add_shadows_to_cells, removal, movement update, child inheritance as one transaction keyed by exact incarnation. Fixtures: local/remote player, NPC, projectile, spell world object, equipped child, contained child, indoor portal crossing, outdoor crossing, teardown/ reconnect.
  4. Consumer cutover in order: indoor static render lookup, outdoor static render lookup, dynamic render lookup, physics broadphase projection, particle owner-cell lookup, point-light owner-cell lookup, directional-shadow reachability. Delete the superseded builders.

Review: architecture (one authority; retry/recenter/reset safe; no per-frame rebuild) and retail (crossed cells and insertion order match the AddPartsShadow family; CellTransit prune change affects collision too and is reviewed as such).

Automated gate: comparator zero mismatch on installed-DAT canonical routes; render-shadow and physics projections each match typed expectations from the same transaction; cancellation, generation replacement, landblock retirement, reconnect, child detach converge to zero rows; full Release solution and connected headless lifecycle route green.

Owner gate G2 — membership stability. Cathedral floating stairs/ramp; move/rotate at Facility Hub stairs; circle dense Tusker groups while turning; remote player and NPC across cathedral wall cells; cast several spells. Pass = static geometry never vanishes because its origin or camera-facing cell changes; dynamics do not vanish at transitions; retired effects leave no rows.

S3 — Walk: exact PView views, leaf admission, and interleave (was OH4 + OH5)

Spec: oh1-built-mesh-view-contract.md, oh1-retail-world-contract.md, the flood appendix, handoff §5.3 facts, and the §7 capture fixtures. Retail: PView::InitCell, InsCellTodoList, ClipPortals, AddViewToPortals, ConstructView, DrawCells, Render::copy_view, set_view, obj_view_set, viewconeCheck; LScape::draw_check_blocks, landcell_check, grab_visible_cells, draw, calc_draw_order; RenderDeviceD3D::DrawBuilding, DrawEnvCell, DrawObjCellForDummies, CShadowPart::insertion_sort, CPhysicsPart::Draw, DrawMesh, DrawMeshInternal.

Binding already-proved facts: 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.

Behavior change: WalkPView owns retail's exact per-frame state (portal-view lists, view/update counts, todo order, draw list, stamps); each content category follows its retail leaf rule (whole-once / Boolean sphere / actual polygon clip / repeated submission) and Vulkan clip slots are removed from categories where retail does not clip; terrain is emitted as ordered landcell events interleaved with buildings and object lists in retail far-to-near order; DrawBuilding is one semantic sequence (degrade gate → full alpha barrier → look-in work → punch → own shell); the "all terrain first" simplification is deleted.

Chunks: (1) transcript emitter for the OH line kinds behind one print-only flag + parser extension + fixture import of the §7 logs; (2) exact PView state and per-category leaf contract with CPU/GPU equivalence pins for any category that still translates a clip to Vulkan; (3) landscape/building/cell/ object interleave with per-landcell terrain ranges; (4) delete disproved generic clip rules and the whole-stage terrain event.

Review: retail lens on every stamp/view loop branch (Ghidra) and on the call order against capture and decomp; shader review of clip-space sign, y inversion, W plane, plane count, scissor for remaining translated categories; performance review that command count increase is measured, not hidden by reordering.

Automated gate: 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; dense-outdoor p50/p99 recorded.

Owner gate: none standalone; folds into G3.

S4 — Depth and alpha: latch, punches, seals, stamps, lists, flushes (was OH6 + OH7)

Spec: oh1-depth-lifecycle.md, oh1-alpha-list-contract.md, the §7 alpha/depth captures. Retail: the complete PView::DrawCells outside-view block, portalsDrawnCount producer/reset/consumer, the mid-frame stamp increment (@0x005A4886), far-Z punches, true-depth exit seals; D3DPolyRender::AddMeshToAlphaList, FlushAlphaList, CShadowPart::insertion_sort, DrawBlock's 0.75 pressure valve.

Behavior change: one frame-persistent latch owner for portalsDrawnCount; the landscape → flush → stamp → clear → seal block gated exactly as retail; WalkFrameDriver's unconditional interior clear deleted; the mid-frame stamp placed exactly so straddling parts draw in both retail scopes; exit seals from the exact current views and cell order; look-ins cannot touch the root latch. The scope-global CYpt sort is replaced by explicit retail list records with per-cell insertion order, FIFO flush, exact full-flush sites, and the 0.75 valve; transparent EnvCell subsets routed to their retail list. AP-34 retired. Vulkan keeps the already-ported state: depth ALWAYS, write ON, color OFF, no stencil; far-Z punch, true clip-space seal.

Chunks: (1) latch owner + conditional block + seal generation + truth-table tests; (2) alpha list records + insertion sort + flush sites + valve + ordering tests; (3) delete obsolete stencil/bias/skip paths and the CYpt sort.

Tests: truth table over root kind, draw_landscape, outside-view count, previous/current portal count → clear/seal/stamp events; two consecutive frames proving the latch is cross-frame; multiple look-ins isolated from the root; coincident cathedral exits at y≈24/48/72; outdoor root never clears interior depth; multiple translucent objects in one cell with reversed distance/insertion orders; equal-key stable tie; two cells where a global sort disagrees with traversal; particle/object/transparent-cell overlap; DrawBuilding 0f flush; pre-clear and final flush; 0.75 partial flush; alternating blend modes across Vulkan batches.

Review: retail lens tracing every state write from producer to next-frame consumer, and every list from insertion to flush; GPU lens on pipeline state after the transcript is exact; architecture lens that the latch has one frame owner and resets on generation change.

Automated gate: depth-event and alpha transcripts exact against §7 captures; focused walk/depth/alpha suites and full Release build green; AP-34 deleted; no behavior-changing probe in the cathedral replay.

Owner gate G3 — opaque solidity and transparency. Cathedral 0xF4180106 ↔ 0xF4180104 both directions with zoom/rotate; floating stairs 0xF4180107 ↔ 0xF4180112 ascend/descend/pan/zoom; exterior ramp from all angles; remote player at 0xF4180112 seen only through valid openings from 0x104, 0x101, outdoors; Facility Hub stairs at all zoom extents; cathedral waterfalls, mist, torches, lifestone/portal effects; Tusker/Nanto/Holtburg rotate in place. Pass = player whole, walls opaque, no wall-textured beam or missing slab, no terrain bleed, correct transparency order, no effect through walls.

S5 — Consumers, material, cleanup, closeout (was OH8 + OH9 + OH10 + OH11)

Spec: oh1-construction-landscape-contract.md §landscape; retail LScape::draw_check_blocks, landcell_check, get_clip_height, block_check, CLandCell::IsInView (previous-frame), CEnvCell::IsInView (constant PARTIALLY_INSIDE); DrawBuilding degrade selection; the fixed-function material stage for translucent detail (AP-232).

Behavior change: the landscape walk produces the exact retail landcell in_view set; frustum/AABB reconstruction is replaced for every IsInView consumer (particle update/degrade, point-light snapshots, directional-shadow selection); the Extended particle range remains a deliberate post-retail option, Retail mode applies no multiplier; AP-117 retired or narrowed. Building degrade selection and complete-body gate exact; translucent detail combine reproduces retail's single stage result with framebuffer-equivalence fixtures; one audited world-subset state policy table; AP-232 retired. Then delete every obsolete owner, fallback, flag, probe, and stale claim, add the architectural guards, and run the full closeout.

Cleanup inventory (delete or retire): competing membership dictionaries; origin-cell and visual-AABB fallbacks; disproved generic per-view clip rules; whole-stage terrain events; unconditional clear code; scope-global alpha ordering; ACDREAM_PROBE_CATHEDRAL_* skip flags and the carrier-discriminator code; ACDREAM_PROBE_FACILITY_STAIRS and WbDrawDispatcher.FacilityStairProbe with its call sites in RetailPViewRenderer, WalkPView, WalkProductionWorldData, WalkStaticStreamPopulator, WbDrawDispatcher.OrderedStream/WalkClassify; obsolete shell-lift, bias, stencil, corrective-redraw, suppression tests; PortalVisibilityBuilder research code out of production; stale launch-option rows; architecture claims contradicted by code. Guards: one WalkPView/graph owner in the production call graph; renderer cannot query DAT; consumers cannot construct independent visibility sets; the submitter cannot sort across semantic boundaries; no production reference to OH diagnostic symbols.

Automated closeout: full Release build; focused App/Content/Core/Runtime/ Launcher suites; hermetic lane Lane!=InstalledDat&Lane!=Linux&Lane!=Manual&Lane!=Timing&Lane!=Live&Lane!=PreparedPackage; installed-DAT lane with exclusions listed; two deterministic geometry/ membership runs with equal hashes; transcript equality over all fixtures; capped/uncapped lifecycle/reconnect routes; R6 nine-stop; portal in/out with long destination prep; graceful shutdown with zero retained rows.

Performance checkpoint: dense Arwic capped/uncapped, Tusker dense scene, cathedral floating stairs, Facility Hub; CPU/GPU p50/p99, FPS, draw counts, allocation/frame, memory, retained graph/membership bytes, alpha high water. A regression over 20% against the recorded pre-OH baseline triggers an explicit optimization slice (merge adjacent runs, reuse storage; never reorder, cull, or weaken the transcript).

Owner gate G4 — final matrix. Repeats G1G3 on one clean binary and adds: two-client cathedral wall occlusion; Facility Hub stair circuit; Nanto waterfalls and town; Tusker combat/casting/rotation; Holtburg town/building/ lifestone; two ordinary dungeons chosen without code changes; portal to/from each world type; zoom/pan/rotate at seams; ten minutes of free movement. Per row PASS/FAIL with location and symptom. The final binary is not rebuilt after acceptance except for documentation-only changes.

Documentation closeout: architecture doc (actual graph and pipeline), inventory (asset extraction only, never visibility ownership), divergence register reconciliation, launch options after probe deletion, FW ledger superseded not deleted, roadmap/milestones, campaign memory. Then merge to main. Status changes to CLOSED — USER ACCEPTED only after G4 and docs match code.


10. Canonical scene and symptom matrix

Scene Fixed coordinates/state Required invariant Slices
Cathedral south transition 0xF4180106 [37.181568 46.790077 169.804993]0xF4180104 [37.310383 48.895710 169.804993] Player and walls whole; no wand/body depth inversion S3S4
Cathedral wall actor Observer 0x104, 0x101, outdoors; remote in 0xF4180112 [36.299465 18.594580 169.804993] Actor visible only through a retail-valid sightline S2S4
Cathedral floating stairs 0xF4180107 [38.311169 24.270454 177.423584]0xF4180112 [38.333950 23.704699 177.868729] Every slab stable; no moving wall-textured triangles S1S4
Cathedral exterior ramp Stand on the formerly invisible ramp Authored shell/member always renders S1S3
Facility Hub stairs 0x8A02015E [60.971485 -42.752495 -4.121752], 0x8A02015F [58.815380 -49.425373 -0.857726] Stairs/player stable at bottom, side, ascent, top, zoom S1S4
Nanto waterfalls 0xE43D001E [93.826614 126.522484 120.005005] Falls do not vanish while rotating; houses occlude S4S5
Tusker Island Owner's dense combat route Terrain/scenery/actors stable; spell objects retire S2, S3, S5
Holtburg Town route Buildings intact; particles/lifestone obey depth S3S5
Ordinary dungeons Two, chosen before code changes No cathedral overfit; stairs/walls/portals stable all

Append-only; a new symptom gets a row and an existing invariant before any fix.


11. Test and command policy

dotnet build AcDream.slnx -c Release
dotnet test tests\AcDream.Content.Tests\AcDream.Content.Tests.csproj -c Release --no-build
dotnet test tests\AcDream.Core.Tests\AcDream.Core.Tests.csproj -c Release --no-build
dotnet test tests\AcDream.Runtime.Tests\AcDream.Runtime.Tests.csproj -c Release --no-build
dotnet test tests\AcDream.App.Tests\AcDream.App.Tests.csproj -c Release --no-build
dotnet test tests\AcDream.Launcher.Core.Tests\AcDream.Launcher.Core.Tests.csproj -c Release --no-build

Focused --filter runs are for iteration; a slice closes on the full families above plus the hermetic lane. Record exact commands and counts in §13.

Launch discipline: every launched candidate is a green Release build from a recorded commit; all behavior-changing probes unset; the owner is told the exact commit, recipe, and log path; the owner closes the client.


12. Instrumentation lifecycle

  • One print-only transcript flag for the frame walk, introduced in S3 chunk 1, documented in docs/launch-options.md in the same commit, output-only, never read by any draw decision.
  • Slice-local comparators (S2 old-vs-new membership) live and die inside the slice.
  • Existing ACDREAM_PROBE_CATHEDRAL_* / ACDREAM_PROBE_FACILITY_STAIRS flags stay unset and untouched until S5 deletes them.
  • No agent adds a probe outside its chunk contract.

13. Execution ledger

Update immediately when a slice changes state. Chat is not the ledger.

Slice Status Spec Implementation Reviews Automated gate Owner gate Notes
v1 OH0 CLOSED oh0-baseline.md b3b7d922 read-only classification Release build green; 319 focused / 1 skip n/a historical; candidates it committed are S1/S2 seeds
v1 OH1 SUPERSEDED research contracts committed at 5cd4fd2c/5d907ae9 (kept, binding) T0T3 evidence grammar parked on quarantine/oh1-evidence-grammar-2026-09-02 reviews found the grammar a false oracle three times n/a n/a see §15
S1 Geometry IMPLEMENTED + REVIEWED — G1 PENDING oh2-cellstruct-surface-contract.md (§3.5 arbitrated on the binary 2026-09-02) chunk A acf17246; chunk B b681717c; hygiene 0840d5fb; review-fix round (see notes) lead verified both chunks against the named pseudo-C and the paired binary (absent-UV rule corrected before landing); two Opus lens reviews (retail, data/architecture) returned 8 distinct anchored findings, all verified by the lead and fixed: anomalous sides value now takes retail's default single-side shape instead of dropping; per-polygon mask OR hoisted before the degenerate guard; untextured slots no longer bake vertices; failed slot/texture lookups memoized once per slot; cell-shell upload order is ascending source surface index; HasDrawableGeometry doc corrected; equivalence sweep cell half pinned at zero; InAscendingSurfaceOrder marked bake/upload/test-only build 0/0; Content 213/213 (Lane!=Timing incl. PreparedPackage on the recipe-8 pak); Core 4,947/4,948 with the one failure CollisionShadowVerifierTests.DisabledGraphTraversal_AllocatesZeroBytes (allocation measurement outside S1 files; passed in the previous full run, rerun in isolation below); Bake 21/21; Launcher.Core 365/365 (Lane!=Linux); Runtime 1,884/1,884; App hermetic 6,757/6,757 G1 pending dev pak rebaked twice to recipe 8 (final 597,369,112 B, 0 failures, acdream.recipe7.pak kept); TOC 2,237,866 → 2,237,865 explained (one unreferenced solid-color texture payload; all 729,888 cell mesh keys present); corpus scan 5,346 landblocks / 729,888 cells / 8,601,560 polygons, old-only 3,197 (all untextured), new-only 0, unexplained 0, anomalous sides 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 PLANNED oh1-construction-landscape-contract.md G2 seeds in b3b7d922
S3 Walk PLANNED built-mesh/world contracts + captures folded into G3
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

Rollback ledger

Slice Commits Last accepted gate Revert
FW closeout b8befded, 4808d4d1, 4683ac6f, e8808602 FW/Tusker gates historical anchors only
v1 OH0 b3b7d922 n/a git revert b3b7d922 removes the investigation candidates including the Facility stair fix; not a visual claim
S1 G1 fill during execution; restore acdream.recipe7.pak
S2 G2 fill
S3 G3 fill
S4 G3 fill
S5 G4 fill

14. Risk register (condensed)

  • R1 second scene graph. Graph records own only topology/membership facts; mesh/entity state is borrowed. Consumer deletion is inside S2.
  • R2 over-porting C++ mechanics. Port observable ordering, ownership, stamps, and transitions into retained arrays; equality by transcript.
  • R3 Vulkan reorders. Immutable stream; only adjacent compatible runs merge; tests place merge-compatible draws around alpha/depth boundaries.
  • R4 package churn. S1 owns one recipe bump with strict rejection, migration, rollback, corruption tests, launcher coverage.
  • R5 oracle incompleteness. The §7 capture is the answer key; a missing fact gets one exact additional capture, never an approximation.
  • R6 scene overfitting. Production guards reject scene IDs; installed-DAT sampling and ordinary-dungeon gates are mandatory.
  • R7 per-cell command cost. Correctness-first; the 20% rule triggers an explicit optimization slice.
  • R8 stale docs. S5 cannot close until architecture text is checked against production call sites.
  • R9 evidence sink (new). Rule 2 and rule 15. A slice with no production change after its first chunk is a red flag, not progress.

15. v2 rescope record (2026-09-02)

What happened. v1's OH1 ("upgrade the oracle first") ran unsupervised for eighteen hours and produced ~32K lines of uncommitted canonical-JSONL evidence grammar plus 142 tests, three review rounds each finding the grammar encoded wrong retail semantics, and zero production change. The grammar re-encoded PView inside a validator, making it a second port that needed the same retail review; it also validated "strong" evidence that neither the retail captures nor the acdream recorder produced. The one unlocking item, extending the cdb capture templates, was never started.

What v2 keeps. All committed research contracts; the FW0 capture corpus and its proven line-format + parser + replay pattern (which reached 9/10 conformant fixtures in FW1); the b3b7d922 candidates as S1/S2 seeds; the retail facts the T3 reviews established (handoff §5.3).

What v2 parks. The evidence grammar, recorder hooks, importer, manifest command, and their docs, verbatim, on quarantine/oh1-evidence-grammar-2026-09-02.

Stage mapping. OH2 → S1; OH3ad → S2; OH4 + OH5 → S3; OH6 + OH7 → S4; OH8OH11 → S5. Owner gates: G1 after S1, G2 after S2, G3 after S4, G4 final.

Process changes. Rules 2 and 15; the §5 working model; the §7 single capture session; evidence products limited to what each slice consumes.

Memory: claude-memory/feedback_evidence_infrastructure_sink.md; claude-memory/project_overhaul_campaign.md is the START HERE.