acdream/docs/plans/2026-09-01-campaign-overhaul-world-solidity.md
Erik e7b6dc03c5 docs(render): OVERHAUL ledger — G2 PASSED by the owner, S2 closed
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-03 06:30:29 +02:00

731 lines
49 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# 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)
```text
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 (revised 2026-09-02 from the ownership trace in
`s2-membership-ownership-map.md`):**
1. Retail CELLARRAY from the whole part array (per part: physics sphere else
drawing sphere, part box) computed in `ShadowObjectRegistry` at the same
registration call as today's collision flood, retained as a new product
beside `_entityToCells`, plus per-cell part entries (entity, part, GfxObj,
cell frame, clip-planes-required) in registration order. Nothing consumes
it yet; a comparator over installed-DAT fixtures reports retail vs current
collision vs current render cells. Zero pixel change.
2. Render statics cut over to the registry's per-cell part entries; delete
`ResolveStaticRenderCells`, `ComputeStaticRenderCells`, the fingerprint
cache, and App's `FromStaticRenderParts` use. 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. Collision cut over: `_entityToCells`/`_cells` from the same CELLARRAY.
Physics suites, placement/collision replay fixtures, connected nine-stop
route.
4. Dynamics and children: `add_shadows_to_cells` recursion at registration and
movement; particles own-cell; delete the render-side parent-chain walk.
Fixtures: local/remote player, NPC, projectile, spell world object,
equipped child, contained child, indoor portal crossing, outdoor crossing,
teardown/reconnect.
5. Consumer cutover and deletion: remaining `WalkProductionWorldData` buckets
become borrowed views, particle owner union reads the same, duplicate
dictionaries and origin-cell/visual-AABB fallbacks are deleted. Lights and
directional shadows stay for S5. Topology triplication (`LoadedCell` /
`WalkCell` / flat asset) is consolidated with S3's `WalkPView` state, not
here.
**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.
---
### Self-gate poses (owner-supplied 2026-09-02)
The lead may run owner gates itself: launch the Release client at a recorded
commit through a session config (direct character login, no select screen),
teleport with the server command below (`/teleloc <cell> <x> <y> <z> <qw> <qx>
<qy> <qz>`), screenshot each pose into the automation artifact directory, read
the PNGs, and record PASS/FAIL per pose in §13. The owner double-checks in the
morning; a self-passed gate stays provisional until then.
| Pose | Command |
|---|---|
| Cathedral floating stairs | `/teleloc F4180112 38.999477 23.470444 178.053741 -0.980785 0.000000 0.000000 -0.195090` |
| Facility Hub stairs | `/teleloc 8A02015E 60.251431 -38.848198 -5.995000 0.995004 0.000000 0.000000 -0.099833` |
| Holtburg house interior | `/teleloc A9B4013F 134.555893 11.423566 94.005005 0.996917 0.000000 0.000000 -0.078459` |
Add the §10 matrix coordinates and the four retail capture poses
(`docs/research/2026-08-30-fw-walk-oracle/posed/`, `P` lines: cell, origin
xyz, quaternion) as further stops when a gate needs them.
---
## 11. Test and command policy
```powershell
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 | **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 | CLOSED — G2 PASSED (owner, 2026-09-03): Facility Hub PASS, Holtburg house PASS, cathedral leak unchanged/not worse (S3/S4 target), portal haze FIXED by chunk 6 and owner-confirmed; the terrain doorway-punch finding is carried to S4; the chunk-6 retail-lens review is the one open item | `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 (retail's zero-sphere `find_cell_list` 0x0052b4e0, verified statically 2026-09-03 — AD-117 item 1 dropped), 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). Connected R6 soak on the FINAL S2 build (`logs/connected-r6-soak-20260903-010403.report.json`, binary matches source, exit 0, graceful=True): 9 canonical checkpoints, 0 failures, 10 warnings (server-side population drift + DAT VFX table messages), 522 s — route PASS. OWNER G2 CHECK 2026-09-03 (client at `4b0b29e4`): Facility Hub PASS, Holtburg house PASS; cathedral: the original leak unchanged, NOT worse (S3/S4 target, G2 bar met); TWO NEW OWNER FINDINGS block G2 closure — (a) parts of buildings leak through terrain outdoors in Holtburg — owner screenshot shows doorway-sized fragments of the houses on the terrace BELOW showing through the hill; mechanism identified: `PortalDepthMaskRenderer` draws every visited cell's `OtherCellId == 0xFFFF` portal fan (`RetailPViewPassExecutor` `DrawDepthFan`) with depth compare `Always` + depth write, so a building doorway BEHIND terrain still punches far depth through the hill and the interior draws through the hole; retail's far punch cannot be `Always` against terrain — the exact z-func is S4's first question (the #117 punch stencil is already on S4's delete list; the retail-world contract §5.4 wording must be re-read at the capture). Pre-existing (not an S2 regression), assigned to S4; (b) the purple portal-exit haze on the character no longer appears on arrival — ROOT CAUSE FOUND (instrumented runs `logs/selfgate-20260903-053731-haze-candidate`, `…-054153-haze-candidate-2`, chunk-4 control `…/bisect-chunk4/logs/selfgate-20260903-054328-haze-chunk4`): the server keeps the player Hidden until acdream sends LoginComplete at reveal `complete` (retail-correct); the Hidden-state script's emitters spawn in the arrival cell at `materialized`, are view-eligible at `world-visible`, and are never DRAWN (frame `h02-arrive-400ms`: room, no character, no cloud) because the walk draws an owner's emitters only through the owner's registry rows and a hidden owner's shadow is suspended; the deleted chunk-5 fallback used to carry them. Retail gives every emitter its OWN cell membership (`add_particle_shadow_to_cell` 0x00514a70, one shadow in its own cell, no clip planes, drawn at that cell's turn regardless of the parent's hidden state) — the branch AD-117 item 4 had deferred as 'no production path'. Fix = S2 chunk 6 `f6b4584b` (packet §10): `ParticleSystem` per-pass cell→handles index + `DrawForCell`; the walk draws particles BY CELL at the existing turns; every owner-union particle path deleted; the post-replay per-cell pass deleted (it double-submitted the root flood — the implementer flagged it, the lead verified `EmitCellContentsTurn` fires `CellParticles` for root-flood and look-in cells alike); AD-117 item 4 → port note; temporary probes removed. VERIFIED: `logs/selfgate-20260903-062522-haze-chunk6` frame `h02-arrive-400ms` shows the purple cloud at the character in Facility Hub; three-pose self-gate `logs/selfgate-20260903-062615-s2-chunk6` in the accepted band (cathedral 12.7% / Facility 15.1% / house 13.9% px vs baseline, wall-panel mean 79,20,25), zero exceptions. Gates at `f6b4584b`: Core 4,987/4,987; Content 214/214; Runtime 1,884/1,884; App hermetic 6,760/6,760; App InstalledDat 217 / 2 pre-existing #383. Owner re-check of the haze: CONFIRMED FIXED 2026-09-03 ("Ok yeah it is fixed now"). 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 (the S3 packet §7 names the two traces); then S3 |
| 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 |
### 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 | `acf17246`, `b681717c`, `0840d5fb`, `e2543d0e`, `8c6563ca` (+ pin test) | G1 PASS 2026-09-02 | revert newest-first; then restore `acdream.recipe7.pak` over `acdream.pak` in the dev DAT dir (the recipe-8 consumer rejects a recipe-7 pak, and vice versa) |
| S2 | `059b8883`, `5a2792d6`, `707d2803`, `afbd2410`, `75ea269d`, `c94a1a40`, `f6b4584b` | G2 PASSED 2026-09-03 (owner-confirmed after the chunk-6 haze fix; terrain punch carried to S4) | revert newest-first `c94a1a40` → `059b8883`; the registry's retail product and the walk's borrowed views go together — do not revert a middle chunk alone |
| 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.