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>
30 lines
1.2 KiB
Python
30 lines
1.2 KiB
Python
import sys, re
|
|
path = sys.argv[1]
|
|
pat = re.compile(r'flood=(\d+) eye=\(([^)]+)\) player=\(([^)]+)\) rawPlayer=\(([^)]+)\) yaw=([-\d.]+)')
|
|
rows = []
|
|
with open(path, encoding='utf-8', errors='ignore') as fh:
|
|
for l in fh:
|
|
m = pat.search(l)
|
|
if m:
|
|
rows.append((int(m.group(1)),
|
|
tuple(float(x) for x in m.group(2).split(',')),
|
|
float(m.group(5))))
|
|
print("total pv-input rows:", len(rows))
|
|
# find first window of 25 frames containing >=4 flood changes (an oscillation burst)
|
|
def changes(seg): return sum(1 for i in range(1, len(seg)) if seg[i][0] != seg[i-1][0])
|
|
W = 25
|
|
start = None
|
|
for i in range(len(rows)-W):
|
|
if changes(rows[i:i+W]) >= 4:
|
|
start = i; break
|
|
if start is None:
|
|
print("no oscillation burst found"); sys.exit()
|
|
print(f"burst at row {start}; dumping {W+8} frames (flood, eyeX,eyeY,eyeZ, dEyeX_mm,dEyeY_mm, yaw):")
|
|
prev = None
|
|
for r in rows[start:start+W+8]:
|
|
fl, e, yaw = r
|
|
dx = (e[0]-prev[0])*1000 if prev else 0.0
|
|
dy = (e[1]-prev[1])*1000 if prev else 0.0
|
|
mark = " <" if (prev and fl != prevfl) else ""
|
|
print(f" flood={fl} eye=({e[0]:.6f},{e[1]:.6f},{e[2]:.6f}) dX={dx:+7.3f}mm dY={dy:+7.3f}mm yaw={yaw:.6f}{mark}")
|
|
prev = e; prevfl = fl
|