P0 (verbatim-spatial-pipeline-port) Tasks 1+2. ConformanceDats loads the
cottage-doorway cells from the real dats with their real ContainmentBsp;
CottageDoorwayCharacterizationTests maps the Holtburg 0140..017F indoor
neighborhood and pins the master-plan threshold building (origin
161.93,7.50,94.00): 0xA9B40170 vestibule (exit portal 0xFFFF + portal to
0171), 0xA9B40171 room. Grid math confirms the outdoor side is landcell
0xA9B40031 -> the 0031<->0170<->0171 ping-pong is verified real. Verified
interior points recorded for the point_in_cell/find_cell_list goldens.
Plan: docs/superpowers/plans/2026-06-03-p0-conformance-apparatus.md
Notes: docs/research/2026-06-03-p0-conformance-apparatus-notes.md
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The doorway saga (void -> transparent walls -> flaps) proved patching the hybrid is hopeless:
retail does membership + collision + camera + render as ONE coupled pipeline; acdream
reimplemented pieces with mismatched criteria at the seams. Master plan to port ALL of it
verbatim: A membership (find_cell_list/find_transit_cells/find_building_transit_cells intrinsic,
no bridge), B uniform collision (no indoor/outdoor fork) + door collision, C camera
(update_viewer + find_visible_child_cell), D the full PView render (ConstructView/InitCell/
ClipPortals/GetClip/DrawCells/DrawPortal + the update_count watermark). KEEP/REPLACE/DELETE
lists, decomp anchors per function, P0-P6 sequence (apparatus-first, foundation-up, visual gate
each), and the kickoff prompt. Supersedes the render-only redesign's scope.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The inside/outside render currently splits viewpoints: the player cell roots
visibility + the portal side-test, the eye only projects. Retail uses ONE
viewpoint — the collided camera (viewer) — for the mode decision, indoor root,
side-test, AND projection (RenderNormalMode -> DrawInside(viewer_cell) @92675;
InitCell side-test vs viewer.viewpoint @432991; viewer_cell = sphere_path.curr_cell
@92871). The split makes the render mode follow the player while the screen comes
from the camera -> doorway-straddle void + see-through transition (user evidence
2026-06-03). Spec unifies on the viewer: V1 un-split (robust viewer cell from the
camera sweep, no AABB/grace -> no U.4c flap; lighting stays on the player cell),
V2 DrawPortal (outside-looking-in), V3 floor seal. Supersedes residual-A; merges
A+C. Keeps the blue-hole fix (CurrCell player-only).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Canonical handoff: docs/research/2026-06-03-membership-and-bluehole-shipped-handoff.md
(what shipped: membership Stage 1 ordered-CELLARRAY port + the blue-hole render-root
clobbering fix; the full remaining-issues list — A camera-collision, B R1b particles,
C R2 outside-looking-in, Stage 2 membership, #7 stairs, the 5-test baseline; KEEP/
DON'T-REDO; key files + decomp anchors; copy-paste pickup prompt for next session).
- ISSUES.md: recorded the cottage doorway flap DONE (both causes) in Recently closed.
- render design spec §7: R1 + flap marked DONE; A/B/C mapped to the next render phases.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Ports retail CELLARRAY::add_cell (acclient_2013_pseudo_c.txt:701036): ordered list,
dedup by cell_id, append at end. The order is load-bearing for the verbatim
find_cell_list current-cell-first interior-wins pick (next commits) that fixes the
R1 cottage membership flap. Implements ICollection<uint> (helper-facing) +
IReadOnlyCollection<uint> (consumer-facing). 5 unit tests.
Also lands the membership-port pseudocode (workflow step 3) + the Stage-1 plan.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
User's own decomp dig (verified): the flap's deepest root is architectural, not the
find_cell_list pick ordering. Retail membership is persistent object STATE (curr_cell
mutated ONLY by change_cell at a portal crossing); acdream RE-DERIVES CellId from
FindCellSet geometry every tick → ping-pong. Plus multi-valued CELLARRAY (retail) vs
single CellId (acdream), uniform vs forked collision (0x0100), intrinsic vs bridge
building entry. Reframed the handoff + prompt: the pick-ordering port (§4.3) is
SUPERSEDED/symptomatic; the job is STAGE 1 = persistent + multi-valued + portal-
crossing membership (change_cell 281192, find_transit_cells, SetPositionInternal),
drop the 5ca2f44 pre-check; STAGE 2 = uniform collision + intrinsic entry. New §4.4
(the 4-point analysis) + §4.5 (staged fix).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Canonical pickup for a fresh session. R1 (per-cell DrawInside render) shipped + is
correct (cellar seals); it exposed a pre-existing cell-membership ping-pong (the
flap). Root cause: CellTransit.BuildCellSetAndPickContaining picks from an UNORDERED
HashSet, dropping retail find_cell_list's current-cell-first ordering (CELLARRAY
index-0 + interior-wins-break, pc:308742-308825). Next job: verbatim port of that
ordered pick, replacing the HashSet + the 5ca2f44 pre-check approximation. User
authorized breaking any physics to get membership faithful. Full diagnosis, verbatim
retail source, fix plan, KEEP/don't-redo, test baseline, and a copy-paste pickup
prompt in the doc.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Bite-sized plan for R1 (the per-cell DrawInside core): InteriorEntityPartition
(3-bucket, TDD), InteriorRenderer per-cell loop, the binary render decision in
OnRender (indoor = DrawInside only), and the :1756 bypass repurpose. Particles
deferred to R1b. Grounded in the live code surface (exact file:line + signatures).
Ends at the R1 user visual gate (sealed Holtburg cottage, no bleed).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Resolves the plan §3 open questions with the user this session:
- object/entity/particle draw = LITERAL PER-CELL LOOP (retail DrawCells),
not a global MDI batch with per-instance clip. Fidelity > perf > blast-radius.
- sequencing = HOLISTIC: build the per-cell DrawInside directly; no intermediate
global-pass gate-fix. First visual gate = sealed cottage interior, no bleed.
- terrain in the seal = FAITHFUL: drawn only through the exit-portal clip, never
as a floor under the interior. Inventory's 'relax Skip' suggestion REJECTED as a
non-retail workaround; grey-floor = a sealing bug (verify cell mesh in R1).
- WB mesh pipeline KEPT (per-cell draws from the global buffers, batched within a
cell); two-camera invariant preserved (eye projects, player cell roots visibility).
Phases (holistic): R1 unified per-cell DrawInside (the core) -> R2 outside-looking-in
(DrawPortal) -> R3 dungeons -> R4 polish+cleanup. Each ends GREEN + a user visual gate.
Retail anchors cited throughout (RenderNormalMode 0x453aa0, DrawCells 0x5a4840, etc).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The Phase W indoor seal did NOT land. The 2026-06-02 visual gate proved the interior render is fundamentally broken (#78: transparent walls, outdoor terrain + scenery entities bleeding in, grey floors, no outside-looking-in). Stage 4 (sky-through-door clip) was real but a top layer on a base that never sealed.
DECISIVE EVIDENCE (committed in the handoff): the PVS computes correctly AND the cell shells render correctly (opaque, textured, complete — the [shell] probe shows zero NOSNAP / zero missing-texture). The failure is the SEAL + three inconsistent gates — concretely the WbDrawDispatcher.cs:1756 ParentCellId==null -> return true bypass draws outdoor scenery indoors, and the indoor path draws the outdoor world then gates it instead of running ONLY DrawInside. Retail, when inside, runs ONE PView flood: visibility IS the cull; the landscape enters only through clipped exit portals + a conditional depth-only clear.
Dossier (per the user's mandate: NO shortcuts/bandaids, port from retail, redesign the whole pipeline if needed, brainstorm first):
- Master handoff (root cause + retail target + reusable-vs-redesign + apparatus + do-not-repeat + copy-paste pickup prompt).
- Huge staged redesign plan R0(brainstorm)->R1(one visibility authority, kill the bleed)->R2(indoor=DrawInside-only)->R3(the seal, DrawCells port)->R4(per-cell object/particle clip)->R5(outside-looking-in)->R6(dungeons)->R7(polish/conformance). Each ends at a user visual gate.
- 3 research docs: full retail render pipeline reference (705 lines, decomp-verified), acdream pipeline inventory + failure map, reference cross-check (WB two-pipe is the wrong model).
#78 promoted to the redesign. The 5 remaining Core test failures are pre-existing physics/collision bugs, none render-related.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
GetMaxSpeed deliberately does NOT branch on ForwardCommand — it returns RunAnimSpeed x run-rate as the InterpolationManager.AdjustOffset catch-up speed (doc comment + ACE MotionInterp.cs:670-678, retail-verified; the slow catch-up fixed the 1-Hz remote-blip). The 3 failing tests (WalkForward/WalkBackward/Idle) asserted a REMOVED command-branching design. Consolidated into one [Theory] pinning the no-branch contract across commands.
Also files #104 (LOW): scene VFX particles not clipped to the PView visible cell set — deferred out of the Phase W seal (entity bleed already gated by Stage 5; scene particles depth-tested; sky particles scissored). Needs OwnerCellId plumbing (~6-8 files).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Canonical pickup for the next session. Membership root cause (static :1947 re-derive)
FIXED the retail way (find_cell_list interior-wins pick + swept determination, 59f3a13)
and offline-verified (doorway strobe -> one clean transition). T0 made the suite
deterministic (12 known failures, none Phase-W regressions). Stage 3 (render-root
unification) DONE (6a1fbbd->573c555). Remaining: Stage 4 (the seal: sky/landscape inside
the portal-clip bracket + conditional doorway Z-clear = no blue-hole), Stage 5 (entity/
particle clip), green-tests triage, then the single final visual verification. Render is
wire-and-fill-gaps (PView infra exists). Flags a stash discrepancy (1 of 2 stashes missing
from the shared refs/stash) for the user to check against other worktrees.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Per-step subagent-driven plan for the render half: T0 test-hygiene baseline,
Stage 3 render-root unification (root at CellGraph.CurrCell + seen_outside, drop
the FindCameraCell grace-frame fallback), Stage 4 PView seal (sky/landscape inside
the portal-clip bracket + conditional doorway Z-clear = no blue-hole; EnvCellRenderer
GL_BLEND verify), Stage 5 entity/particle cell-clip. Key reframe from grounding the
plan in the actual code: the PView infra (PortalVisibilityBuilder BFS + OutsideView,
ClipFrame, EnvCellRenderer GL_BLEND fix, WbDrawDispatcher cell gate) ALREADY EXISTS and
the A8 stencil split is already gone — so the render half is wire-and-fill-gaps, not a
from-scratch port. Execution policy: no intermediate user gates, single final visual
verification, full suite green at verification.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Stage 1 (return swept sp.CurCellId, 3e1d502) was gated and the doorway strobe
PERSISTS: [cell-transit] still flips 0170<->0031. Airtight root from code analysis:
Transition.FindEnvCollisions re-derives the cell from the STATIC origin via
engine.ResolveCellId at TransitionTypes.cs:1947 and clobbers sp.CheckCellId (:1949)
at the start of every sweep pass — a second, earlier static re-derive the four
studies missed (they targeted the late return-site). It is the sole path that can
set an indoor swept cell outdoor (the containment pick at :2075 skips outdoor cells).
:1947 is dual-purpose (jitter source AND the only indoor->outdoor exit), so Stage 2
must replace it with a directed exit-portal crossing + do_not_load prune + exitOutside
re-gate — a careful #98-area rework, not a one-line delete. Render residuals at the
gate (no interior outside-looking-in, blue-through-door, particle/NPC bleed) are all
expected Stages 3-5, not Stage-1 regressions. Stage 1 is kept (correct + necessary).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Bite-sized TDD plan for design Stages 0-1 + W2b revert + visual gate: add the
[cell-swept] diagnostic, return the swept sp.CurCellId from ResolveWithTransition
(retail SetPositionInternal), revert the superseded W2b hysteresis, visual-gate the
doorway/cellar strobe, then lock it with a doorway replay regression. Render chunk
(Stages 3-5) gets its own spec+plan after this gate.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Four independent decomp studies (Opus 4.8 x2, Sonnet 4.6, external Codex)
converge: retail carries the cell through the collision sweep (validate_transition
advances curr_cell only on an accepted move, reverts on a block) and commits it in
SetPositionInternal — it never re-derives membership from a static resting position.
acdream already ports the sweep machinery (sp.CurCellId/CheckCellId, ValidateTransition,
CheckOtherCells) but ResolveWithTransition discards the swept cell and re-derives
statically via ResolveCellId (PhysicsEngine.cs:909/928) — the root of the
0170<->0031 doorway/cellar ping-pong. The do_not_load_cells prune is secondary
(static/cross-cell lists), not the anti-flicker; W2b was doubly misplaced and is reverted.
Render: one PView::ConstructView portal traversal over the same cell graph, rooted at
the physics current cell; seen_outside (not a dungeon flag) gates landscape; the outside
draws through exit portals clipped to the doorway (no blue-hole, no stencil split).
Dungeons/interiors share the machinery; "underground" is emergent.
Design doc lays out the staged, evidence-first rewrite (Stage 0 diagnostic ->
Stage 1 transition-owned membership [visual gate] -> Stage 2 CELLARRAY/prune parity ->
Stages 3-5 render root + PView seal + entity clip). Adds the shared research prompt and
all four study reports as the grounding record.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
8 TDD tasks (RED->GREEN), Core-only, zero behavior change, built alongside the legacy cell systems. Grounded in the retail CObjCell survey + acdream inventory + #98 fixtures.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Pixel-grounded investigation concluded the indoor 'world from below' is a cell-MEMBERSHIP disagreement between render-side CellVisibility and physics-side ResolveCellId, not any single draw gate (terrain has one gated draw path; it leaks only on render null-root frames). Decision with user: full migration onto one retail CObjCell graph across physics+collision+render+streaming, staged in 5 verify-each cycles. This lands the evidence model + the Stage 1 (ObjCell scaffold) design. No code yet.
- docs/research/2026-06-02-render-cell-membership-evidence.md (the why, from pixels)
- docs/superpowers/specs/2026-06-02-unified-cell-graph-stage1-design.md (Stage 1)
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Net code change this session = 0 (stencil-occlusion T1-T4 implemented, regressed,
reverted to baseline 9bff2b0). Documents the honest failure + lessons (patchwork via
flag-based gate routing; the interior-writes-mask rule breaks outdoors; coded before
screenshotting), the still-useful evidence (cottage = IsBuildingShell GfxObjs not cell
shells; two redundant traversals; retail DrawCells outside_view gate; working window
screenshot tooling), the open questions to answer with pixels first, and a refined
evidence-first pickup prompt.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The architecture and ISSUES edits in the prior commit (0013819) failed silently because
they were anchored on the session-reminder's rendering of the files, not the real text.
Redone against actual content:
- architecture doc: new 'Render Pipeline (SSOT)' section — the 3-gate patchwork vs the
unified-PView target + the one rule (compute visibility once, enforce it once).
- ISSUES #78: promoted to the render-architecture-reset target; points to the canonical
handoff + the architecture section.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
A week on the indoor render (Phase U.4 → U.4c → 2026-05-31) fixed the flap but
produced NO shippable progress: walls/ceiling don't seal, outdoor terrain is
visible from inside (#78), the enclosure reads grey/transparent. Root cause is
ARCHITECTURAL, not a bug.
Evidence this session (direct, via the new [shell] probe + screenshots) RULED OUT
every subsystem except the gating architecture: the interior cell shells render
fine (geometry/texture/opaque/depth all correct, zh=0 tr=0); the visibility
traversal computes correct sets + non-empty portal clips; cull mode is fine; the
camera/eye thread was a detour. The residual is that OUTDOOR geometry is not gated
to portal openings when indoors, and acdream enforces visibility THREE inconsistent
ways (TerrainClipMode / per-cell shell clip / entity ParentCellId filter with an
outdoor-stab bypass) instead of retail's ONE PView gate.
This commit is the reset handoff + documentation, not a code fix:
- docs/research/2026-05-31-render-architecture-reset-handoff.md — canonical: honest
state, evidence ledger (ruled-out / do-not-repeat), the mapped 3-gate patchwork,
the retail PView target (one traversal → one gate for ALL geometry), the reset
mission, and a copy-paste pickup prompt.
- docs/architecture/acdream-architecture.md — new "Render Pipeline" SSOT section
(current divergence + unified-PView target + the one rule: compute visibility
once, enforce it once). (Doc has pre-existing corruption below this section —
flagged for separate cleanup.)
- Apparatus: ACDREAM_PROBE_SHELL → [shell] (EnvCellRenderer per-cell prepared/drawn
geometry + flags) added to RenderingDiagnostics + EnvCellRenderer. Throwaway.
- docs/superpowers/specs/2026-05-31-camera-collision-indoor-engagement-design.md —
spec for e099b4c (camera collision; now parked as orthogonal to the seam).
Next session: STOP point-fixing; do the architecture reset to a single PView gate.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Root cause (b): ShadowObjectRegistry.GetNearbyObjects (line 480) returns early
when primaryCellId is an indoor cell, skipping the outdoor radial sweep that
contains the landblock-baked cottage exterior-shell GfxObj. The issue-#98 fix
that prevents the player's head sphere from being capped by the cottage floor
also prevents the IsViewer camera sweep from finding the exterior building shell.
Result: camera passes through exterior walls unimpeded, driving the residual
transparent-walls symptom after the U.4c flap fix.
Evidence: live capture shows eyeInRoot=n ~90% of frames, eye-player distance
3.43m (full chase, no pull-in). RED test deterministically reproduces: synthetic
indoor cell (0xA9B40175) + exterior GfxObj registered at cellScope=0; probe
SweepEye returns pulledIn=0.0000m (full eye distance Y=5.0, wall at Y=4.0).
Fix design: exempt IsViewer from the indoor-primary early-return gate in
GetNearbyObjects — retail's find_obj_collisions (named-retail :308918) has no
indoor/outdoor cell gate; the acdream fix is correct only for IsPlayer.
Apparatus committed:
- tests/AcDream.App.Tests/Rendering/CameraCollisionIndoorTests.cs (RED test)
- docs/research/2026-05-31-camera-collision-indoor-diagnosis.md (findings + design)
- PhysicsCameraCollisionProbe.cs [flap-sweep] diagnostic retained (U.4c spike)
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Canonical handoff (research note) for the U.4c flap fix + the three residuals the
visual gate revealed (#78 terrain-not-gated-inside, camera-collision need, U.5).
Records the full hypothesis journey (H1/H2 both evidence-disproven) so the next
session doesn't re-walk them. ISSUES.md: flap recorded in Recently-closed; #78
annotated (more visible post-fix). CLAUDE.md: U-phase orientation updated with the
flap-fixed status + the canonical handoff pointer + camera-collision-next.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Live ACDREAM_PROBE_FLAP moving capture: flap frames are uniformly res=Grace
eyeInRoot=n terrain=Skip; good frames eyeInRoot=Y terrain=Planes. The 3rd-person
camera EYE drifts out of the player's cell -> FindCameraCell returns the stale cell
for 3 grace frames -> from that stale root the doorway portal is behind the eye
(D=+1.26 CULL) -> exit cell drops -> terrain+shells Skip. Clip math is fine
(clip=5 when eye inside). Fix: (1) root visibility at the PLAYER's cell (retail
CellManager::ChangePosition tracks curr_cell by player; acdream already does this
for lighting at GameWindow:7152); (2) keep a player-reachable cell + exit when the
threshold eye-projection degenerates. Supersedes H2 and the earlier idle-frame
'stale root refuted' note.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
A8CellAudit portals now dumps each cell's local AABB. Real flap cells: 0171 local
y in [-7.65, 1.15], 0170 in [-8.61, -7.65]; the 0171->0170 portal plane is at
y=-7.65 (0171's MIN boundary), no overlap. So an eye genuinely inside 0171 always
has side-test D<=0 -> always traverses 0171->0170; the side test cannot cull 0170
while the eye is in 0171. The flap therefore requires the eye OUTSIDE 0171 while
root is still 0171 (cache/grace/3rd-person camera) -> a camera-cell-resolution
issue, not the side test (H2, disproven) and not the per-frame PVS set (H1, in
doubt). Mechanism still unconfirmed -> needs a live eye-pos capture. Stale H2
conclusion in the characterization note corrected with a banner.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
InitCell decode (PortalFlags.PortalSide=0x2) + a swept-pose A8CellAudit comparison
(O=centroid, A=winding-corrected PortalSide, B=opposite) over the real flap cells.
A is IDENTICAL to O at every pose/every portal — the (Flags&2)==0 boolean convention
makes the dat PortalSide sense equal to our centroid sense, so swapping is a no-op
and cannot fix the flap. B culls true-interior poses (wrong polarity). Conclusion:
the flap is NOT the side-test sense — it's the 3rd-person camera eye crossing an
interior portal plane while FindCameraCell still roots in the cell; ANY plane-side
test culls there. No production code changed (no no-op shipped).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
A8CellAudit portals dump extended to print per-portal plane + centroid-derived
InsideSide vs the dat's authored PortalSide. Real Holtburg cottage cells show:
the flap is a DIRECT 0xA9B40171->0xA9B40170 portal side-test flip (0170 is a
direct neighbour, not multi-hop), and our centroid-derived InsideSide is
anti-correlated with the dat PortalSide that retail InitCell (432896) uses.
Evidence selects H2 (port the side test) over H1 (PVS set-grounding). Camera
cell 0171 seenOutside=Y. Full reading + fix direction + open sign question in
the note.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Five tasks: (1) RED apparatus reproducing the doorway flap on a synthetic
C0->C1->C2(exit) chain; (2) Layer 1 LoadedCell.VisibleCells + SeenOutside
plumbing; (3) oracle-ported PVS grounding of set membership (the fix, gated by
task 1); (4) seen_outside invariants (sealed=empty, threshold=stable); (5)
live [vis] + visual gate. Task 3 is a faithful port (add_views 433382 /
InitCell 432896 / ClipPortals 433572), pseudocode-first, not fabricated.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Grounds the visible-cell SET in the stable per-cell PVS (stab_list) + seen_outside,
refreshed on cell entry, the way retail does (grab_visible_cells 311878, add_views
433382, DrawInside 433793). Our PortalVisibilityBuilder rebuilds the set per-frame
from a pose-brittle CameraOnInteriorSide walk, so a flipped side-test drops the exit
cell, empties OutsideView, and TerrainMode.Skip flaps terrain/shells off at the
doorway. Both stable inputs already live in-process (envCell.VisibleCells,
envCell.Flags & SeenOutside); U.4c is plumbing + grounding, not new dat parsing.
Apparatus-first: characterize the flap on a live ACDREAM_PROBE_VIS capture + port the
add_views/ClipPortals/AddToCell semantics to pseudocode before implementing; the
builder is not declared correct until a live [vis] shows non-empty + narrowing
OutsideView. No hysteresis band-aid (forbidden). Indoor rendering untouched.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Code review caught a CRITICAL under-inclusion: ApplyReciprocalClip scanned for the
first OtherCellId match, so a cell with two portals to the same neighbour clipped both
near-side openings against the FIRST reciprocal polygon — hiding geometry through the
second opening (real on Holtburg cellar cells 0x148<->0x149). Plumb the dat's
OtherPortalId back-link through CellPortalInfo + BuildLoadedCell and index the reciprocal
directly (retail arg2->other_portal_id, 433557). Skip (degrade to over-include) when the
index is unresolvable — never clip against a guessed polygon. Adds a disjoint two-back-
portal regression test.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Clip the portal opening against the neighbour's matching back-portal polygon
before propagating, so a cell's clip region is the intersection of the opening
seen from both sides. Closes the M-4 stub in ISSUES #102. Can only tighten,
never under-include; degrades to prior behavior when no back-portal is found.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Code-review minor follow-ups: correct the CellTodoList comments (ties are LIFO,
not FIFO — an equal-distance newcomer lands at the tail and pops first, matching
retail's break-on-first-not-greater + pop-from-tail). Update ISSUES #102 to record
that U.2a closes I-1/I-2 (under-count + duplicate accumulation) via the enqueue-once
gate, narrowing the residual to diamond-topology clip-completeness (AddToCell onward
re-propagation, tracked under U.6).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
One PView-faithful portal-visibility pass replacing the abandoned two-pipe
(inside/outside) split (#103). Settled in brainstorm 2026-05-30:
- Full Phase U in one spec (indoor BFS + outdoor building-peering + dungeon
fixpoint + distance-priority ordering + reciprocal OtherPortalClip).
- Per-cell gate = hardware clip planes (gl_ClipDistance) + scissor pre-check
(retail's two-level model); structurally immune to the #103 global-mask flood.
- Terrain stays its own path, gated to OutsideView (retail-faithful; NOT the
handoff's "terrain as cells" sketch).
- Salvage = reuse the clip math (PortalView/ScreenPolygonClip/PortalProjection,
~36 tests), rework the builder (PortalViewBuilder), delete the stencil pipeline
+ GameWindow two-pipe orchestration. Audited keep-list preserves the real
EnvCellRenderer / BuildingId / camera-collision fixes.
Staged U.1-U.6 with three visual gates. Retail anchors + acdream file:line
injection points catalogued in the spec.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Decision (2026-05-30, with user): the WB-inherited two-pipe (inside/outside) render
split is the root cause of the indoor seam bugs (flap, missing/transparent walls,
terrain bleed) and cannot be seamless. Abandon A8/A8.F (#103); build ONE unified
pipeline driven by retail's PView portal visibility — seamless by construction. The
2026-05-30 camera-collision + physics viewer-cap work is kept (retail-faithful, but a
detour from the seam fix). New Phase U scoped; #103 superseded; CLAUDE.md / roadmap /
milestones updated; full decision + scope + next-session pickup prompt in
docs/research/2026-05-30-unified-render-pipeline-decision-and-handoff.md.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
The plan's Task 2 code block still showed moverFlags: ObjectInfoState.None; the
shipped code (fcea05f) and spec §5.1 use IsViewer|PathClipped|FreeRotate|
PerfectClip (retail init_object(player, 0x5c)). Update the stale snippet so the
plan matches reality (this stale block was the likely source of a re-report).
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
The 2026-05-18 retail-chase-camera spec scoped collision out citing "retail
doesn't raycast." Phase A8.F falsified that (SmartBox::update_viewer DOES sweep
viewer_sphere); mark the note superseded and point to the A8.F spec.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Code review found the probe passed ObjectInfoState.None; retail's
SmartBox::update_viewer calls init_object(player, 0x5c) =
IsViewer|PathClipped|FreeRotate|PerfectClip (pseudo-C :92864). PathClipped makes
the sweep hard-stop at first contact (TransitionTypes.cs:811) instead of
edge-sliding around corners (which would re-trigger the A8.F camera-cell
instability); IsViewer lets the eye pass through creatures, colliding only with
world geometry. Resolves the spec's slide-vs-stop open question. Also reset
CollideCamera in the Defaults_AreRetailValues baseline test (review: maintenance
trap). Spec §5.1/§11.1 synced.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Bite-sized TDD plan for the swept-sphere camera collision: CollideCamera flag,
ICameraCollisionProbe + PhysicsCameraCollisionProbe (reuses ResolveWithTransition),
RetailChaseCamera slot-in, GameWindow wiring, Camera-menu toggle, visual
acceptance. Also refines the spec from planning findings: the InitPath +radius
sphere-center offset (ToSpherePath/FromSpherePath z-shift) and the deterministic
probe test scope (z-offset round-trip + cellId==0 guard; collision correctness
rides the existing sweep suite + visual).
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Design for porting retail's stage-2 camera collision (SmartBox::update_viewer):
sweep a 0.3 m sphere from the head-pivot to the damped eye via the existing
ResolveWithTransition engine (collides both indoor cell walls and GfxObj
building shells, e.g. the cottage cellar per #98/#101), publish the stopped
position as the eye. Fixes the A8.F flap by keeping the eye out of walls so the
camera-cell + portal side-tests stay stable. Self-skip via LocalEntityId; gated
by CameraDiagnostics.CollideCamera (default ON). Corrects the prior
retail-chase-camera spec's "no camera collision" note.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Correction after the user (who has played retail and observed the camera pull in
at walls) flagged the prior "no camera collision" conclusion. Verified against the
decomp: retail's camera collision lives in SmartBox::update_viewer (0x00453ce0),
NOT CameraManager::UpdateCamera. The earlier research traced only the producer
(UpdateCamera computes the desired/damped eye -> viewer_sought_position) and missed
the consumer (update_viewer), which sweeps a 0.3 m viewer_sphere via
CTransition::find_valid_position from the head-pivot to that eye and uses the
stopped position (fallbacks: AdjustPosition, then snap to player). The player-fade
when super close (CameraSet::UpdateCamera -> SetTranslucencyHierarchical) is a
SEPARATE stage, already ported as RetailChaseCamera.ComputeTranslucency.
Implication: a swept-sphere camera collision is RETAIL-FAITHFUL, not a divergence —
no special sign-off needed, and acdream already owns the Transition swept-sphere
engine. Updated TL;DR, KEY FINDING, the fix section (was "design decision"),
slot-in (collide the damped eye, after RetailChaseCamera.cs:131), open questions,
pickup prompt, and reference index. Memory updated likewise.
Lesson recorded: when the decomp says "no X" but a domain expert says X exists,
trace the CONSUMER of the computed value, not just the producer.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Root cause of the A8.F flap / missing-walls reframed (with the user's help):
the 3rd-person camera EYE passes through walls, and the A8.F renderer keys its
"am I inside?" (PointInCell) and portal side-tests (CameraOnInteriorSide) off
that eye position (camPos = invView translation, GameWindow.cs:7271). Eye clips
a wall -> those decisions flip frame-to-frame -> the flap.
Key finding from camera research (Opus agent + verified against the decomp):
retail's camera does NOT collide with walls either — it fades the player to
translucent (CameraSet::UpdateCamera @ 0x00458ae0 -> SetTranslucencyHierarchical),
which acdream already ports as RetailChaseCamera.ComputeTranslucency. So a
"spring arm that pulls the eye in on a wall hit" is a deliberate divergence from
retail, not a faithful port — needs user sign-off before coding.
Handoff documents: the eye->visibility coupling + flap mechanism, acdream's
current camera (the ported turn/jump input-lag = damping + velocity ring +
mouse filter; no collision), retail's camera (symbols+addresses), the reusable
swept-sphere collision machinery (BSPQuery.FindCollisions vs CellPhysics.BSP),
3 fix options (lead: modern spring arm), open design questions, apparatus, and a
pickup prompt.
Bug A (cellar terrain flood) already fixed + committed in 9417d3c; the
recursive-clip builder works (the prior "Bug B" framing was wrong).
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>