Commit graph

564 commits

Author SHA1 Message Date
Erik
8d93665053 #119: the [up-null] lead is EXONERATED (dat-proven) - both GfxObjs are legitimately no-draw models
Issue119UpNullGfxObjDumpTests pins the dat truth: 0x010002B4 = 9 polys,
ALL NoPos, all surfaces Base1Solid; 0x010008A8 = 1 poly, NoPos,
Base1Solid|Translucent. Retail's skipNoTexture never draws either model
(the BR-1 build-time-skip <=> draw-time-skip equivalence), so
ObjectMeshManager's empty render-data cache is the CORRECT terminal state
- the only defect was the alarming "permanently invisible" log line,
reworded into an honest tripwire pointing at the dump test.

Second fact, same test (ShellModel_NoTexturedPolyIsDropped): on the
hall/tower shell 0x010014C3, ZERO textured polys are dropped by the
extraction gates (137/149 draw; the 12 dropped are the known #113
no-draw orphans) - the per-poly GfxObj extraction is exonerated for
building shells, kept green as a regression pin.

Net for #119: the missing tower-stair parts are NOT the up-null pair and
NOT a per-poly extraction drop. Remaining hypothesis space (interior
stair-cell flood admission, or a different model than assumed) needs the
re-gate to identify the exact tower; then the cell set + flood replay
headlessly like #118. ISSUES.md updated.

Suites: App 232, Core 1419+2skip (1416+3 new), UI 420, Net 294.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-06-11 16:55:45 +02:00
Erik
5a80a2ee24 #118: outdoor dynamics draw in the outside stage under interior roots - the house-exit clip+vanish was the SEAL z-killing the player
Root cause (pinned by the new deterministic exit-walk harness, NOT guessed):
under an interior render root, the exit-portal SEAL stamps the door fan at
TRUE depth after the gated full depth clear, and T1's "ALL dynamics last"
pass then drew the outdoor-classified player depth-tested - every fragment
beyond the door plane z-failed against the seal across the whole aperture.
Harness measured the full window: from the moment the sphere center crosses
the plane until the eye follows (~2.6 m of camera lag, ~2.2 s at walk speed)
the player is invisible; while straddling, the beyond-plane body half clips
at the plane. The handoff's three cone-level candidates are all EXONERATED:
the cone walk passes every step; (eye, ViewerCellId) come from the same
SweepEye call with camera-update-before-visibility-read in the same frame;
the side-test window is sub-epsilon under healthy resolution.

Retail oracle (grep-named-first): PView::DrawCells 0x005a4840 runs
LScape::draw FIRST (pc:432719), then the gated depth clear (pc:432731-32)
and the exit-portal seals (pc:432785-86); outdoor cell objects draw inside
the landscape stage (DrawBlock 0x005a17c0 -> DrawSortCell pc:430124), and
an object draws once per overlapped shadow cell (pc:430056-64) - the
straddling body composes from both stages, neither half clips.

Fix: RetailPViewRenderer assigns dynamics to the OUTSIDE stage under an
interior root when outdoor-classified OR sphere-straddling an exit-portal
plane of their flood-visible cell (DynamicDrawsInOutsideStage - pure, the
harness drives it as the ordering contract); they ride the landscape slice
draw (pre-clear, seal-protected) with the same per-slice cone test as
outdoor statics. Indoor dynamics keep the last pass (retail loop C);
straddlers draw in both (retail shadow dual-draw). Outdoor roots keep
all-dynamics-last - the BR-2 punch-after-dynamics lesson (88be519) stands.

Apparatus: HouseExitWalkReplayTests - dat-backed corner-building exit walk
driving the production stack headlessly (RetailChaseCamera damping ->
healthy-sweep viewer resolution -> PortalVisibilityBuilder.Build ->
ClipFrameAssembler -> ViewconeCuller -> the DrawDynamicsLast predicate +
a CPU seal-depth model). 5 tests: cone pin, seal-depth pin, straddle
dual-draw pin, per-step table, stale-root window quantifier (#118 cand 2).

Suites: App 232 (227+5), Core 1416+2skip, UI 420, Net 294.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-06-11 16:49:29 +02:00
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
Erik
0e6e24faf6 docs: #118 narrowed - partition + per-tick ParentCellId exonerated; decision-stack candidates + exit-walk harness design recorded
Read-level exonerations: the local player routes to Dynamics correctly
(ServerGuid set), and its entity ParentCellId syncs per tick from the
controller - neither is the vanish mechanism. Live candidates are the
doorway-crossing decision stack: (a) eye/cell incoherence under camera
damping (the verified #115/BR-8a divergence - we damp from our own
damped eye while the root comes from the swept cell), (b) the
exit-portal side test culling the OutsideView when the eye is
epsilon-outside while the root is still interior (retail's
AdjustPosition demotes the viewer cell the same moment), (c) the
aperture-cone tightness for an outdoor player with an indoor viewer.
Next step is the deterministic exit-walk harness (all-CPU drive of the
production decision stack over the corner-building cells); designed in
the issue entry, queued for a focused session.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-06-11 16:11:54 +02:00
Erik
2d15084243 #120: arm the propagation tripwire for self-attribution + two convergence regression pins
Investigation: retail's growth propagation RECURSES natively too
(AddViewToPortals -> FixCellList -> AdjustCellView -> AddViewToPortals,
Ghidra 0x005a52d0/0x005a5250/0x005a5770, no depth guard) - the in-place
recursion shape is faithful; retail's safety is fast convergence. Our
depth-128 firing means slow/non-saturating growth (each lap of a portal
cycle nests one recursion level), not necessarily a true infinite loop.

Two dat-backed sweeps over the corner-building cell set could NOT
reproduce the T5 firing:
- PortalPlaneCrossings_InPlacePropagationConverges: +/-6cm eye sweep
  across every portal plane, seeded from both sides.
- InCellDirectionSweep_InPlacePropagationConverges: 3024 builds, in-cell
  eye grid x 8 yaw x 3 pitch (the walking-and-turning regime).
Both pass with 0 firings -> production-only ingredients suspected (full
lookup graph - one T5 firing was 0x0162, another building - and/or the
real camera path).

Armed: PortalVisibilityBuilder.ConvergenceTripwireCount (test
observable, both Build + look-in sites) + DumpPropagationChain - on the
next firing the log carries root cell, eye, per-cell frequency summary,
and the 24-entry chain tail, so the cycle's structure (A<->B ping-pong
vs 3-cycle laps) reads directly off the output. Both sweeps stay as
regression pins.

