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>
This commit is contained in:
parent
d6aa526dd3
commit
6c3a96b26e
14 changed files with 8231 additions and 1 deletions
30
find_burst.py
Normal file
30
find_burst.py
Normal file
|
|
@ -0,0 +1,30 @@
|
|||
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
|
||||
Loading…
Add table
Add a link
Reference in a new issue