acdream/docs/research/2026-06-08-flap-physics-diagnosis-REFUTED-its-render-membership.md
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

8.9 KiB
Raw Blame History

Handoff/Findings — the "physics rest µm-jitter" flap diagnosis is REFUTED; the flap is a RENDER membership instability at the grazing doorway portal — 2026-06-08 (PM)

Supersedes docs/research/2026-06-08-flap-rootcause-physics-rest-handoff.md (the AM handoff). That handoff asked to be treated as a suspect statement and verified — this session verified it with primary evidence and it does not hold. The flap is not physics and not camera drift. It is the portal-flood membership flickering non-monotonically at the grazing doorway portal as the camera eye sweeps (i.e. while you turn the camera at the doorway). This is the SPEC's §2.2 diagnosis (2026-06-08-portal-flood-membership-stability-design.md), NOT its refuted §4 enqueue-once fix.


1. What was claimed (AM handoff) vs what the evidence shows

AM claim: the flap's varying input is a physics resting-position µm jitter_body.Position blips ~1 ULP between ticks at rest → RenderPosition (Lerp of physics) jitters → eye jitters → flood flips. Fix = physics rest-stability (broaden kill_velocity, hold contact plane).

Refuted by three independent pieces of primary evidence:

A. The physics body is bit-stable at standstill — it does NOT blip

door-recheck-capture.jsonl (515 MB, 238,342 ResolveWithTransition records, captured standing at the doorway, cells 0xA9B40170/0171/0174/0175/0031):

  • 216,300 true-standstill records (zero velocity, currentPos==targetPos).
  • 0 resolve re-snaps (result.position != input never happens at standstill).
  • 0 cross-tick currentPos drift (the body position is carried forward byte-identically).
  • The grounded-but-cp=none contradictory state DOES occur (3.5% of frames) but produces no position blip.

Confirmed independently with 4 new deterministic tests (all GREEN — they PROVE rest is bit-stable):

  • PlayerMovementControllerTests.Update_AtRestNoInput_RenderPositionBitStableAcrossManyFrames (flat terrain)
  • PlayerMovementControllerTests.Update_WalkThenStop_SettlesToBitStableRest (flat terrain, post-motion)
  • CellarUpTrajectoryReplayTests.IndoorCellarFloor_AtRestZeroOffset_BodyPositionBitStable (indoor cell, resolver loop)
  • CellarUpTrajectoryReplayTests.IndoorCell_FullController_AtRestNoInput_RenderPositionBitStable (indoor cell, full controller loop)

B. On the actual flap frames, the PLAYER position is byte-identical

pvinput.log window 77487758 (a clean flood 6↔2 flap), player RenderPosition for 11 consecutive frames: (155.632858, 13.527222, 94.000000)byte-identical. The physics output the camera reads does not move at all during the flap. (The 1-ULP player blip the AM handoff cited is at the outdoor flood=1 records — a red herring, not the indoor flap.)

C. The EYE moves while the player is still — and the camera DOES settle when idle

Same window: the eye orbits smoothly ~1 mm/frame (X ↓, Y ↑, Z constant) — a slow camera rotation around the stationary player. And:

  • Of 888 flood flips in the capture, only 1 had a byte-identical eye (and that one is the outdoor→indoor root switch). Every other flip had a moved eye → the flood is deterministic in the eye; it changes only when the eye moves (matches Build_IsDeterministic_*).
  • Longest indoor byte-identical-eye runs: 203 / 181 / 178 frames (~3.4 s) — within each, the flood is a single constant value (no flicker). 61% of indoor frames have a byte-stable eye.
  • ⇒ The camera settles at rest (no boom drift, no spring oscillation). When the eye is still, the flood is stable. The flap fires only while the eye is moving.

2. The actual mechanism

When the camera eye sweeps through the grazing doorway portal (you turn the camera at the threshold), the deep cell cluster {0172,0173,0174,0175} flickers in/out — flood 6,6,6,2,2,6,6,6,2,6,2 — i.e. non-monotonic membership across a monotonic eye sweep. A correct visibility flood would transition the deep cluster in/out once as the grazing portal closes; instead its clip flips empty↔non-empty as the eye crosses and re-crosses the knife-edge. This is the SPEC's §2.2 diagnosis (the grazing portal's clip / re-clip drift makes clippedRegion.Count flip 0↔N, dropping the deep cluster on empty-clip frames).

It is NOT physics (A, B). It is NOT camera drift/oscillation (C: eye byte-stable ~3.4 s when idle). It is a render-side portal-flood membership instability at grazing angles, surfaced by camera rotation.