App tests: 227 green (was 225; +2 pins).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-06-11 15:57:25 +02:00
Erik
af5d424df0 docs: T5 comprehensive gate verdict - PARTIAL PASS; #108/#109/#97 closed, #117-#120 filed
The single comprehensive visual gate (2026-06-11, user-driven):

CONFIRMED (user axioms): doors block both ways incl. off-center (#99
visual pass), cellar descent/ascent clean + #108 grass-sweep GONE, inn
2nd floor clean (#97 CLOSED), interiors stable through doorways incl.
edge-on, #109 far-door oscillation GONE, formerly-popping stairs now
stable at all ranges. The entire T6/BR-7 collision port passed 100%.

REMAINING (render, filed at mechanism level - no live whack-a-mole):
- #117 aperture-shaped see-through: doors/interiors visible through
  terrain hills and through nearer buildings (the far-Z punch erases
  occluder depth at aperture pixels). Decomp direction:
  DrawPortalPolyInternal depth state vs draw order.
- #118 character clipped + vanishes momentarily on house exit
  (viewer-indoor/player-outdoor transition frames; local-player
  partition / aperture-clip suspects).
- #119 old-tower stairs partially invisible + extraneous water barrel
  (pre-existing); T5-log lead: [up-null] 0x010002B4 + 0x010008A8
  cached EMPTY render data, permanently invisible.
- #120 [pv-ERROR] in-place propagation tripwire at depth 128 on the
  cottage interior cells (T2 convergence invariant break, self-detected
  during the gate) - investigate FIRST.

Rain-indoors not verifiable (clear weather).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-06-11 15:46:30 +02:00
Erik
60c10707a3 docs: T6 (BR-7) ship closeout - #99/#90 closed, #97 likely-closed note, #116 filed, plan stamped
- ISSUES.md: #99 DONE (per-cell shadow architecture, dbfbf85+ca4b482;
  visual rides T5); #90 DONE (stickiness workaround removed, retail
  ordered-pick owns doorway hysteresis); #97 likely-closed note (the +5m
  pad producer deleted - verify at T5); #116 filed (slide-response
  family: tick-22760 lateral-slide loss + BSPStepUp D4 first-frame
  behavior, both pre-dating BR-7, oracle-first fix shape).
- Port plan: execution stamp updated to BR-2..BR-7 ALL CODE-COMPLETE
  with the per-commit map; BR-7 section marked code-complete; remaining
  = T5, the single comprehensive user visual gate.
- Memory digests (physics + render + MEMORY.md index) updated in the
  same session per the digest protocol.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-06-11 14:49:18 +02:00
