DragAutoScroller.run() consumes an AsyncStream of CADisplayLink
targetTimestamps from NSView.displayLink(target:selector:) on the
lane's existing anchor view (which was already the right NSView — no
new plumbing). The stream is the lifetime: cancellation ends the
iteration, termination invalidates the link, the link releases its
target. DragAutoScrollClock keeps the retired loop's two non-trivial
rules — first tick scrolls nothing, no tick integrates past 50ms (a
paused link resumes with the whole gap as its delta) — and the math is
frame-rate independent by test: one second at the edge moves 800.0
points at 120Hz and at 60Hz alike. Run-loop mode .common is
load-bearing: a drag runs AppKit's event-tracking mode.
Drag-perf card 2e08fd31.
Claude-Session: https://claude.ai/code/session_01CqjXB7ASoWtbyoGod68k97
The pathfinder's drag-reorder model, ported and generalized (DRAG-REORDER.md
travels with it, rewritten for lanes, the interior masonry, multi-drag,
cross-board sessions, the re-grounding trio, and the committed-overlay hold):
- DropSlotMath — resting-layout zones from analytic lane arithmetic and the
pure masonry placement (MasonryLayout now lays out through the same
MasonryPlacement the drag reads, so geometry cannot drift), span-capped
triggers sized to the dragged run's future footprint, hysteresis holds with
the fresh-entry fallback, boundary ties, own-slot no-ops; nil means hold.
- DragAutoScrollMath — the activation bands and velocity ramp, pure.
- The drop commits, one performWrite bracket each: moveCards/copyCards within
a board (insertion ranks touch only the dragged cards; renumber fallback);
receiveCards/receiveLanes/receiveRestoredCards on the destination store for
cross-board copy and ⌘-move with the import-boundary remint, lane copies
stripping tombstoned cards while moves carry them; restoreByDrag is now
positional, writing order only when the drop names a new one.
Gestures, sessions, previews, and delegates are the second half.
773 unit tests (87 new since the keyboard grammar).
Claude-Session: https://claude.ai/code/session_01SR4XGjmBE16ZUYWpfFHXwY