3. Status of prior fixes / diagnoses

  • AM physics-rest fix — would not have fixed the flap (physics rest is already bit-stable). Do not pursue.
  • SPEC §2.2 diagnosis (grazing-portal membership instability) — CONFIRMED by this evidence.
  • SPEC §4 enqueue-once fix — already refuted in the AM handoff (retail propagates late slices via AddToCell, decomp :433494; broke Build_ViewGrowthAfterDoneCell_PropagatesNewSlicesToExit). So the correct fix is a render-side membership stabilization that is monotonic under a sweeping eye without breaking late-slice propagation — design TBD (brainstorm).

4. Apparatus (this session)

  • 4 GREEN rest-stability tests (above) — keep as regression guards + evidence that physics rest is bit-stable.
  • Analysis scripts (ad-hoc, /tmp): door-recheck standstill survey; pvinput flood-flip vs eye/player delta buckets; indoor byte-stable-eye-run scan. Re-derivable from pvinput.log + door-recheck-capture.jsonl.
  • Existing probes [pv-input] (ACDREAM_PROBE_PVINPUT) and [render-sig] remain the live gate.

5. Next step (proposed)

Brainstorm + design a render-side fix that makes the deep-cluster membership monotonic/stable as the eye sweeps the grazing portal (candidates: more robust grazing-portal clip, a retail-faithful single-process traversal that doesn't re-clip-drift, or matching retail's exact GetClip/polyClipFinish epsilon). Then TDD a builder test that sweeps the eye across the grazing angle and asserts monotonic membership, and visual-gate by turning the camera at the cottage doorway.

6. LIVE-CONFIRMED (2026-06-08 PM, targeted doorway capture, user-driven)

A fresh instrumented capture (launch-flap-capture.ps1; [pv-input] enhanced with rawPlayer=raw physics body pos + yaw; cells 0170-0175 dumped to tests/.../Fixtures/flap-doorway/; 84K frames) confirms the diagnosis across every state and decomposes the flap into THREE render sub-issues. In every case the player render-pos AND raw physics-pos are byte-identical (0 µm) — physics is conclusively exonerated; the flap is 100% camera-eye-driven.

State (user-driven) player moves eye moves flood
Idle, hands fully off no (0 µm) no (0 µm) stable (no flap)
Turn / walk no (0 µm) yes (mm, yaw) oscillates
Camera smoothing-glide after a turn (yaw byte-constant, eye glides monotonically, decelerating) no yes (mm) oscillates 8↔3 ← this is the "flickers while idle" the user perceived

Key burst (row 11167): yaw byte-constant, eye X glides monotonically 155.109→155.435 (18→5 mm/frame, decelerating), flood 8→3→8…3→8. Monotonic eye ⇒ non-monotonic membership ⇒ render instability (not camera hunting).

Three sub-issues (all eye-driven, physics out):

  • A — Membership oscillation: flood non-monotonic as the eye sweeps within a stable root. outside-looking-in 8↔3; outdoor-root 17↔33 (21 flips/2500 frames); indoor-root 2↔6.
  • B — Root toggle (the big one): at the threshold, outRoot flips outdoor↔indoor as the eye crosses the door plane → wholesale visible-set swap ≈18-33 cells ↔ 2 cells (4 toggles in 2500 frames). This is the "two-branch" outdoor-node-vs-indoor-cell root switch the unification was meant to remove — still present.
  • C — Indoor-root under-inclusion: eye just inside ⇒ outRoot=n flood = 2, stable for 2438 frames → outdoors + other rooms missing (the indoor flood does not reach back out the exit portal / to adjacent cells). C is B's partner: the swap to indoor loses the scene → "textures missing."

Fix scope: core render pipeline (root resolution + flood + grazing-clip), NOT physics, NOT camera. Spec §2.2 (membership instability) is right for A; B+C are the threshold root-resolution/flood issues. Spec §4 enqueue-once stays refuted. Design needs brainstorming (saga has reverted speculative render fixes — see feedback_render_one_gate, feedback_verify_render_seal_before_layering).

Apparatus added: launch-flap-capture.ps1, analyze_flap_live.py, find_burst.py, fixtures tests/AcDream.Core.Tests/Fixtures/flap-doorway/0xA9B4017{0..5}.json, flap-doorway-resolve.jsonl.

Memory to correct: project_indoor_flap_rootcause (root is render: A membership instability + B root-toggle + C indoor under-inclusion, all under a moving camera eye — NOT physics rest, NOT camera drift; the "two-branch split" B is still live).