docs(render): rescope Campaign OVERHAUL to five production slices

v2 replaces the twelve-stage plan. OH1's evidence-grammar stage is parked
on quarantine/oh1-evidence-grammar-2026-09-02; the committed research
contracts stay binding. Stage mapping: OH2 -> S1, OH3 -> S2, OH4+OH5 -> S3,
OH6+OH7 -> S4, OH8-OH11 -> S5. Adds the working model (lead in the loop,
bounded chunks, time-box), the single retail capture session before S3,
and per-slice minimal evidence products. Carries the InitCell inflag
prose correction in the flood appendix and marks the T3 handoff superseded.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
This commit is contained in:
Erik 2026-09-02 17:50:25 +02:00
parent 5d907ae9ad
commit 13fc7d8349
3 changed files with 1077 additions and 1444 deletions

File diff suppressed because it is too large Load diff

View file

@ -6,7 +6,18 @@ Second read round: the interior-flood and view-support functions. Same method as
### PView::InitCell @0x005a4b70
**Summary:** Initializes the cell's TOP portal_view slot (portal_view.data[num_view-1]) for the flood: stamps view_timestamp = master_timestamp, clears cell_view_done, grows the per-portal portal_info array to num_portals, classifies every portal as in-view (inflag) or rejected via a cell-local viewpoint-vs-portal-plane side test, computes max_indist = max SQUARED viewpoint distance to any in-view portal vertex, and marks every rejected portal seen=1 so the flood never traverses it. The entry portal (real index; 0xffff sentinel never matches) is forced inflag=1 + seen=1 instead of side-tested.
**Corrected summary (2026-09-02, x87 branch re-arbitrated):** Initializes the
cell's TOP portal_view slot (`portal_view.data[num_view-1]`) for the flood:
stamps `view_timestamp = master_timestamp`, clears `cell_view_done`, grows the
per-portal `portal_info` array to `num_portals`, and classifies every portal by
the cell-local viewpoint/plane side test. The names are deceptive:
`ClipPortals` considers exactly `seen != 0 && inflag != 1`, so `inflag == 0`
is the traversable candidate state and `inflag == 1` is excluded. The entered-
through portal is forced to `inflag=1, seen=1` and is therefore excluded as the
backlink. `max_indist` is the maximum SQUARED viewpoint distance over the
`inflag == 1` portal vertices—the excluded/incoming/back-facing set—not the
traversable set. The earlier prose labels in this report inverted this meaning;
the assignments themselves were correct.
```c
int PView::InitCell(CEnvCell* cell, uint16 entry_portal_idx) // Ghidra: returns int; BN said void
@ -21,12 +32,12 @@ int PView::InitCell(CEnvCell* cell, uint16 entry_portal_idx) // Ghidra: returns
DArray<portal_info>::grow(&slot->portal, cell->num_portals); // exact-size; NEW entries UNINITIALIZED
float max_d2 = 0.0f;
int any_rejected = /*UNINITIALIZED stack dword — see gotchas*/;
int any_candidate = /*UNINITIALIZED stack dword — see gotchas*/;
for (i = 0; i < cell->num_portals; i++) { // CCellPortal stride 0x18
CPolygon* poly = cell->portals[i].portal;
if (i == entry_portal_idx && slot->portal.data[i].inflag == 0) {
// entered-through portal: forced visible + consumed (0xffff seed sentinel never hits this)
// entered-through backlink: forced excluded + consumed (0xffff seed sentinel never hits this)
slot->portal.data[i].inflag = 1;
slot->portal.data[i].seen = 1;
} else {
@ -36,10 +47,10 @@ int PView::InitCell(CEnvCell* cell, uint16 entry_portal_idx) // Ghidra: returns
int side; // 0=POSITIVE, 1=NEGATIVE
if (d > F_EPSILON) side = 0; // F_EPSILON = 0.000199999995f
else if (d < -F_EPSILON) side = 1;
else { slot->portal.data[i].inflag = 0; any_rejected = 1; goto vertex_scan; } // IN_PLANE: always reject
else { slot->portal.data[i].inflag = 0; any_candidate = 1; goto vertex_scan; } // IN_PLANE: traversable candidate
if (side != cell->portals[i].portal_side)
slot->portal.data[i].inflag = 1; // viewer on the see-through side
else { slot->portal.data[i].inflag = 0; any_rejected = 1; } // viewer on the portal's own side
slot->portal.data[i].inflag = 1; // excluded by ClipPortals
else { slot->portal.data[i].inflag = 0; any_candidate = 1; } // traversable candidate
}
vertex_scan:
if (slot->portal.data[i].inflag == 1 && poly->num_pts > 0) // num_pts = byte @ +0xe
@ -48,14 +59,14 @@ vertex_scan:
if (max_d2 < d2) max_d2 = d2;
}
}
slot->max_indist = max_d2; // max squared distance to any in-view portal vertex
slot->max_indist = max_d2; // max squared distance over inflag==1 (excluded) portal vertices
if (any_rejected != 0 && slot->view_count > 0)
if (any_candidate != 0 && slot->view_count > 0)
for (v = 0; v < slot->view_count; v++) {
Render::set_view(&slot->view, v); // installs global active view; the check below does NOT read it
for (j = 0; j < cell->num_portals; j++)
if (portal[j].inflag == 0 && portal[j].seen == 0)
portal[j].seen = 1; // rejected portals become 'consumed': flood never walks them
portal[j].seen = 1; // makes inflag==0 portals eligible for ClipPortals
}
slot->update_count = slot->view_count;
@ -64,7 +75,29 @@ vertex_scan:
}
```
**Gotchas:** BN body @0x005a4b70 is UNUSABLE: it scrambled the x87 side-test control flow AND elided the squared-distance math (showed only the z subtraction). This model is Ghidra-verified (127.0.0.1:8081). Confirmed semantics: side==portal_side rejects, IN_PLANE (|d|<=0.000199999995f) always rejects — matches the FW doc's sidedness table. Real retail quirks: (1) any_rejected (local_4) is NEVER initialized — if no portal is rejected it reads stack garbage; the effect is benign (the fixup inner body no-ops when nothing was rejected; only side effect is redundant set_view churn), so a port should init it to 0 with identical observable behavior. (2) The entry-portal branch is guarded by the STALE inflag (inflag==0) — on a freshly grown portal array inflag is heap garbage (DArray::grow does NOT zero new entries); the caller (AddViewToPortals) presumably establishes it — verify that contract when porting FW3. (3) set_view inside the fixup loop installs each view globally but nothing in the loop consults it, and the LAST view stays installed on exit — both decompilers agree; purpose unclear (possibly vestigial). (4) positionPush(3, cell->pos) means the plane test and max_indist run in CELL-LOCAL coordinates. (5) 0xffff sentinel: ushort zero-extended vs uint loop index — never matches, so the seed cell side-tests every portal. (6) max_indist is a SQUARED distance — todo-list keys fed from it are squared; comparisons stay consistent. Ghidra return type is int (0 = early-out on view_count==0, 1 = did work); BN said void __stdcall.
**Gotchas:** BN body @0x005a4b70 is UNUSABLE: it scrambled the x87
side-test control flow AND elided the squared-distance math (showed only the z
subtraction). The x87 branch was re-arbitrated against retail bytes
`005A4C48..005A4C9D` on 2026-09-02. Confirmed semantics:
`side==portal_side` and IN_PLANE (`|d|<=0.000199999995f`) produce
`inflag=0`, which is the traversable candidate state because `ClipPortals`
later requires `seen!=0 && inflag!=1`; side mismatch produces the excluded
`inflag=1` state. Real retail quirks: (1) `any_candidate` (`local_4`) is NEVER
initialized—if no candidate exists it reads stack garbage; the effect is
benign because the fixup inner body no-ops, leaving only redundant `set_view`
churn, so a port may initialize it to zero with identical observable behavior.
(2) The entry-portal branch is guarded by stale `inflag`; it forces the
entered-through backlink to the excluded/seen state. On a freshly grown portal
array `inflag` is heap garbage (`DArray::grow` does not zero new entries), so
the caller contract remains significant. (3) `set_view` inside the fixup loop
installs each view globally but nothing in the loop consults it, and the LAST
view stays installed on exit. (4) `positionPush(3, cell->pos)` means the plane
test and `max_indist` run in CELL-LOCAL coordinates. (5) The `0xffff` seed
sentinel never matches, so the seed cell side-tests every portal. (6)
`max_indist` is a SQUARED distance over `inflag==1` portal vertices; todo-list
comparisons stay internally consistent even though that set is excluded from
traversal. Ghidra return type is int (0 = early-out on `view_count==0`, 1 =
did work); BN said void `__stdcall`.
### PView::InsCellTodoList @0x005a4f50
@ -147,7 +180,25 @@ void CEnvCell::curr_view_push()
**Gotchas:** VERIFIES the earlier read: num_view++ with 0x48-byte lazy slot alloc + counter resets — with precision: exactly view_count/update_count/view_timestamp are reset on EVERY push (fresh or recycled); cell_view_done and max_indist are NOT reset here and stay stale (heap garbage on a brand-new slot) until PView::InitCell writes them — InitCell always runs before they are consumed, but a port must preserve that ordering or zero them harmlessly. The single-slot null after grow is sound only because this DArray grow(n) sets sizeOf to EXACTLY n (verified @0x005a45d0: copies old, sizeOf=arg; blocksize unused by grow; grow with arg<=sizeOf delegates to shrink) — no hidden capacity slack, so no garbage slots. portal_view_type layout confirmed in acclient.h: {DArray<portal_info> portal @0; view_type view @0x10 (vertex_count_total, poly@0x14, vertex@0x24); max_indist @0x34; view_count @0x38; cell_view_done @0x3c; view_timestamp @0x40; update_count @0x44}; DArray = {data, blocksize, next_available, sizeOf}.
**Report notes:** All four bodies cross-checked against live Ghidra MCP (http://127.0.0.1:8081, patchmem.gpr) — mandatory here, because BN got two of them materially wrong: (1) InsCellTodoList's insertion comparison was polarity-INVERTED in BN (would have modeled a farthest-first pop); Ghidra's strict `dist < prev->dist` break gives a descending-from-index-0 list whose END-pop is NEAREST-first, which is what makes the draw list come out near->far and DrawCells' end-first walk far-to-near — consistent with FW doc section 5. (2) InitCell's BN body scrambled the plane-side branches and elided the dx^2+dy^2+dz^2 accumulation entirely (showed a bare z subtraction). Ghidra-confirmed model: side 0/1 vs portal_side rejects on equality, IN_PLANE always rejects (matches the doc's section 7 sidedness table), max_indist = max SQUARED cell-local distance to in-view portal vertices, and rejected portals get seen=1 in a fixup pass whose per-view set_view calls are side-effect-only. Two genuine retail quirks worth register-awareness if ported observably: InitCell's any_rejected flag is an uninitialized stack read (benign in effect), and the entry-portal force-visible branch keys off STALE inflag whose state is a caller contract (read PView::AddViewToPortals before relying on it in FW3). Struct authorities verified in acclient.h: portal_info {seen, inflag}; portal_view_type (0x48 bytes, field offsets in the curr_view_push gotchas); PView {outside_view, draw_landscape, outdoor_portal_list, cell_draw_list, cell_draw_num, cell_todo_list, cell_todo_num, lscape}; CellListType nodes are 8-byte {CEnvCell* cell, float dist}; CPolygon {vertices@0, num_pts byte@0xe, plane@0x20}. Sources: docs/research/named-retail/acclient_2013_pseudo_c.txt lines 311378-311393, 432896-433045, 433183-433243, 433279-433320; DArray grow/shrink @0x005a45d0 region; struct defs in docs/research/named-retail/acclient.h (portal_info @32458, portal_view_type @32346, view_type @32338, PView @45934, CPolygon @31855).
**Report notes (corrected 2026-09-02):** All four bodies were
cross-checked against the live Ghidra project; the load-bearing branches were
then re-arbitrated against the retail bytes because the earlier prose assigned
the intuitive but wrong meaning to `inflag`. (1) `InsCellTodoList` uses strict
`dist < prev->dist` as its break, giving a list descending from index zero and
nearest-first END pops, with FIFO ties. (2) `InitCell` writes `inflag=0` for
`side==portal_side` and IN_PLANE, then its fixup writes `seen=1`; those rows
are precisely the candidates later admitted by `ClipPortals`'s
`seen!=0 && inflag!=1` gate. Side mismatch and the entered-through backlink
use `inflag=1` and are excluded. `max_indist` is the maximum squared
cell-local distance over the `inflag==1` portal vertices, not over the
traversable candidates. Two genuine retail quirks remain relevant:
`local_4` is an uninitialized stack read, and the entry-portal branch keys off
stale `inflag` state established by the caller/allocation history. Struct
authorities remain `portal_info {seen,inflag}`, `portal_view_type` (0x48
bytes), `PView`, `CellListType {cell,float dist}`, and `CPolygon`. Sources:
named-retail lines 311378-311393, 432896-433045, 433183-433243, and
433279-433320; retail bytes `005A4C48..005A4C9D`; DArray grow/shrink near
`0x005A45D0`; and the named retail header definitions.
## Report 2 - Flood propagation (ClipPortals / AddViewToPortals)

View file

@ -0,0 +1,464 @@
> **SUPERSEDED 2026-09-02 (same day) by the v2 rescope.** This handoff describes the v1 OH1/T3 freeze. Its section 8 dirty-tree map is WRONG: the dirty App rendering files were T2 recorder hooks, not pre-overhaul behavior candidates (those were already committed in `b3b7d922`). The T3 grammar it describes is parked on `quarantine/oh1-evidence-grammar-2026-09-02`. Section 5.3 (retail truths bound by T3) remains a binding input to S3/S4. Current plan: `docs/plans/2026-09-01-campaign-overhaul-world-solidity.md` §15.
# Campaign OVERHAUL handoff — OH1/T3 freeze
**Frozen:** 2026-09-02 (Europe/Stockholm)
**Campaign state:** active; not complete
**Current slice:** OH1, transcript task T3
**T3 state:** third implementation/fix round is locally green, but independent
closure review is still required
**Production rendering claim:** none. OH1 is evidence/contract work and must not
change draw decisions.
This is the durable handoff for a new model. It records the exact checkout,
history, dirty-state constraints, campaign ledger, current automated evidence,
review findings, and the next safe actions. Do not reconstruct state from chat
summaries when this file and the campaign ledger disagree with them.
## 1. Exact checkout and recovery boundary
Work only in this existing worktree:
```text
C:\Users\erikn\source\repos\acdream\.claude\worktrees\peaceful-blackburn-5333f0
```
Repository state at the freeze:
| Field | Value |
|---|---|
| Branch | `claude/campaign-w-retail-frame-walk` |
| HEAD | `5d907ae9ad9462347eb697c39ae3ffac136a40bc` |
| Upstream | `origin/claude/campaign-w-retail-frame-walk` |
| Upstream relation | ahead 32, behind 0 at the freeze |
| Staged paths | 0 |
| Latest commit | `5d907ae9 docs(render): define OH1 retail world contract` |
| Recovery checkpoint | `b3b7d922 checkpoint(render): preserve pre-overhaul investigation state` |
Recent history:
```text
5d907ae9 docs(render): define OH1 retail world contract
5cd4fd2c docs(render): define OH2 CellStruct contract
eaea8776 docs(render): clean OH0 baseline formatting
fba07e77 docs(render): establish Campaign OVERHAUL baseline
b3b7d922 checkpoint(render): preserve pre-overhaul investigation state
e8808602 fix(render): restore landscape objects and walk alpha order
4683ac6f docs(render): record Campaign FW closeout gates
4808d4d1 refactor(render): remove Campaign FW probes
```
The current T3 work is deliberately **uncommitted**. Do not reset, clean,
checkout, or wholesale copy another tree over this checkout. The dirty tree
contains both intentionally preserved pre-overhaul investigation candidates and
new OH1 evidence tooling. Follow the recovery procedure in `oh0-baseline.md`.
In particular:
1. Never use `git reset --hard`, `git checkout --`, or `git clean` here.
2. Do not treat every dirty App rendering file as OH1 work.
3. To inspect an older state, use a separate detached/read-only worktree.
4. To recover through history, revert OH commits in reverse order and stop at
`b3b7d922`; do not rewrite history.
5. Before staging, inspect each path and exclude line-ending/blank-line noise.
## 2. Goal and campaign scope
The active goal is:
> Complete Campaign OVERHAUL — retail world construction and render solidity —
> in this worktree by executing every Plan → Implement → Review slice, using
> deterministic retail evidence, independent review, automated gates, and only
> the necessary owner visual gates, until the campaign is user-accepted and
> closed.
The campaign exists because locally plausible fixes repeatedly traded one world
artifact for another. The accumulated owner-observed symptom family includes:
- Cathedral opaque walls or wall-textured triangles covering floating stairs;
- floating stair slabs appearing/disappearing with camera angle or cell seam;
- the cathedral exterior ramp being entirely absent despite supporting the
player physically;
- wall, terrain, or building textures bleeding through other opaque surfaces;
- the local character being chopped at cathedral and Facility Hub cell seams,
including a missing head/body sections and equipment drawing through it;
- remote players/NPCs and particle systems appearing through opaque walls;
- waterfalls disappearing by camera angle, or shining through buildings;
- outdoor terrain/scenery/object groups disappearing after small camera turns;
- landscape draw range regressions; and
- spell effect world objects lingering after their authored lifetime.
Some preserved dirty-tree candidates improved individual symptoms, but they are
explicitly **unaccepted** and are not a retail-parity baseline. The overhaul is
meant to replace approximation-by-symptom with one executable retail contract
covering authored geometry, cell membership, PView traversal, leaf admission,
draw order, depth, alpha, and downstream consumers.
## 3. Mandatory read order and active ledgers
Read these before editing:
1. `AGENTS.md` in the repository root.
2. `docs/architecture/acdream-architecture.md` — architecture authority.
3. `docs/architecture/worldbuilder-inventory.md` — mandatory before any
rendering or DAT algorithm is reimplemented.
4. `docs/plans/2026-09-01-campaign-overhaul-world-solidity.md` — the campaign
plan and primary execution ledger.
5. `docs/research/2026-09-01-overhaul/oh0-baseline.md` — exact dirty-state
classification, hashes, baseline gates, and recovery procedure.
6. `docs/research/2026-09-01-overhaul/oh1-retail-world-contract.md`.
7. The four supporting OH1 evidence packets:
- `oh1-construction-landscape-contract.md`
- `oh1-built-mesh-view-contract.md`
- `oh1-alpha-list-contract.md`
- `oh1-depth-lifecycle.md`
8. `docs/research/2026-09-01-overhaul/oh1-world-evidence-tooling.md` — the
active OH1 tooling/status ledger.
9. `docs/research/2026-09-01-overhaul/oh2-cellstruct-surface-contract.md`
completed OH2 design, not authorization to skip unfinished OH1 work.
10. `docs/research/2026-08-30-fw-flood-pseudocode-appendix.md` — corrected
PView/flood pseudocode and signedness/branch details.
Historical cathedral context remains useful after the overhaul plan and OH0
classification have been read:
- `docs/research/2026-08-30-cathedral-handover.md`
- `docs/research/2026-08-30-cathedral-synthesis.md`
- `docs/research/2026-08-30-fw-walk-oracle/posed/`
Retail source authority:
- `docs/research/named-retail/acclient_2013_pseudo_c.txt`
- `docs/research/named-retail/acclient.h`
- `docs/research/decompiled/` only as the older address-range fallback.
Grep the named retail decomp by `class::method` before decompiling anything
fresh. When Binary Ninja or recovered pseudo-C leaves a branch sense ambiguous,
use the existing Ghidra arbitration workflow; do not choose the branch that
merely makes current tests green. Content identity must be traced to the DAT,
not inferred from aggregate owner IDs.
The campaign plan contains three important ledgers:
- stage/owner-gate table around lines 434445;
- checkpoint ledger around lines 14611473; and
- execution ledger around lines 15611575.
The execution ledger is authoritative over the plan header's older
`READY TO EXECUTE` wording.
## 4. Campaign progress at the freeze
| Scope | State | Durable result | What remains |
|---|---|---|---|
| OH0 | **CLOSED** | Dirty tree classified; recovery checkpoint `b3b7d922`; baseline and source/package hashes recorded | Nothing unless the checkout must be recovered |
| OH1 research contract | **CLOSED/COMMITTED** | Main and four supporting retail contracts at `5d907ae9` | Keep synchronized with executable evidence |
| OH1 T0T2 | **CLOSED** | Canonical schema/codec/hash/coverage foundations, strong frame/call grammar, narrow FW0 importer, and output-only App recorder foundations | Preserve their strict capability boundary |
| OH1 T3 | **IMPLEMENTED, GREEN, REVIEW OPEN** | Source-closed PView, installed-view, DrawCells, shell/object-leaf, and persistent-stamp grammar; third fix round frozen uncommitted | Finish the missing adversarial surface and independent retail/architecture closure review |
| OH1 T4T8 | **PENDING** | No closure claim | Complete landscape/building order, alpha/material, depth lifecycle, recorder/fixture integration, aggregate gates, and OH1 closeout as defined by the plan |
| OH2 design | **CLOSED/COMMITTED** | Exact CellStruct surface/subset contract at `5cd4fd2c` | Production implementation, package migration, deterministic installed-DAT manifest, review, and G1 are not started |
| OH2 implementation | **PLANNED/BLOCKED ON OH1** | None | Start only after OH1's executable contract is review-closed |
| OH3 | **PLANNED** | Canonical cell graph/exact part-shadow membership | Entire slice |
| OH4 | **PLANNED** | Exact PView views and leaf admission/clipping | Entire slice |
| OH5 | **PLANNED** | Exact landscape/building/cell/object interleave | Entire slice |
| OH6 | **PLANNED** | Exact depth epoch, clear latch, punches, seals, stamps | Entire slice plus owner gate G2 |
| OH7 | **PLANNED** | Exact alpha ownership/order/flushes | Entire slice |
| OH8 | **PLANNED** | Exact landscape `in_view` and particle/light/shadow consumers | Entire slice |
| OH9 | **PLANNED** | Building/material/degrade leaf fidelity | Entire slice |
| OH10 | **PLANNED** | Delete duplicate owners/fallbacks/experiments/stale claims | Entire slice |
| OH11 | **PLANNED** | Full regression, performance, connected routes, docs, final acceptance | Entire slice plus final owner gate G4 |
OH2 did not disappear: its **design** was produced in parallel and committed.
Its implementation is intentionally waiting because implementing geometry before
the complete OH1 oracle is review-closed would repeat the campaign's central
failure mode: a green test encoding the wrong retail behavior.
## 5. Current T3 implementation
### 5.1 Purpose and boundary
T3 does not render anything. It defines a strict, canonical JSONL evidence
language in `AcDream.Core.Diagnostics.WorldEvidence` and validators that reject
semantic traces that cannot be a retail PView/DrawCells execution. The schema is
currently unshipped version 4. Do not add a compatibility path for an older
in-progress v4 shape; finish this version atomically unless persisted external
artifacts are discovered.
The third fix round changed only:
- `src/AcDream.Core/Diagnostics/WorldEvidence/WorldEvidenceModels.cs`
- `src/AcDream.Core/Diagnostics/WorldEvidence/WorldEvidenceJsonl.Vocabulary.cs`
- `src/AcDream.Core/Diagnostics/WorldEvidence/WorldEvidenceJsonl.TranscriptShapes.cs`
- `src/AcDream.Core/Diagnostics/WorldEvidence/WorldEvidenceJsonl.cs`
- `src/AcDream.Core/Diagnostics/WorldEvidence/WorldEvidenceJsonl.PViewGrammar.cs`
- `tests/AcDream.Core.Tests/Diagnostics/WorldEvidence/WorldEvidenceJsonlTests.cs`
- `tests/AcDream.Core.Tests/Diagnostics/WorldEvidence/WorldEvidenceT3Tests.cs`
The wider uncommitted OH1 evidence scope also includes:
- `src/AcDream.Core/Diagnostics/WorldEvidence/`
- `src/AcDream.App/Rendering/Walk/Diagnostics/`
- `tests/AcDream.Core.Tests/Diagnostics/WorldEvidence/`
- `tests/AcDream.App.Tests/Rendering/Walk/LegacyWalkOracleImporter.cs`
- `tests/AcDream.App.Tests/Rendering/Walk/LegacyWalkOracleImporterTests.cs`
- `tests/AcDream.App.Tests/Rendering/Walk/WorldFrameTranscriptRecorderTests.cs`
- `tools/A8CellAudit/GeometryManifestCommand.cs`
- `docs/research/2026-09-01-overhaul/oh1-world-evidence-tooling.md`
### 5.2 What round three closed
The third round closed these previously falsifiable gaps:
- route-stage truthfulness;
- distinct source/destination/outside/temporary ViewSet ownership;
- exact previous/current installed-view identity;
- caller-owned restore after `OtherPortalClip`;
- `CellView`/`AddView` state replay and exact append/count ledgers;
- `SetOtherSeen` ordering after branch, recursion, and watermark;
- stronger exact call-body, direct-parent, and grouping validation;
- actual failed-tail-pop evidence for `NullTail`;
- persistent global device, cell-shell, and typed-part stamp ledgers;
- reject-then-accept and all-reject stamp cases;
- global `Render::PortalList` bindings for `ClipPortals` and object-cell turns;
- exact `Render::copy_view(newmethod=1)` algorithm replay rather than checking
only caller-supplied output bytes; and
- deletion of stale `PortalVisit`/legacy `PartAdmit` vocabulary.
This round exists because earlier green versions were independently shown to
be false oracles. Review caught inverted portal-flag and sidedness meanings,
conflated `do_clip`/side state, restore ownership assigned to the wrong
function, conflated view containers, incomplete call/cardinality ledgers,
self-fulfilling `copy_view` tests, and wrong draw-call ownership. Do not close
T3 merely because 153 tests pass.
### 5.3 Retail truths already bound by T3
These are not optional interpretations:
- `portal_info` has raw signed `seen` and `inflag`; a clip candidate is
`seen != 0 && inflag != 1`.
- Retail sidedness is `POSITIVE = 0`, `NEGATIVE = 1`.
- `InitCell` treats `inflag = 0` as a candidate and `inflag = 1` as excluded/
backlink; `max_indist` is computed from final `inflag == 1` vertices.
- Todo storage is farthest at the front and nearest at the tail; tail pop is
nearest-first; equal keys preserve FIFO order.
- `ClipPortals` is two-pass: pass one resolves/liveness globally. If any portal
is live, pass two evaluates every source view against every flag candidate,
including unresolved candidates.
- `OtherPortalClip` resets one function-static temporary view set each epoch.
Its first copy may reject. Its far clip always uses `do_clip = 1`; the far
side is derived separately as
`far.portal_side == POSITIVE ? NEGATIVE : POSITIVE`.
- `ClipPortals`, not `OtherPortalClip`, restores the source view after the
helper returns, including rejection and far-zero paths.
- Source CellView, destination CellView, PView outside view, and the one static
reciprocal temporary view are separate containers.
- `AddToCell` installs every newly appended view unconditionally.
- `SetOtherSeen` occurs only after the completed branch/recursion/watermark.
- `FixCellList` always calls `AdjustCellPlace` and then `AdjustCellView`; the
list move itself remains conditional.
- `DrawCells` draws shells first and objects second, in reverse cell order;
views are ascending. A null `drawing_bsp` skips only that cell's shell.
- The object chain is
`DrawObjCellForDummies → insertion_sort → DrawObjCell → DrawPartCell →`
`CShadowPart::Draw → CPhysicsPart::Draw → DrawMesh`.
- Built EnvCell shells and built parts submit whole after Boolean admission;
portal polygons, not arbitrary built meshes, are polygon-clipped.
- Device, cell-shell, and part stamps persist. The first ordinary accepted
view stamps/draws and later views suppress; force/local-player paths bypass
the ordinary inner stamp behavior.
## 6. Automated state at handoff
All results below are from the frozen uncommitted tree.
| Gate | Result | Provenance |
|---|---|---|
| T3 focused cases | **54/54 passed** | Final third-round agent run |
| Core WorldEvidence aggregate | **153/153 passed** | Final third-round agent run |
| Core Release build | **PASS, 0 warnings / 0 errors** | Final third-round agent run |
| App legacy importer + recorder compatibility | **46/46 passed** | Handoff verification run after the Core freeze |
| Complete solution Release build | **PASS, 0 warnings / 0 errors** | Handoff verification run after the Core freeze |
| Trailing whitespace | **clean** | Final third-round agent run |
| Dead T3 vocabulary grep | **clean** | Only the intentional test asserting `PartAdmit` is absent remains |
The complete solution **test suite was not rerun** after the third T3 round.
No tests are known red. The older OH0 baseline (319 focused passes / 1 skip)
and the tooling note's pre-T2 counts are historical provenance, not current OH1
closure evidence.
Reproduction commands from the worktree root:
```powershell
dotnet test tests/AcDream.Core.Tests/AcDream.Core.Tests.csproj -c Release --no-restore --filter "FullyQualifiedName~Diagnostics.WorldEvidence.WorldEvidenceJsonlTests"
dotnet test tests/AcDream.App.Tests/AcDream.App.Tests.csproj -c Release --no-restore --filter "FullyQualifiedName~WorldFrameTranscriptRecorderTests|FullyQualifiedName~LegacyWalkOracleImporterTests"
dotnet build AcDream.slnx -c Release --no-restore --nologo
git diff --check
```
## 7. Known open T3 review surface
T3 is not review-closed until these are either implemented and tested or
explicitly disproved as required by the retail sources:
1. Add a dedicated same-typed-part-across-two-cells persistent-stamp fixture.
2. Add an outside-`DrawCells` `PortalListBind` positive/completeness fixture.
3. Add explicit `copy_view` adversarials for every numerical boundary:
- exactly one pixel and just over one pixel;
- every wrap-prune branch;
- the 32-plane cap;
- negative zero;
- second append/pool reset; and
- normalization epsilon.
4. Decide under retail and architecture review whether call boundaries require
a typed `PViewCallContext`. Exact identities currently come from owned
semantic rows. Do not add the type merely for aesthetics, and do not reject
it merely to avoid a schema edit.
5. Decide whether `NullTail`'s current
`TailPopAttempted = true` + `TailPointerPresent = false` is sufficiently
exact, or whether retail evidence requires a standalone nullable-pop event.
6. Run a fresh independent retail-faithfulness review and a separate
architecture/false-oracle review. The reviewer must try coordinated
omissions/relabels, not only single-field mutations.
No owner/client gate is needed for T3 unless static retail sources genuinely
lack one fact. If an owner capture becomes necessary, request one exact pose,
action, duration, and expected trace. Do not ask the owner to explore visually.
## 8. Dirty-tree map
At the freeze, `git status --short` reports no staged files. The principal
groups are:
### Preserved pre-overhaul behavior candidates — do not attribute to T3
- App composition/rendering changes in `FrameRootComposition`,
`ParticleRenderer`, `RetailAlphaQueue`, `RetailPViewPassExecutor*`,
`RetailPViewRenderer`, `OrderedDrawStream`, `WalkFrameDriver`,
`WalkStaticStreamPopulator`, `WbDrawDispatcher*`, and
`WorldSceneRenderer`;
- associated App walk/alpha/PView/runtime-option tests;
- `docs/launch-options.md`; and
- A8 audit project/lock-file changes.
Their detailed semantic classification and risk level are in
`oh0-baseline.md`. They include geometry recipe, lighting, depth-state,
exit-seal, membership, built-mesh, part-stamp, shell-stamp, and diagnostic
candidates. None is accepted simply because it remains in the tree.
### OH1 evidence work
- Core `Diagnostics/WorldEvidence` models, codec, grammar, and tests;
- App transcript recorder and narrow legacy oracle importer/tests;
- the synthetic A8 geometry-manifest command boundary;
- launch-option documentation for output-only evidence; and
- the active tooling note and corrected flood appendix.
### Known non-semantic noise to exclude from narrow commits
The following were classified as CRLF-only in OH0:
- `src/AcDream.App/Rendering/Scene/RenderProjectionRecordFactory.cs`
- `src/AcDream.App/Rendering/Scene/RenderSceneContracts.cs`
- `src/AcDream.Core/Physics/ShadowPartBox.cs`
- `src/AcDream.Core/World/MeshRef.cs`
- `src/AcDream.Core/World/WorldEntity.cs`
`src/AcDream.App/Streaming/LandblockBuildFactory.cs` was blank-line-only.
Recheck with `git diff --ignore-space-at-eol -- <path>` before assuming any of
these has gained semantic content.
## 9. Next safe execution sequence
1. Confirm `HEAD`, branch, and `git status --short`; do not clean the tree.
2. Read the documents in section 3, especially OH0 and the active tooling note.
3. Review the seven round-three T3 files as one closed grammar change.
4. Implement the bounded adversarial fixtures in section 7 without changing
production rendering or loosening the canonical schema.
5. Run the 153-test WorldEvidence aggregate, the 46-test App compatibility
gate, `git diff --check`, and the complete Release solution build.
6. Obtain independent retail-faithfulness and architecture/false-oracle
reviews. Fix findings and rerun the same gates.
7. Update `oh1-world-evidence-tooling.md` and the campaign execution ledger.
8. Stage only the reviewed T3/OH1 paths. Preserve the OH0-classified App
behavior candidates and line-ending noise. Commit T3 only after review
closure; record the commit in the checkpoint ledger.
9. Complete OH1 T4T8 from the plan: landscape/building interleave,
alpha/material evidence, depth lifecycle, recorder/fixture integration,
and final no-production-change gates/reviews.
10. Mark OH1 closed only when all planned evidence families are executable and
the narrow FW0 importer is still truthfully narrow.
11. Then begin OH2 implementation from the already committed CellStruct
contract. OH2 owns the production descriptor, package version/migration,
installed-DAT manifest generation, two-run determinism gate, review, and G1.
Do not jump directly to cathedral symptom fixes. The first production behavior
change belongs to OH2 after OH1 closes. Preserve the campaign's Plan →
Implement → Review rhythm and combine owner gates according to the stage table;
do not launch a client after every code edit.
## 10. Copy-paste prompt for the next model
```text
Take over Campaign OVERHAUL in the EXISTING worktree:
C:\Users\erikn\source\repos\acdream\.claude\worktrees\peaceful-blackburn-5333f0
Branch: claude/campaign-w-retail-frame-walk
Frozen HEAD: 5d907ae9ad9462347eb697c39ae3ffac136a40bc
Do not use the main checkout. Do not create or copy another worktree over this
one. The tree is intentionally dirty and has no staged files. Never run reset
--hard, checkout --, or clean. The recovery anchor is b3b7d922.
First read, in order:
1. AGENTS.md
2. docs/architecture/acdream-architecture.md
3. docs/architecture/worldbuilder-inventory.md
4. docs/research/2026-09-01-overhaul/2026-09-02-campaign-overhaul-handoff.md
5. docs/plans/2026-09-01-campaign-overhaul-world-solidity.md
6. docs/research/2026-09-01-overhaul/oh0-baseline.md
7. docs/research/2026-09-01-overhaul/oh1-retail-world-contract.md
8. all four supporting OH1 contract packets
9. docs/research/2026-09-01-overhaul/oh1-world-evidence-tooling.md
10. docs/research/2026-09-01-overhaul/oh2-cellstruct-surface-contract.md
11. docs/research/2026-08-30-fw-flood-pseudocode-appendix.md
Current truth: OH0 is closed. OH1 research and T0-T2 are closed. OH1/T3's third
implementation round is uncommitted and locally green (54/54 T3, 153/153 Core
WorldEvidence, 46/46 App importer/recorder, complete Release build 0 warnings/
errors), but T3 is NOT independently review-closed. OH1/T4-T8 and every
production slice OH2-OH11 remain pending. OH2 design exists at 5cd4fd2c, but
OH2 implementation must not start until OH1 closes.
Your first work is to inspect—not rewrite—the frozen T3 grammar and close the
explicit review gaps listed in handoff section 7: same-part-across-two-cells
stamps, outside-DrawCells PortalListBind, all copy_view numerical adversarials,
and evidence-based decisions on PViewCallContext and NullTail representation.
Then run independent retail-faithfulness and architecture/false-oracle reviews,
fix findings, rerun the recorded gates, update both ledgers, and commit only the
narrow reviewed T3 scope.
The named retail pseudo-C and retail headers are the behavior oracle. Grep by
class::method first. Use Ghidra to arbitrate ambiguous branch sense. Do not
invent an approximation and do not make production draw decisions in OH1.
Do not infer render content from aggregate owner IDs; trace identities to DAT.
No owner/client gate is currently needed. If a static fact genuinely cannot be
recovered, ask for one precise capture with an exact pose/action/duration and
expected trace. The user normally closes a running client; never kill it unless
the user explicitly authorizes control.
```
## 11. Handoff stop condition
At this freeze all previous subagents are complete and no agent should be
assumed to be editing the tree. The next model owns the next mutation. Before
changing anything, compare live `git status` and `git diff` with this document;
newer filesystem state always needs explicit classification rather than being
silently folded into T3.