Erik
dbfbf8506c T6 (BR-7) C3: per-cell shadow architecture - flood registration, building channel, per-cell query; b3ce505 stopgap DELETED (closes #99)
The A6.P4 port, fused into one installment per the BR-2 half-port lesson
(registration and query are co-dependent: flood-registering shells under
the old radial query would re-open #98 through the vestibule).

REGISTRATION (ShadowObjectRegistry rewritten):
- Register/RegisterMultiPart/UpdatePosition compute the cell set via
  CellTransit.BuildShadowCellSet (the C2 find_cell_list flood) seeded by
  the entity's m_position cell id; the private 24m XY-grid rectangle and
  its single-landblock clamp are deleted. Flood spheres follow retail's
  CylSphere rule (base point + cyl radius, cap 10; BSP bounding-sphere
  fallback - Ghidra 0x0052b9f0). Statics flood with the do_not_load
  prune; dynamics (server spawns, isStatic:false) without.
- Keep-when-empty (SetPositionInternal num_cells gate, pc:283540): a
  failed flood leaves the previous registration in place.
- RefloodLandblock: streaming-race hook re-runs the flood when a
  landblock's cells hydrate (retail init_objects -> recalc_cross_cells,
  Ghidra 0x0052b420/0x00515a30); wired at GameWindow's hydration tail.
- GameWindow sites pass the server position's full cell id as the seed
  (spawn + UpdatePosition); the five static sites pass ParentCellId.

BUILDING CHANNEL (CSortCell.building shape):
- Building SHELLS are not shadow objects in retail (only caller of
  find_building_collisions is CSortCell::find_collisions 0x005340aa;
  one building per origin landcell, init_buildings 0x0052fd80 verified
  verbatim + ACE cross-ref). IsBuildingShell entities skip the registry;
  Transition.FindBuildingCollisions runs the shell part-0 BSP off
  cache.GetBuilding(cellId) with bldg_check set around it
  (find_building_collisions 0x006b5300), CollidedWithEnvironment on
  non-Contact non-OK. BuildingPhysics.ModelId = pre-resolved part-0
  GfxObj (0x02 Setups resolved at the CacheBuilding site).
- Placement/ethereal weakening: BSPQuery Path 1 passes center_solid=0
  when BldgCheck && HitsInteriorCell (BSPTREE::find_collisions 0x0053a82e
  + placement_insert 0x005399d8) so doorway crossings don't hard-fail
  against shell solids. SpherePath gains both retail fields;
  HitsInteriorCell is rebuilt at every cell-array build
  (build_cell_array reset 0x00509ef2 + find_cell_list/check_building_
  transit set sites).

QUERY (retail per-cell order, transitional_insert 0x0050b6f0):
- TransitionalInsert per attempt: env -> building (LandCell only) ->
  objects on the PRIMARY cell, then on OK the check_other_cells pass
  (env -> building -> objects per OTHER overlapped cell) + the
  carried-cell advance - the advance now happens AFTER all per-cell
  object passes (the WF1 ordering divergence), with Adjusted/Slid
  feeding the retry exactly like retail's OK_TS case.
- FindObjCollisionsInCell = CObjCell::find_obj_collisions (0x0052b750):
  iterate ONLY the asked cell's list. DELETED: the radial 9-landblock
  sweep, the +5m query pad, the b3ce505 indoor-primary gate, and the
  isViewer exemption (the camera is bounded by interior cell-BSP env
  collision - retail's own channel; CameraCornerSealReplayTests pins it
  against real dat, and the new building-channel camera test pins the
  outdoor stop).

TESTS: Core 1416/0/2 (was 1398 + 4 pre-existing #99-era fails + 1 skip),
App 225, UI 420, Net 294 - all green.
- 3 of the 4 #99-era reds flipped green as designed: the door apparatus
  (Apparatus_Grounded_50cmOffCenter_FrontApproach_Blocks) and tick-13558
  (indoor walkthrough) now assert the door BLOCKS; tick-22760 pins the
  outdoor blocking invariant.
- The 4th (BSPStepUp D4) + 22760's lateral-slide delta are NOT cell-set
  problems (probes prove the door is found + BSP-only dispatched;
  BR-7 left both byte-identical) - filed as issue #116 (slide-response
  family), D4 skipped with the issue reference.
- FindEnvCollisionsMultiCellTests migrated to the public entry (the A4
  multi-cell halt now lives at the retail call site).
- New registry pins: per-cell query surface, outdoor-footprint-never-
  indoor (#98 architectural), door-outdoor-cell membership, reflood.
- CameraCollisionIndoorTests rewritten against the building channel
  (the isViewer-exemption pins died with the exemption).

Closes #99 (doors block both ways via registration-time cell membership
+ the straddle-spanning player cell array). #97 likely closed (the +5m
radial pad that produced phantom-collision candidates is gone) - verify
at T5. #98 stays closed ARCHITECTURALLY (outdoor footprints structurally
cannot reach interior cells; the cellar harness stays green).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-06-11 14:37:50 +02:00
Erik
85fe20f51d docs: stamp the port plan with end-of-day execution status (BR-2..6 code-complete, BR-7 + T5 remaining)
Doc-and-reality sync before the session handoff: the plan's phase
sections read future-tense while T1-T4 landed them. The render digest
carries the authoritative ledger; this stamp points there and names the
4 pre-existing #99-era Core failures as BR-7's built-in acceptance
signal.
2026-06-11 13:23:28 +02:00
Erik
1e5db94f0e docs: plan amendment - user directive: port everything, test once at the end
'I don't care if it is non-playable... I want everything ported, then we
test.' Per-phase playability + per-phase visual gates DROPPED. BR-2..BR-6
execute as ONE continuous port with build+tests green per commit and a
single comprehensive visual pass at the end (T5). Replaces the
playability rule with: every installment must be a COMPLETE retail
behavior, never half of one (the BR-2 punch-without-ordering lesson,
88be519).
2026-06-11 11:03:37 +02:00
Erik
9abbf58cb0 docs: #108 re-attributed render -> membership (BR-2 gate finding)
The BR-2 punch/seal gate proved #108 (cellar grass-sweep) is a membership
flip (player classified outdoor mid-cellar), not a render depth bug. The
punch only masked it on outdoor-root frames. Move #108 to the membership
track; the interior depth seal is a separate mechanism that does not fix it.
2026-06-11 10:37:40 +02:00
Erik
695eca2c1f BR-1: RESOLVED as already-equivalent - premise falsified by pre-check, equivalence pinned, #113 attribution corrected
The plan's BR-1 ('implement the skipNoTexture draw-time surface gate')
died on its pre-check: acdream ALREADY suppresses every portal fill.
ReplicateProductionEmission_OnPortalFills replicates the exact emission
conditions of the production extractors on the hall/cottage fills:
pos=False neg=False for every one (Stippling.NoPos skips the positive
side at ObjectMeshManager.PrepareGfxObjMeshData:1046,
PrepareCellStructMeshData:1394, CellMesh.Build:44, GfxObjMesh.Build:71;
the fills have no negative surface). There is nothing to gate.

What ships instead: StipplingSurfaceEquivalenceTests - 2,607 polys across
13 building models + 13 environments, ZERO violations both directions:
NoPos <=> untextured-surface. Our build-time skip is proven equivalent to
retail's draw-time skipNoTexture rule (Ghidra 0x0059d4a4, default on
@0x00820e30) on this content. The pin fails loudly if future content
breaks the invariant - the cue to implement the draw-time gate then.

Corrections folded into the plan + comparison docs:
- The #113 phantom residual CANNOT be GfxObj fills (they never reach a
  vertex buffer). Plausible true sites are cell-side: flood-admitted
  cells drawn with the pass-all NoClipSlice when slot-less
  (RetailPViewRenderer.cs:71), and/or cell statics drawn unclipped +
  un-viewcone'd (object-lists-skip-portal-view-gate, confirmed).
  BR-2 opens with the probe that pins which.
- The e46d3d9 user-gate observations (filter removed phantom/doors) were
  confounded - the filter was a provable mesh no-op on shells AND doors.
- Ledger rows solid-surface-skip-missing + the acdream half of
  portal-polys-baked-unconditional re-marked REFUTED-for-fills; the
  retail mechanism descriptions and the un-consumed PortalIndex->
  CBldPortal pairing (BR-4) stand.

Suites: Core 1398 green (1392 baseline + 6 new facts) + the 4 pre-existing
#99-era failures + 1 skip. No production code.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-06-11 06:25:31 +02:00
Erik
eb689ae73f docs: add "out of scope / tracked follow-ups" section to the port plan ($4)
Names the boundary of what BR-1..BR-8 delivers, so the gaps are written
down rather than silently assumed (the very thing that breeds whack-a-mole):
FU-1 transparency/sorting (BR-9 candidate, area unmapped), FU-2 dungeon
visibility scaling #95 (plausibly helped by BR-4/BR-6 but NOT guaranteed -
re-measure after), FU-3 LOD/degrades, FU-4 picking, FU-5 the ~30 open
questions (in the comparison doc $6), FU-6 verification top-up before
BR-8b lighting. None blocks BR-1..BR-8; each becomes its own item.

The #95 dungeon-scaling follow-up was previously raised only verbally -
now tracked in the plan. Sections 4/5 renumbered to 5/6.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-06-11 06:15:03 +02:00
Erik
5e2f99d08e docs: Phase A comparison + Phase B port plan (holistic building-render investigation)
Deliverable 1: docs/research/2026-06-11-building-render-acdream-vs-retail-
comparison.md - the acdream-vs-retail architecture comparison synthesized
from two ultracode mapping fan-outs (11/12 areas, ~90 agents, every retail
claim Ghidra/pc-cited, every acdream claim file:line, 40/76 divergences
adversarially verified so far; raw per-area evidence committed under
docs/research/2026-06-11-holistic-map/).

Headline findings: (1) retail flattens GfxObjs/cells at load exactly like
us (ConstructMesh + RemoveNonPortalNodes) - the MDI pipeline survives;
(2) the phantom/door mechanism is the skipNoTexture draw-time surface gate
(dat-confirmed); (3) retail never geometrically clips world geometry -
aperture exactness is a DEPTH discipline (punch maxZ1 / seal maxZ2 / gated
clear + far-to-near whole-mesh draws) - reframes #114; (4) flood admission
is already faithful, the trigger/depth/multi-view/cone-culling layers are
missing; (5) #115 root cause verified (boom damping severed from the
published collided viewer); collision A6.P4 design verified with
corrections (signed other_portal_id >= 0 gate).

Deliverable 2: docs/plans/2026-06-11-building-render-port-plan.md - the
phased port plan (BR-1 surface gate, BR-2 depth punch/seal, BR-3 delete
the shell chop, BR-4 draw-driven floods, BR-5 viewconeCheck, BR-6 one
gate, BR-7 collision A6.P4, BR-8 camera/lighting/LOD) with per-phase
acceptance criteria, bug closures, keep-list, and a playable-after-every-
phase migration order. AWAITING USER APPROVAL - no implementation.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-06-11 05:54:12 +02:00
Erik
9c45144047 docs: holistic building-render port charter + next-session prompt (the 2026-06-11 mandate)
User mandate: stop bug-by-bug; map acdream-vs-retail for building draw,
interiors, interior collision, dynamics, clipping, culling; plan the port
of retails drawing discipline once and for all. The handoff carries the
branch state (124c6cb, nothing on main), the full evidence inventory from
this session (orphan no-draw polys, door-vanish mystery, draw-side clip
status, straddle gate), the gap map, tooling (Ghidra MCP 8081 correct
PDB, live cdb protocol, dat dump + flood harnesses), the investigation
charter (workflow fan-out per subsystem, adversarial verification), and
the paste-ready new-session prompt. #113 marked REOPENED and folded in.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-06-10 21:50:23 +02:00
Erik
6c9bbce433 docs: file #114 (indoor shell-clip region quality) + #115 (camera feel) from the first user gate
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-06-10 20:24:09 +02:00
Erik
8259598970 docs: #113 closed (attribution + fix) + #112 residual resolved in ISSUES.md
#113 moved to Recently closed: the phantom staircase was the Holtburg
meeting hall (AAB3, not A9B3) interior stair cells drawn unclipped from
outside - the PView shell clip was routed but never GL-enabled (927fd8f).
Misplaced-cell hypothesis refuted with dat evidence. #112 residual
paragraph updated: retail straddle gate live-binary verified + ported
(414c3de); at-doorway demote is retail-faithful, deep gaps now keep-curr.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-06-10 16:56:27 +02:00
Erik
6d2218cac3 docs: #113 pickup handoff - phantom-stairs/misplaced-cell attribution plan + #112 residual rider + tonight's shipped-state table
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-06-10 15:28:44 +02:00
Erik
77d7ea1530 docs: file #113 - phantom exterior staircase on A9B3 building (unclickable => shell/cell geometry); suspect misplaced interior cell unifying #112-gap + collision symptoms
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-06-10 15:24:53 +02:00
Erik
6509a28926 docs: #112 primary fix shipped - hatch removed, lateral recovery in; residual = at-doorway demote via outdoor candidates (oracle read pending)
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-06-10 15:04:25 +02:00
Erik
e9c8a925d2 docs: file #112 - house containment gap demotes to outdoor with no containment-based re-promotion (A9B3 cottage, dat-scan evidenced)
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-06-10 14:46:22 +02:00
Erik
33662b35b6 docs: #111 closed - three-layer fix chain (bestCell clobber, triangle-soup grounding, entity snap parity), user-gated at two buildings
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-06-10 14:34:53 +02:00
Erik
383af0ab5f docs: file #111 - ACE-mutated indoor restores start outdoor-classified (transparent until door-press); evidence + retail fix direction
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-06-10 13:54:37 +02:00
Erik
34fcbc3806 docs: #107 closed - root cause + four-leg fix + live verification; ledger updated
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-06-10 12:53:42 +02:00
Erik
fb360ab3cc docs: #110 corner press USER-GATED - camera no longer clips into the wall pressed into a corner
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-06-10 12:18:43 +02:00
Erik
096b81657b docs: #105 x #110 CLOSED - staged-texture-flush drop close-out (evidence chain + lesson); handoff marked historical
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-06-10 12:17:09 +02:00
Erik
d4b5c71e66 fix(render): re-land near plane 0.1m (retail Render::znear) — #110 resolved, closes the §4 corner see-through; close #105/#110
The 137b4f2 payload, re-landed now that #110 is resolved: the missing-indoor-
textures correlation was the pre-existing #105 staged-texture-flush drop
(fixed in c787201), not a near-plane mechanism. znear=0.1 merely raised #105's
trigger probability — a closer near plane makes close-up geometry newly
visible, inflating per-frame prepare/upload pressure indoors and growing the
never-flushed tail. Exactly the handoff's only-credible-link hypothesis,
verified instead of assumed.

Retail: Render::SetFOVRad sets znear=0.1 flat (decomp :342173, initializer
:1101867). 0.1 < the 0.3m camera-collision sphere, so a wall the collided eye
presses against no longer falls inside the near plane — the §4 corner
see-through-wall closes.

Verification on the 0.1 arm (the arm that struck 2-of-3 on 2026-06-10):
nearplane-reland-1.log — [tex-flush] after=0 on all 45 lines, 68,291 [shell]
lines with zero zh>0 batches, all four dat tripwires silent, no [wb-error].
ISSUES.md: #105 + #110 moved to Recently closed with root cause + evidence.
Pending user re-gate: corner press (wall stays solid) + distance scan for
z-shimmer (none expected; retail ships 0.1 with D24).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-06-10 12:14:00 +02:00
Erik
5d63038b61 docs: #105 x #110 handoff - white-texture GL-side investigation plan + near-plane re-land path
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-06-10 11:17:36 +02:00
Erik
8bd3492612 revert(render): near plane back to 1.0m pending #110 - 0.1 correlated with missing indoor textures
Bisect (user-gated): two consecutive runs on 0.1 lost indoor textures; the 1.0 bisect run rendered clean. #105 tripwires silent on the bad runs (GL-side). No known mechanism links the near plane to texturing - #110 filed to investigate (RenderDoc / flip-testing) before re-landing retail's znear=0.1, which the corner see-through fix depends on. Comments on all four cameras point at #110 so the retail value is not re-landed blind.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-06-10 11:02:55 +02:00
Erik
137b4f2d25 fix(render): near plane 1.0m -> 0.1m (retail Render::znear) - corner see-through-wall; file #107-#109
The collided camera eye sits 0.3m from walls (viewer_sphere radius); a 1.0m near plane clipped the wall face away, so pressing the camera into a corner showed the clear color through the wall (gate result: unchanged by the flood fix - it was never a flood bug). Retail sets Render::znear = 0.1 flat in SetFOVRad (decomp :342173, initializer :1101867). All four cameras aligned. Also files #107 (indoor spawn wedge, 3-for-3), #108 (cellar-up terrain sweep across door opening), #109 (exit-door texture/background oscillation) from the 2026-06-10 visual gate; gate confirms the dac8f6a flood fix: room-room + indoor-outdoor transitions clean.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-06-10 10:48:53 +02:00
Erik
482b0dea1b docs: SS2b corner-seal refuted (openings, not walls) - SS4 converges on edge-on clip collapse; next = retail clip oracle
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-06-10 10:01:04 +02:00
Erik
df2ef7c598 docs: §4 outdoor full-world flap CLOSED — depth-mask leak close-out (evidence chain + fix + verification)
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-06-10 09:22:02 +02:00
Erik
d877e4329a docs: §4 outdoor full-world flap — onset pinned to building-flood merge (handoff)
Evidence-chain handoff for the outdoor flap investigation: frame-exact
onset (pv-input flood 1->5 + the gl-state doorway-box fingerprint, same
frame), the full probe exoneration chain (camera matrix NaN-free at
6 dp, eye above terrain, cross-frame GL leak refuted, full-screen quad
planes can't cull, MergeNearbyBuildingFloods doesn't touch OutsideView,
ClipFrame capacity clean), the two surviving kill-mechanism suspects
(per-instance clip-slot routing under outdoor roots / terrain UBO
content at draw time), the decisive [clip-route] probe spec, the
user-validated repro protocol, and the probe-semantics gotchas.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-06-10 08:19:54 +02:00
Erik
41fa3cbbc4 docs: #106 CLOSED — gate-4 verification + running-artifact attribution correction
Move #106 to Recently closed (user-verified collision + solid walls;
probe-verified 49 clean transitions incl. south A9B4->A9B3 at y=-0.19,
east A9B3->AAB3 at x=192.2, and room-by-room tracking through the
originally-failing A9B3 cottage). Records the three adjacent
pre-existing bugs the gate runs surfaced and fixed (legacy Resolve bare
ids, bogus-indoor-claim recovery, entry-hold streaming deadlock).

Correct the capture doc's attribution: the outdoor running distortion
was NOT fully the stale anchor — gate 4 shows residual background-color
screen artifacts persist with a correctly-following anchor. The
residual is the render §4 flap family (render digest), not membership.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-06-10 06:59:24 +02:00
Erik
23adc9c9df fix(phys): #106 follow-up — legacy Resolve returns full prefixed cell ids (teleport bare-id wedge)
The #106 live gate run was sabotaged by a pre-existing bug the corrective
ACE teleport exposed: PhysicsEngine.Resolve (the legacy Phase-D resolve,
still used by the teleport-arrival snap at GameWindow.cs:4869 and the
player-mode-entry snap at :11295) returned BARE low-word cell ids on
every computed exit (ComputeOutdoorCellId, bestCell.CellId & 0xFFFF,
nextCellIndex, enterCellIndex). The teleport committed 0x0000013F into
PlayerMovementController.CellId, and a bare indoor id wedges the entire
membership chain:

- GetCellStruct(0x0000013F) misses (cells are keyed full-prefix) -> no
  indoor wall BSP -> walk through walls;
- the b3ce505 #98 gate reads "indoor primary" -> outdoor object radial
  sweep skipped -> NO object collision anywhere in the world;
- BuildCellSetAndPickContaining early-returns an unresolvable id forever
  (block 0x0000 is a real far-NW map block) -> membership frozen;
- render root never resolves -> interiors draw empty when stepping in.

Probe evidence: probe-cell-106-gate.log has exactly 2 [cell-transit]
lines for the whole session, both reason=teleport — the second one
(0xA9B3003C -> 0x0000013F) is the wedge. This is the L.2e "player CellId
tracked as bare low byte" finding (2026-05-12) finally biting; prefix
survival until now was a race artifact — Resolve only preserved the full
id when the landblock had not streamed in yet (passthrough exit), which
is why login snaps usually came out prefixed.

Fix: capture the matched landblock's key in Resolve's containment loop
and return lbPrefix | (targetCellId & 0xFFFF) on the computed exit —
the same full-32-bit convention Resolve's own doc comment states for
its inputs, and what both production callers (player snaps) require.
The passthrough exits (no landblock / step-reject) still return the
caller's id unchanged.

