Skip to content

fix(outline): PROG-119 land drag-drops in the same frame as the drop#95

Merged
bryankennedy merged 1 commit into
mainfrom
act/PROG-119
Jul 13, 2026
Merged

fix(outline): PROG-119 land drag-drops in the same frame as the drop#95
bryankennedy merged 1 commit into
mainfrom
act/PROG-119

Conversation

@exe-dev-github-integration

Copy link
Copy Markdown
Contributor

Summary

Fixes the PROG-119 reorder flash: after dropping a dragged outline row, it briefly snapped back to its original slot before jumping to the drop position.

Root cause. dnd-kit clears its drag transforms synchronously inside the drop event, but React Query v5's notifyManager defers all cache-subscriber notification through setTimeout(0) — so the browser painted a frame (sometimes two) with the old order and the transforms already gone before the optimistic rank write reached the components. The board never showed this because PROG-59 keeps a local columns mirror updated synchronously in onDragEnd; the Outline renders straight from the snapshot cache, so all three of its drag surfaces (action rows, arc sections, focus sections) flashed.

Fix. One line in store.ts: notifyManager.setScheduler((cb) => cb()) — synchronous notification, React Query v4's behavior. React 18 auto-batching still coalesces a multi-write drop (tied-group container renumber) into one commit, and every cache write lives in store.ts's event/async mutation helpers, so nothing writes during render. Every optimistic mutation now paints in the same frame as its event, which is what the instant-UI requirement (SPEC §2.1) wants globally. Alternative (board-style local mirrors × 3 surfaces) rejected in docs/decisions/PROG-119.md.

Verification

Headless Playwright driver that drags a top-level outline row and samples the DOM every rAF frame after mouseup:

  • before: new order first visible at frame 2 (the flash)
  • after: new order at frame 0, old order never reappears, no >2px positional jump, order persists across reload

bun run check, bun test src (170 pass), and bun run format:check all green.

Dropping a dragged outline row flashed: the row snapped back to its old
slot for a frame or two, then jumped to the drop position. dnd-kit clears
its drag transforms synchronously in the drop event, but React Query v5
defers cache-subscriber notification through setTimeout(0), so the
optimistic rank write painted one-two frames late. The board dodged this
with a local columns mirror (PROG-59); the Outline renders straight from
the snapshot cache, so all three of its drag surfaces (rows, arc
sections, focus sections) showed the flash.

Set a pass-through notifyManager scheduler so cache writes notify
synchronously (React Query v4 behavior). React 18 auto-batching keeps a
multi-write drop as one commit, and no code path writes the cache during
render. Verified with a headless rAF-sampling driver: new order visible
at frame 0 after mouseup (was frame 2), no old-order reappearance, no
positional jump, order persists across reload. Decision record in
docs/decisions/PROG-119.md.
@bryankennedy bryankennedy merged commit 721e30e into main Jul 13, 2026
2 checks passed
@bryankennedy bryankennedy deleted the act/PROG-119 branch July 13, 2026 18:37
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant