Endpoint drags fire markDirty(wallId) on every pointermove tick. The
old behavior rebuilt the dragged wall AND every wall sharing a junction
on every tick — in a 4-corner room with doors, that's 4× the CSG
+miter pass per tick. Visible as drag lag.
New behavior: the dragged wall rebuilds every tick (so the drag tracks
the cursor with full fidelity, cutouts and all). Adjacent walls are
queued in pendingAdjacentByLevel and rebuilt on the trailing edge —
80ms after the dirty stream stops. The corners snap into their correct
miter joins ~80ms after release, which is the standard CAD-app
"rubber-band the dragged element, fix neighbors on commit" pattern.
Module-level singleton state for the queue + timestamp — WallSystem is
mounted exactly once globally, so module state is the right scope.
Expected speedup:
- t-junction drag: ~3× (was 3 walls/tick, now 1)
- 4-corner room with door per wall: ~4×
The trailing flush condition (!hasDirtyWalls && now - lastWallDirtyAtMs
>= DRAG_FLUSH_MS) means single edits (non-drag) pay an 80ms latency
before neighbors miter correctly. Acceptable for now; the real fix is
the affordance/tool port (Milestone C) which will explicitly signal
"drag in progress" so we can drop the heuristic. Until then this is a
substantial drag-perf win for zero risk.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>