Tests: Resolve_IndoorStay_ReturnsFullPrefixedCellId (the teleport
shape, red pre-fix) + Resolve_OutdoorStay_ReturnsFullPrefixedCellId;
Resolve_LeaveIndoorCell_TransitionsToOutdoor's unmasked
`CellId < 0x100` assertion codified the bare behavior — now masked +
asserts the prefix. Full suite: 294+218+420 green; Core 1371 green +
the same 4 pre-existing door/#99-era failures + 1 skip.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-06-09 23:34:30 +02:00
Erik
7078264291 fix(phys): #106 — outdoor membership crosses landblock boundaries (LandDefs global-lcoord port)
The player's outdoor cell froze at the last in-block cell the moment they
walked over a landblock boundary (10,449-frame playerCell freeze in the
2026-06-09 capture; whole neighbouring-block interiors unenterable, plus
the running-distortion from the stale render anchor). Root cause: the
add_all_outside_cells port clamped BOTH the candidate proposal and the
find_cell_list containing-cell pick to the current landblock's 8x8 grid,
in a frame that silently assumed the current block sits at world origin.
One step over the line -> zero candidates -> FindCellSet returns
currentCellId forever.

Retail has no such clamp. Its cell math runs in a GLOBAL landcell grid
(lcoord 0..2039 spanning the map): get_outside_lcoord = blockid_to_lcoord
+ floor(blockLocalPos/24) with no bounds besides the map edge, and
lcoord_to_gid re-derives the landblock id from the lcoord's upper bits —
crossings are inherent, never special-cased.

The fix, decomp-cited throughout:
- New AcDream.Core.Physics.LandDefs: in_bounds (pc:68509),
  blockid_to_lcoord (pc:68520), inbound_valid_cellid (pc:163438),
  gid_to_lcoord (pc:163500), lcoord_to_gid (pc:171859),
  get_outside_lcoord (pc:438690), adjust_to_outside (pc:438719).
  Cross-checked against ACE LandDefs.cs; three artifacts documented and
  avoided: BN's int8_t mis-render of block_y, BN's dropped 192f
  BlockLength constant, and ACE add_cell_block's "FIXME!" same-block
  guard (an ACE divergence, not retail).
- CellTransit.AddAllOutsideCells rewritten as the faithful sphere
  variant (pc:317499 @0x00533630): adjust_to_outside re-seats the
  (cell, position) pair cross-block, check_add_cell_boundary (pc:317229)
  adds up to 3 neighbours by global lcoord, add_outside_cell (pc:317056)
  has no same-block filter. adjust_to_outside failure breaks the sphere
  loop (pc:533699 verbatim).
- BuildCellSetAndPickContaining: the outdoor containing-cell pick is now
  the global XY-column under the sphere centre (AdjustToOutside), not
  the [0,8)-clamped current-prefix reconstruction. Interior-wins order
  and current-cell-first hysteresis unchanged.
- World->block-local frame conversion via the landblock origin already
  registered in CellGraph (new TryGetTerrainOrigin); Zero fallback
  preserves the legacy anchor-block assumption for unregistered terrain.
