acdream/docs/research/2026-06-11-t6-br7-shipped-t5-gate-post-t5-handoff.md
Erik acaaeae434 docs: session handoff - T6/BR-7 shipped + T5 verdict + post-T5 state, with the next-session prompt
docs/research/2026-06-11-t6-br7-shipped-t5-gate-post-t5-handoff.md:
the 9-commit ledger with decomp anchors, the per-cell shadow
architecture summary, the T5 gate verdict (collision half 100% passed;
#117-#120 filed), the #117 fix detail (depth-gated punch - re-gate
pending), the #118 narrowing + exit-walk harness design, the #119
up-null lead, the #120 armed tripwire, watchouts/DO-NOT-RETRY
additions, new apparatus inventory, the next-session work order, and
the paste-ready prompt.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-06-11 16:17:41 +02:00

17 KiB
Raw Blame History

T6 (BR-7) SHIPPED + T5 gate verdict + post-T5 fixes — session handoff (2026-06-11)

Branch: claude/thirsty-goldberg-51bb9b, HEAD 0e6e24f. Nothing on main. Suites (all green): Core 1416 / 0 / 2 skips (skip 1 = pre-existing PvsConformanceTests; skip 2 = BSPStepUpTests.D4 with the #116 reference), App 227, UI 420, Net 294.

This session: (1) shipped T6 / BR-7 — the A6.P4 per-cell shadow collision architecture, the last code phase of the holistic building-render port; (2) ran T5, the single comprehensive user visual gate (PARTIAL PASS — the entire collision half passed, four render artifacts filed); (3) fixed #117 (aperture punch-through), armed #120 (flood-growth tripwire), narrowed #118 (exit-vanish). The holistic port (BR-1…BR-7) is now code-complete and partially visually validated.

Read first, always: claude-memory/project_render_pipeline_digest.md + claude-memory/project_physics_collision_digest.md (both updated this session — current-truth banners on top).


1. The session's commit ledger (oldest first)

SHA What
6ec4cde T6 C1 — signed OtherPortalId + the >= 0 building-transit gate (check_building_transit 0x0052c5d0; BN renders the comparison unsigned — Ghidra-proven sign extension; wire 0xFFFF = 1 = no reciprocal portal). Multi-sphere CheckBuildingTransit overload + hitsInteriorCell out.
abf36e2 T6 C2 — CellTransit.BuildShadowCellSet: the registration-side sphere-overlap portal flood (verbatim find_cell_list 0x0052b4e0 via calc_cross_cells(_static)). Indoor seed → that cell + growing-array walk; outdoor seed → block-crossing AddAllOutsideCells; outdoor cells in the walk run the building bridge; statics get the do_not_load prune ({seed} stab list — also strips outdoor cells, retail-faithful). The spec's VisibleCellIds rule was REFUTED (WF1) — no visibility list anywhere in shadow placement. 11 unit tests.
dbfbf85 T6 C3 (FUSED — the BR-2 half-port lesson: registration+query co-dependent) — registry rewritten to flood-seeded per-cell lists (CylSphere flood rule: base pt + cyl radius, cap 10, 0x0052b9f0; keep-when-empty pc:283540; RefloodLandblock streaming hook = retail init_objects → recalc_cross_cells); building shells left the registry (per-LandCell channel: Transition.FindBuildingCollisions = CSortCell::find_collisions 0x005340a0 → find_building_collisions 0x006b5300; ONE building per ORIGIN landcell, init_buildings 0x0052fd80 verified verbatim + ACE cross-ref; only caller is 0x005340aa); query strictly per-cell (FindObjCollisionsInCell = find_obj_collisions 0x0052b750; insert order env→building→objects on the primary, then CheckOtherCells runs env+building+objects per OTHER cell with the carried-cell advance AFTER all object passes — transitional_insert 0x0050b6f0 OK_TS case); placement weakening center_solid=0 when BldgCheck && HitsInteriorCell (0x0053a82e / 0x005399d8; both fields added to SpherePath, rebuilt at every cell-array build). DELETED: the radial 9-LB sweep, the +5 m query pad, the b3ce505 indoor gate, the isViewer exemption. 3 of the 4 #99-era reds flipped green (door apparatus → …_Blocks, tick-13558 asserts the door BLOCKS, tick-22760 pins the blocking invariant).
ca4b482 T6 C4 — A6.P5 hasExitPortal topology widening DELETED (outside cells enter the collision array ONLY on the retail straddle — same flag as the membership pick; the WF1 correction "re-gate, don't delete" implemented); #90 stickiness REMOVED (dead code — ResolveCellId's only caller is the cache-null test fallback; the ordered-pick hysteresis owns doorway behavior). Two old A6.P5 pins inverted to retail truth.
60c1070 docs — T6 ship closeout: #99/#90 closed in ISSUES, #97 likely-close note, #116 filed (slide-response family), plan stamped.
af5d424 docs — T5 gate verdict (§3 below): #108/#109/#97 closed (user-confirmed), #117#120 filed.
2d15084 #120 armed — tripwire self-attribution (DumpPropagationChain: root, eye, per-cell frequency, 24-entry chain tail) + ConvergenceTripwireCount observable + 2 dat-backed convergence sweeps as regression pins (3024 builds, 0 firings — production-only ingredients suspected). Retail finding: retail RECURSES natively too (AddViewToPortals → FixCellList → AdjustCellView, 0x005a52d0/0x005a5250/0x005a5770, no depth guard) — depth-128 = slow-convergence laps, not necessarily a true loop.
478c549 #117 FIXED — depth-gated punch (§4 below).
0e6e24f docs — #118 narrowed (§5 below): two suspects exonerated by read; candidates + exit-walk harness design recorded in ISSUES.

2. T6 / BR-7 — what the architecture is now (one paragraph)

Objects register into the EXACT cells their collision footprint overlaps, computed once at registration by the retail sphere-overlap portal flood (BuildShadowCellSet); a door straddling a threshold lands in BOTH the outdoor landcell and the vestibule list. The collision query is strictly per-cell (GetObjectsInCell) at retail's two sites — the primary insert (env → building → objects) and check_other_cells (the same per OTHER overlapped cell), with the carried-cell advance after all object passes. Building shells are NOT shadow objects: an outdoor LandCell carries at most one building reference (its origin cell) and runs the shell part-0 BSP through FindBuildingCollisions with the bldg_check/hits_interior_cell placement weakening. There is no spatial radius anywhere in the query path — cell membership IS the broad phase. The b3ce505 stopgap, the A6.P5 widening, and the #90 stickiness are all gone.

#116 (filed): tick-22760's lateral-slide loss + BSPStepUp D4's first-frame slide are a PRE-EXISTING slide-response family (probes prove the cell-set layer innocent; BR-7 left both byte-identical). Fix shape: ONE oracle-driven pass over SlideSphere + the first-contact frame (get_object_info pc:279992 only seeds the NEXT frame). Do NOT patch the degenerate-offset guard ad hoc.


3. T5 verdict (the user's reports are AXIOMS)

PASSED: doors block both ways incl. off-center (#99 visual); cellar descent/ascent clean + #108 grass-sweep GONE; interiors stable through doorways incl. edge-on; inn 2nd floor clean (#97 CLOSED); #109 far-door oscillation GONE; formerly-popping stairs now STABLE at all ranges (the distance-pop class is dead). Rain-indoors not verifiable (clear).

Filed:

  • #117 — aperture-shaped see-through: doors/interiors visible through terrain hills + through nearer buildings. → FIXED this session (§4).
  • #118 — character clipped + vanishes for a moment when exiting houses (viewer-indoor/player-outdoor window). → narrowed (§5), fix queued.
  • #119 — old tower: stair parts invisible (pre-existing, "same issue as before"; the tower stairs ARE visible in retail — user axiom) + an extraneous water barrel. Lead from the T5 log: exactly two [up-null] upload returned null for 0x00010002B4 / 0x00010008A8 — caching EMPTY render data (permanently invisible) lines at startup (t5-gate-launch.log:33-34, untracked in the worktree root). Untouched.
  • #120[pv-ERROR] in-place propagation tripwire at depth 128 on cottage cells 0x…0175/0174/0162 during normal play (T2 invariant tripwire). → armed for self-attribution (§1, 2d15084); wait for the next natural firing (any launch's log will carry the chain dump).

4. #117 — the fix that needs the re-gate

Decomp-settled root cause: retail's DrawPortalPolyInternal (0x0059bc90) draws the punch with DEPTHTEST_ALWAYS + per-vertex far-Z (0.99999899, maxZ1 bit0) — it stomps ANY occluder depth unconditionally. Retail is safe only because its outdoor pass is painter's-ordered far→near: anything nearer redraws after the punch. Our z-buffered MDI frame has no such order → the far house's aperture punch erased the near house's wall / the hill's depth, and interiors + door entities (dynamics drawn last) painted through — both #117 shapes.

Fix (478c549, PortalDepthMaskRenderer): the punch is now two passes — A) stencil-mark where the aperture fan passes LEQUAL at its true depth biased 0.0005 NDC toward the viewer (≈6 cm at 5 m; keeps #108's terrain-hugging-the-door case punched), no depth write; B) far-Z write with depth ALWAYS, stencil-gated EQUAL 1, zeroing stencil as it goes (self-cleaning). The frame order guarantees correctness: terrain + ALL building shells draw in the landscape stage BEFORE DrawExitPortalMasks, so pass A tests against the real occluders. The SEAL (interior roots) stays retail-verbatim single-pass (it runs right after the gated full depth clear — nothing nearer to stomp). WindowOptions now requests 8 stencil bits explicitly. The stale "RESERVED — unwired" banner on the class was corrected (T1 wired it via DrawRetailPViewPortalDepthWrite).

Acceptance = the focused re-gate: downhill door check, behind-house openings, AND #108 cellar stays clean (the bias is the only regression surface).


5. #118 — narrowed; the exit-walk harness is the next step

Exonerated by read: the draw partition (the local player carries ServerGuid → Dynamics, never dropped) and entity-cell staleness (pe.ParentCellId = result.CellId syncs per tick, GameWindow ~6855).

Live candidates (the doorway-crossing decision stack), in order:

  1. Eye/cell incoherence under camera damping — the render root is the sweep's RetailChaseCamera.ViewerCellId while the projection eye (camPos) is the DAMPED position; during a crossing they can disagree by the damping lag. This is the already-VERIFIED #115/BR-8a divergence (retail damps FROM the published collided viewer; we damp from our own damped eye) — fixing BR-8a may fix #118 outright.
  2. Exit-portal side test at the threshold — eye ε-outside the door plane while the root is still the interior cell → CameraOnInteriorSide culls the exit portal → OutsideView EMPTY → SphereVisibleOutside culls ALL outdoor dynamics (the player) for those frames. Retail's AdjustPosition demotes the viewer cell to outdoor the same moment the point exits (seen_outside → adjust_to_outside), making the inconsistent state structurally brief.
  3. The doorway-aperture cone tightness for an outdoor player + indoor viewer.

Next step (apparatus, not guessing — 3 hypotheses = build the harness): a deterministic exit-walk harness over the corner-building cells (CornerFloodReplayTests infrastructure): per step of an eye+player path crossing the doorway, drive the production decision stack headlessly — viewer-cell resolution → PortalVisibilityBuilder.Build(root)ViewconeCuller.Build → the exact DrawDynamicsLast visibility predicate — and assert the player sphere stays visible on every step. All CPU; the failing step pins which candidate fires. Full design in the ISSUES #118 entry.


6. Watchouts / DO-NOT-RETRY for the next session

  • No radial/spatial sweeps back into ShadowObjectRegistry, no topology-based outside-add, no gates — cell membership IS the broad phase; the straddle flag is live-binary verified. (Physics digest rules.)
  • Do not patch the SlideSphere degenerate-offset guard ad hoc — #116 wants the oracle read first.
  • The punch must stay depth-gated. Reverting to bare ALWAYS without painter's ordering re-opens #117 by construction.
  • #120: don't tune the tripwire constant (128). The chain dump is the lead; retail's own recursion has no guard — the fix will be about WHY convergence is slow (dedup/merge admitting near-duplicates per lap), not about the limit.
  • The two convergence sweeps in CornerFloodReplayTests (PortalPlaneCrossings_… / InCellDirectionSweep_…) are regression pins — keep green.
  • Building channel is origin-cell-only (retail-verbatim, init_buildings + ACE cross-checked). If the re-gate shows soft wall collision on a LARGE building, first write the dat conformance fact (shell extent vs origin landcell for Holtburg models) before touching the dispatch.
  • The 4 GameWindow registration sites pass seedCellId:; live entities seed from the wire cell id; IsBuildingShell entities skip the registry entirely. Don't re-add them.
  • xunit swallows Console.WriteLine — use ITestOutputHelper or %TEMP% for harness diagnostics.

7. New apparatus (this session)

Tool Where Purpose
PortalVisibilityBuilder.ConvergenceTripwireCount static, test-visible #120 observable; both Build + look-in sites
DumpPropagationChain fires with the tripwire root + eye + per-cell frequency + 24-entry chain tail
PortalPlaneCrossings_InPlacePropagationConverges CornerFloodReplayTests ±6 cm sweep across every portal plane, both seed sides
InCellDirectionSweep_InPlacePropagationConverges CornerFloodReplayTests 3×3×2 in-cell eye grid × 8 yaw × 3 pitch (3024 builds)
Diagnostic_Tick22760_DumpEngineInternals DoorBugTrajectoryReplayTests #116 repro dump (door found + BSP-only dispatched correctly)
[bldg-channel] probe Transition.FindBuildingCollisions per-channel-hit line under ACDREAM_PROBE_BUILDING
t5-gate-launch.log worktree root (untracked) the T5 session log — [up-null] ×2 + [pv-ERROR] ×3 evidence

8. Next-session work order (work-order autonomy: drive, don't ask)

  1. #118 — build the exit-walk harness; fix what it pins (BR-8a is the likely fix if candidate 1 confirms — the retail damping shape is already verified in the plan).
  2. #119 — chase the [up-null] pair (identify the two models; why ObjectMeshManager's upload returned null; whether the permanently-invisible cache should retry); then the barrel (static-inclusion question).
  3. Focused re-gate with the user (one launch, short list): downhill door check + behind-house openings (#117), house-exit character (#118), tower stairs + barrel (#119), #108 cellar stays clean, and grep the log for [pv-ERROR] chain dumps (#120's self-attribution).
  4. Then per the plan: BR-8a camera (may already be consumed by #118), #116 oracle pass, roadmap/milestones closeout of the holistic port.

9. Paste-ready next-session prompt

Pick up acdream as a SENIOR 3D ENGINE DEVELOPER on the POST-T5 residual
fixes of the holistic building-render port. Worktree branch
claude/thirsty-goldberg-51bb9b, HEAD 0e6e24f. Nothing goes to main.

STATE: the holistic port is CODE-COMPLETE and T5-gated (partial pass).
T6/BR-7 (per-cell shadow collision) SHIPPED — #99/#90/#97/#108/#109 all
CLOSED (user-confirmed at T5). #117 (aperture punch-through occluders)
FIXED 478c549 — pending visual re-gate. Suites green: Core 1416/0/2skip,
App 227, UI 420, Net 294.

READ FIRST (in order):
1. Memory digests: project_render_pipeline_digest +
   project_physics_collision_digest (current-truth banners on top; the
   DO-NOT-RETRY tables APPLY — note the new no-radial-sweep /
   no-topology-add / punch-stays-depth-gated / #116-oracle-first rules).
2. docs/research/2026-06-11-t6-br7-shipped-t5-gate-post-t5-handoff.md
   (THE handoff: T6 architecture summary, T5 verdict, #117 fix detail,
   #118 narrowing + harness design, #119 up-null lead, #120 armed
   tripwire, watchouts, work order).

DO NEXT — #118 (character clipped+vanishes on house exit):
build the deterministic exit-walk harness designed in ISSUES #118 /
handoff §5 (CornerFloodReplayTests infrastructure; per step of an
eye+player doorway-crossing path, drive viewer-cell resolution →
PortalVisibilityBuilder.Build → ViewconeCuller → the DrawDynamicsLast
visibility predicate; assert the player sphere stays visible). The
failing step pins one of three candidates (handoff §5); candidate 1
(eye/cell incoherence under damping) is the verified #115/BR-8a
divergence — if it confirms, the fix is BR-8a's retail damping shape
(damp FROM the published collided viewer). 3 hypotheses already exist —
apparatus first, no speculative fixes.

THEN — #119 (tower stairs + barrel): chase the [up-null]
0x00010002B4/0x00010008A8 permanently-invisible upload failures
(t5-gate-launch.log:33-34) before any draw-path theorizing; the barrel
is a separate static-inclusion question.

THEN — the FOCUSED RE-GATE with the user (one launch, short checklist):
downhill door check + behind-house openings (#117), house-exit character
(#118), tower stairs + barrel (#119), #108 cellar stays clean; grep the
log for [pv-ERROR] chain dumps (#120 self-attributes on its next firing).
User retail reports are AXIOMS; no per-artifact live-probing.

Build + test green per commit. Baselines: App 227 / Core 1416 + 2 skips
/ UI 420 / Net 294.