Apparatus + handoff for the indoor flap. Confirmed (primary evidence): the flap is the portal-flood clip being µm-sensitive at the threshold, driven by a ~1-8µm jitter in the player RenderPosition (physics resting position not bit-stable; Lerp surfaces it). REFUTES the 2026-06-07 see-through/EnvCell/outdoor-node diagnosis (ModelId GfxObj 0x01000A2B IS the solid exterior) AND an enqueue-once attempt (retail propagates late slices via AddToCell; the existing PropagatesNewSlicesToExit test caught it; reverted). Adds: Build determinism test, A8CellAudit gfxobj dump, [pv-input] 6dp probe + [render-sig] outRoot/bshell fields. No functional fix shipped. Next: higher-precision physics rest trace -> port retail kill_velocity/contact rest-stability. Canonical: docs/research/2026-06-08-flap-rootcause-physics-rest-handoff.md Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
8.1 KiB
Handoff — the indoor FLAP traced to a physics rest µm-jitter; prior diagnoses REFUTED — 2026-06-08
CANONICAL PICKUP for the indoor render flap. This session refuted the 2026-06-07 cutover-flip diagnosis AND an enqueue-once attempt, confirmed the real mechanism with primary evidence, and traced the root all the way down to a physics resting-position µm jitter. The fix is in physics (rest-stability), is teed up, and needs one more higher-precision trace to pin the exact cause before porting. Spec:
docs/superpowers/specs/2026-06-08-portal-flood-membership-stability-design.md(its §4 enqueue-once design is REFUTED — see §3 here; its §6 physics contingency is now the active direction).
1. What the flap IS (confirmed, primary evidence)
At the Holtburg cottage doorway threshold, the portal-visibility flood set oscillates frame-to-frame
(ids=[0170,0171,0172,0173,0174,0175] ↔ [0170,0171], i.e. 6↔2 cells) from a stable viewer cell
(root=0xA9B40170, outRoot=n). The deep 0172-0175 cluster pops in/out → textures "battle."
- It is NOT see-through walls from outside (standing outside with the door closed is stable — user visual gate), NOT the outdoor node, NOT a root toggle, NOT nondeterminism.
PortalVisibilityBuilder.Buildis a pure deterministic function (proved byPortalVisibilityBuilderTests.Build_IsDeterministic_*, passes). So the flip requires a varying input.- The high-precision
[pv-input]probe (6 dp) shows the camera eye AND the playerRenderPositioncarry perpetual ~1–8 µm float jitter at rest (e.g. player Z94.000000 ↔ 94.000008). At the threshold a grazing portal's clip is so knife-edge that this µm jitter flips its empty/non-empty result → the flood membership flips → the flap.
Mechanism chain:
physics resting position blips ~µm → ComputeRenderPosition Lerp surfaces it as µm eye jitter → the portal-flood clip (clip-non-empty membership) is µm-sensitive at the grazing threshold portal → flips → flap. Retail is flap-free because its authoritative local position is bit-stable at rest (so its same
clip-non-empty membership never crosses the boundary).
2. REFUTED — the 2026-06-07 cutover-flip diagnosis (do NOT act on its F1/F2)
docs/research/2026-06-07-cutover-flip-render-residuals-diagnosis-handoff.md is wrong on its
load-bearing claims (primary evidence in this session):
- "See-through from outside" — not reproduced (outside, door closed, is stable).
- "Walls ARE the EnvCell shells; ModelId is a partial frame" — refuted: the cottage ModelId GfxObj
0x01000A2Bis a full closed exterior (76 render polys, bbox 20×18×10.4 m, 46 outward-facing walls + roof —tools/A8CellAudit gfxobj 0x01000A2B). EnvCell shells are interior-facing. F2 (EnvCell back-faces) targets the wrong geometry. - "Oscillation = outdoor-node flood (1↔13)" — corrected: it is the indoor flood, stable root, 2↔6. F1 targeted the wrong root.
- "branch=RetailPViewInside every frame proves the flap is gone" — tautological (post-flip
clipRoot = viewerRoot ?? _outdoorNodeis ~never null, sobranchcan't reportOutdoorRoot).
3. REFUTED — enqueue-once traversal (TDD caught it)
Hypothesis: the flap is acdream's MaxReprocessPerCell re-enqueue drift; restore retail's enqueue-once
(first-discovery only, no re-enqueue). Refuted: retail does NOT stop at first discovery — its
AddViewToPortals growth branch calls AddToCell (decomp :433494), so a cell's later-grown view
IS propagated (late slices reach exit portals). The existing test
PortalVisibilityBuilderTests.Build_ViewGrowthAfterDoneCell_PropagatesNewSlicesToExit encodes exactly
this retail behavior; enqueue-once broke it. The change + its test were reverted (tree clean, 27 portal
tests green). The divergence is the re-clip DRIFT, not the propagation — and underneath, the flap is
the µm input jitter (which removing the drift would only reduce, not eliminate; Build is
deterministic so only a bit-stable INPUT guarantees no flap).
4. The root — physics resting position not bit-stable
PlayerMovementController.ComputeRenderPosition (line 810): Vector3.Lerp(_prevPhysicsPos, _currPhysicsPos, alpha). Lerp(a, a, t) == a exactly, so the µm RenderPosition jitter means
_prev != _curr — the physics body's resting position blips ~µm between ticks. Retail's
kill_velocity (OBJECTINFO::kill_velocity = set_velocity(0), decomp :274467) is called by
validate_transition (:272567) on every grounded collision/slide with a valid contact plane,
keeping rest bit-stable.
acdream rest path:
calc_acceleration(PhysicsBody.cs:191) zeroes gravity only whenContact && OnWalkable && !Sledding.UpdatePhysicsInternal(PhysicsBody.cs:352) skips position integration whenvelocity <= 0.- Player flags set per tick in
PlayerMovementController(1271-1301):Contact|OnWalkableonly whenresolveResult.IsOnGround && Velocity.Z <= 0; else cleared → gravity. - acdream's
kill_velocity(PhysicsEngine.cs:837) is narrower than retail's — fires only onObjectInfo.VelocityKilled(the airborne steep-roof/wall reset), NOT on every grounded contact.
So at a clean rest the position is bit-stable; the blip is an intermittent failure (a stray
gravity tick / µm velocity residual / contact-plane not re-established). The [resolve] probe (3 dp)
shows the body stable to mm at spawn rest (94.000 repeated) — confirming the blip is sub-mm,
below that probe's precision — and shows groundedIn=True but walkable=False cp=none (no contact
plane established at rest), a lead toward the Contact/contact-plane path.
5. NEXT STEPS (the physics rest-stability fix)
- Higher-precision physics rest trace (REQUIRED before fixing). The 3-dp
[resolve]probe is too coarse. Add a 6-dp per-tick probe of the resting body:_body.Position,Velocity,Acceleration,TransientState(Contact/OnWalkable),resolveResult.IsOnGround, contact-plane valid. Launch, let the character sit at spawn (no input needed — autonomous), capture ~10 s, and find the tick where the position blips µm and which condition failed (gravity applied? velocity residual? resolve re-snap? Contact cleared?). - Port the retail-faithful rest-stability fix for the pinned cause — most likely one of:
(a) broaden
kill_velocityto match retail'svalidate_transition(zero velocity on every grounded contact with a valid contact plane, :272567); (b) ensure theContactflag / contact plane is re-established on the zero-distance rest sweep socalc_accelerationkeeps gravity off; (c) a retail-faithful "supported body at rest is frozen" (skip integration/resolve when grounded + zero velocity + no movement input). TDD: a test asserting the resting body position is bit-stable across N ticks with no input. - Visual gate at the cottage doorway threshold: hold still — the 2↔6 oscillation is gone (re-run
[pv-input]/[render-sig], floodids=constant at rest).
DO NOT RETRY: the overlap-predicate render band-aid (rejected by user — not retail); enqueue-once (refuted, §3); any render-side debounce/grace (forbidden).
6. Apparatus (committed this session) + state
- Keep (real regression value):
PortalVisibilityBuilderTests.Build_IsDeterministic_*(proves Build deterministic);tools/A8CellAuditgfxobjmode (dumps render geometry — used to refute the ModelId claim). - Diagnostic probes (env-gated, inert off; KEEP for the physics trace + flap visual gate, strip after
the fix ships):
[pv-input](ACDREAM_PROBE_PVINPUT, 6-dp Build inputs + flood count, RenderingDiagnostics + GameWindow); theoutRoot=/bshell=fields on[render-sig];launch-pvinput.ps1,launch-bshell-probe.ps1,launch-resolve.ps1. - Tree: PortalVisibilityBuilder.cs reverted to the re-enqueue (no functional change shipped). Build green; App.Tests green (portal-visibility 27/27).
- Memory to update:
project_indoor_flap_rootcause(root is the physics rest µm-jitter, not the render diagnosis or enqueue-once).