- Cross-landblock building entry comes free: the candidate snapshot now
  contains neighbour-block landcells, so GetBuilding/CheckBuildingTransit
  fire for cottages across the line (the capture's one failing entry).

Investigated FIRST per the pickup brief: the b3ce505 #98 stopgap gate is
definitively exonerated — it is a collision-object query gate that fires
only for indoor primary cells; no membership path touches
ShadowObjectRegistry.

Tests: 31 new (25 LandDefs conformance incl. capture-geometry goldens
0xA9B40031 -> 0xA9B30038/0xA9B30034 and the northbound return; 4
AddAllOutsideCells cross-block; 3 FindCellSet membership goldens incl.
the non-anchor-frame origin conversion). Full suite: 294+218+420 green;
Core 1369 green + the 4 pre-existing door/#99-era failures + 1 skip
(unchanged from baseline).

Pseudocode + artifact notes:
docs/research/2026-06-09-landdefs-outside-cells-pseudocode.md.
Remaining acceptance: live boundary walk with ACDREAM_PROBE_CELL=1
(ISSUES.md #106).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-06-09 23:10:59 +02:00
Erik
12fb408972 docs: #106 pinned — outdoor membership freezes at landblock boundaries
The 53MB flap-probe capture (user live-reproduced the broken-house entry)
plus 3-agent analysis settles the day: playerCell froze at 0xA9B40031 for
10,449 frames spanning ~130m of outdoor walking into landblock A9B3 and a
stand INSIDE an A9B3 cottage. Within-landblock outdoor flips are 96/96
clean; all 10 successful indoor entries were same-landblock buildings; the
single cross-landblock entry failed. The render flood independently drew the
A9B3 interior cells the whole time — rendering is downstream and healthy;
membership is the broken layer (feedback_render_downstream_of_membership,
proven again). The stale render anchor also explains the outdoor running
distortion; the capture refutes flood-level causes outdoors (26,960/26,960
outdoor frames rigid at outPolys=1 vis=1).

Files #106 (HIGH, physics/membership) with fix pointers: ResolveCellId /
AddAllOutsideCells cross-landblock proposal, the b3ce505 outdoor-sweep gate
(possible stopgap fallout, like #99), retail find_cell_list :308742 +
LandDefs.get_outside_lcoord. Reframes #105: largely superseded by #106;
residual (single wall missing while membership indoor-correct) stays open
with all tripwires armed. Handoff:
docs/research/2026-06-09-105-capture-analysis-membership-landblock-pin.md

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-06-09 22:38:19 +02:00
Erik
8dc707d43b docs: dat-reader investigation handoff + file #105 (white walls, tripwired)
Records the 2026-06-09 dat-reader thread-safety investigation: concurrent
READS on Chorizite.DatReaderWriter 2.1.7 exonerated (source audit + 1.1M-read
hammer, b3920d8); the real crash was dispose-during-read at teardown (fixed,
8fadf77); the white-walls mechanism remains open as #105 with every silent
dat-miss exit tripwired (7433b70) so the next occurrence self-attributes.

Also corrects project lore: the A.1-era rule that all dat reads must stay on
one thread does not hold for the 2.1.7 read path, and both investigation
subagents'' claimed ReadBlock instance-field race does not exist in the
shipped source — verify agent claims against source before acting on them.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-06-09 21:29:06 +02:00
Erik
a1b12dff40 docs(render): R-A2b shipped + flap residual (sec 4) + texture red-herring handoff
R-A2b (485e44d) killed the 0171<->0173 churn (maxPop 16->1, measured). Visible flap residual is sec 4 (edge-on openings render-side + corner camera-seal). Camera-damping tried+failed+reverted. The white-walls scare was a RED HERRING: heavy per-frame probes (ACDREAM_PROBE_FLAP) starve the thread-unsafe dat-reader so texture-decode loses the race -> white; a clean launch (no probes) fixes it. The dat-reader thread-safety bug is the real underlying issue (filed). Repo clean at HEAD.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-09 18:44:33 +02:00
Erik
7b8a490da9 docs(render): R-A2b plan — back-portal side-cull (Option B), verify-first B1/B2 pin
Reading retail InitCell (:432896) side test during writing-plans showed retail's flood is acyclic (the back portal fails the side test, so 0171<->0173 can't cycle). Our flood traverses the back portal -> the cycle -> the churn. Option B (user-chosen): cull the back portal like retail, keep the forward-portal void rescue, remove the dead cap. Phase 1 pins WHY the back portal is traversed (B1 eyeInsideOpening bypass vs B2 CameraOnInteriorSide convention) before the fix; spec REVISION updated A->B.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-09 10:25:28 +02:00
Erik
3fd71a123c docs(render): R-A2b spec — revive bounded-propagation, churn confirmed at flap-time
The indoor doorway flap is the portal flood's re-enqueue churn (0171<->0173 mutual re-contribution; drifted near-duplicate regions AddRegion won't dedup -> grew -> re-enqueue, capped at MaxReprocessPerCell=16 -> eye-sensitive flood depth -> grey flash). Confirmed live: launch-churn-confirm.log shows maxPop=16 on 44% of frames during a doorway walk-through. The 2026-06-08 'maxPop=1, churn refuted' verdict was a camera-turn-at-rest capture (wrong reproduction); its DO-NOT is overturned.

Fix (Option A, user-approved): contributions already covered by the neighbour's accumulated view don't grow it (no re-enqueue); only the uncovered remainder propagates -- retail's 'redundant -> empty before copy_view' (copy_view confirmed to just append). Remove MaxReprocessPerCell; keep re-processing of genuinely-new slices. Scope: PortalVisibilityBuilder only. Revives 2026-06-08 spec+plan (banners redirected).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-09 09:48:53 +02:00
Erik
8f879bd7d9 docs(render): calibrated indoor-flap handoff — MEASURED vs HYPOTHESIS vs OPEN
Separates what is measured (eye smooth + 1um at rest -> not jitter) from the leading-but-unproven hypothesis (clip edge-on) and the NOT-ruled-out alternative (camera position: retail eye collided/head-on 93%, ours floats edge-on). The one 'clean' pass had ratio 4.2x back-and-forth, so the flood claim is indicated not proven. Lists the verify-first steps before any R-A2b fix. Counters this session's pattern of overclaiming then refuting.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-09 08:16:51 +02:00
Erik
8c78f1f07a docs(render): plan status — R-A4 ruled out by measurement; remaining work is R-A2b (indoor-flood edge-on robustness)
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-09 08:10:06 +02:00
Erik
c62663d7cb feat(render): R-A2 — per-building floods (the flap fix)
Replace the outdoor root's single unified reverse-portal flood (whose root-level
portal-side test oscillated as the chase eye grazed a doorway — the measured
flood 2<->6) with retail's per-building floods.

- OutdoorCellNode.Build(uint): portal-less land root; floods only itself ->
  full-screen OutsideView -> terrain (PortalVisibilityBuilder IsOutdoorNode seed).
- PortalVisibilityBuilder.ConstructViewBuilding: per-building flood seeded at a
  building's own finite entrance (retail ConstructView(CBldPortal) 0x5a59a0 via
  DrawPortal 0x5a5ab0 / portal_draw_portals_only 0x53d870). Entrance-bounded ->
  consistent ~2-cell depth (measured retail cell_draw_num, handoff OPTION-A 3.4).
- RetailPViewRenderer.DrawInside: when the root is the outdoor node, group nearby
  cells by BuildingId and merge each per-building flood into the frame before
  assembly; existing shells/object-list draw path unchanged. 48 m seed cutoff.
- GameWindow: pass flat NearbyBuildingCells only on outdoor-node frames.

Tests: +3 PortalVisibilityRobustnessTests (per-building touches ~2 cells, membership
stable under the measured 36 um eye jitter). UnifiedFloodTests retired (its subject,
the unified flood from the outdoor node, is removed); surviving full-screen-OutsideView
coverage moved to OutdoorCellNodeTests. App Rendering 207/207, Core movement 14/14.

Conformance-verified sound; the grazing-doorway flap is the visual acceptance test.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-08 18:44:43 +02:00
Erik
7fe98098f5 refactor(render): R-A1 — canonicalize outdoor-root detection on IsOutdoorNode
Replace ReferenceEquals(clipRoot, _outdoorNode) object-identity checks with the
documented LoadedCell.IsOutdoorNode flag (4 sites) so they survive R-A2 changing
the outdoor root's portals. Behavior-preserving (build + targeted suites green:
App PortalVisibilityBuilderTests 24/24, Core PlayerMovementControllerTests 14/14).

Right-sized from the planned 'collapse to one root': reading the live dispatch,
the viewerRoot ?? outdoorRoot split is already correct (viewerRoot feeds
cameraInsideCell/lighting via the older CellVisibility BFS; clipRoot is the render
root), and the 2026-06-07 cutover flip already made in-world frames single-path
DrawInside. The real flap fix is R-A2 (per-building floods). Dead exterior
DrawPortal look-in deletion deferred to R-A3.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-08 18:25:58 +02:00
Erik
6996e5645c docs(render): mark bounded-propagation plan + spec SUPERSEDED (churn refuted by measurement)
Point both at the Option-A full-retail-port handoff so a fresh session can't follow the dead plan.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-08 16:20:24 +02:00
Erik
fe87e9794a docs(render): FLAP settled by live-retail measurement — full retail port DECIDED (Option A) + exhaustive handoff
Attached cdb to the live 2013 retail client at the Holtburg doorway + read the decomp.
The indoor flap is a STRUCTURAL divergence, settled by measurement (not inference):

- Retail has ONE render path: DrawInside(viewer_cell) every frame. NO inside/outside
  branch (RenderNormalMode's outside branch is dead code; is_player_outside only gates
  sky/lighting). "Entering a building" is not a render event — only the camera sweep
  resolving a different viewer_cell. Same path before/after threshold -> no seam.
- Retail's eye JITTERS ~36um at rest yet membership is stable -> robustness is
  STRUCTURAL: many small per-building floods (~7/frame, ~2 cells each, via terrain BSP
  -> DrawPortal -> ConstructView(CBldPortal)), not one giant knife-edge flood.
- Our 3 divergences: (D1) invented inside/outside branch (GameWindow.cs:7498,
  clipRoot = viewerRoot ?? _outdoorNode :7396); (D2) synthetic _outdoorNode; (D3) one
  unified flood.

DECISION (user-approved): Option A — rip out branch + outdoor node, root always at the
real viewer_cell, one DrawInside, per-building rendering. Phased, conformance-tested,
visual-gated.

REFUTED by measurement (do not retry): bounded-propagation/churn (maxPop=1, 0/63k
reciprocals empty); byte-stable eye (retail's jitters ~36um — rest-snap cd974b2 failed +
regressed, reverted 9b1857a).

Lands the canonical exhaustive handoff for a FRESH session
(docs/research/2026-06-08-full-retail-render-port-OPTION-A-handoff.md), the CLAUDE.md
READ-THIS-FIRST banner, and reusable cdb apparatus. No project code changed; working tree
at the known-good baseline.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-08 16:19:34 +02:00
Erik
a3dadbf664 docs(render): implementation plan — portal-flood bounded-propagation (instrument+pin, then fix)
Phase 1 (fully specified): add the [portal-churn] probe (per-Build re-enqueue +
reciprocal pre/post), a deterministic re-pop anchor test, and a live doorway
capture to PIN the exact divergence (where acdream's redundant reciprocal
back-contribution stays non-empty where retail clips to empty) — a float-drift
runtime fact, not derivable from decomp.

Phase 2 (evidence-gated outline): port the bound (redundant contributions don't
add propagatable slices; remove MaxReprocessPerCell), keeping re-processing +
Build_ViewGrowthAfterDoneCell green. Gets its own no-placeholder plan after the
Phase 1 pin — apparatus-first, not a deferred placeholder.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-08 12:38:02 +02:00
Erik
ab6ed905f1 docs(render): correct flap spec — enqueue-once REFUTED, bounded-propagation port
The writing-plans decomp pass read FixCellList (433407) -> AdjustCellView (433741)
-> ClipPortals(update_count) + AddViewToPortals, proving retail RE-PROCESSES a
grown-after-drawn cell. So the approved "enqueue-once / no re-process" approach is
wrong (it would break Build_ViewGrowthAfterDoneCell for the right reason — that test
is actually retail-faithful).

Corrected approach (user chose the faithful moderate port over an epsilon-dedup
band-aid): KEEP re-processing on growth, but BOUND it the way retail does — each
view slice processed once (monotonic update_count watermark) and redundant
reciprocal back-contributions clip to EMPTY (OtherPortalClip -> no copy_view -> no
new slice), so the reciprocal/drift loop can't churn. acdream churns because its
reciprocal yields a drifted non-empty sliver, bounded only by the
MaxReprocessPerCell=16 hack. Remove the cap; bound structurally.

Scope unchanged: PortalVisibilityBuilder only; no rooting/camera/clip-math-rewrite/
seal change. One open precision (exact line where acdream's sliver becomes
non-empty — float-drift-dependent on real geometry) deferred to the plan's first
task: instrument PortalVisibilityBuilder (per-pop re-pop count + reciprocal-clip
in/out + grew), capture at the doorway, pin it, THEN fix.

Spec updated in place with a REVISION banner; superseded enqueue-once body retained
for the audit trail.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-08 12:33:06 +02:00
Erik
6c3a96b26e diag(render): flap re-diagnosed as portal-flood re-clip DRIFT; physics + camera REFUTED
The 2026-06-08 AM "physics rest micro-jitter" diagnosis is refuted with primary
evidence (door-recheck 216K standstill records: 0 position re-snaps; player
byte-stable during the flap). Two adversarial verification sub-agents confirmed:

- Retail roots the render at the camera viewer_cell (swept from the player via
  SmartBox::update_viewer 0x453ce0; DrawInside(viewer_cell) 0x453aa0) and toggles
  DrawInside / LScape::draw -- so acdream's eye-cell rooting + inside/outside
  toggle are RETAIL-FAITHFUL. The locked-design "root at player cell" is wrong.
- The flap is render membership instability, eye-motion-driven: the visible-cell
  set oscillates (8<->3) as the eye sweeps monotonically. Root = the
  re-enqueue-on-growth DRIFT (PortalVisibilityBuilder.cs:322, MaxReprocessPerCell
  =16) re-clipping each grown cell every round -> sub-cm eye jitter flips membership.

Fix (spec, not yet implemented): verbatim port of retail's enqueue-once flood
(ConstructView + AddViewToPortals): enqueue once on first discovery, clip each
cell's portals once, union late growth in place (AddToCell) + draw-reorder
(FixCellList), never re-enqueue. Kills the drift; rooting/camera/seal untouched.

This commit lands VERIFIED GROUNDWORK + design only:
- spec: docs/superpowers/specs/2026-06-08-portal-flood-enqueue-once-port-design.md
- findings: docs/research/2026-06-08-flap-physics-diagnosis-REFUTED-its-render-membership.md
- [pv-input] probe gains rawPlayer + yaw (disambiguates the varying input)
- 4 GREEN physics rest-stability tests (prove rest is bit-stable -> flap not physics)
- apparatus: launch-flap-capture.ps1, analyze_flap_live.py, find_burst.py
- captured fixtures: tests/.../Fixtures/flap-doorway/0xA9B4017{0..5}.json

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-08 11:21:46 +02:00