Skip to content

fix(quick-edit): stop RELOAD storms from cross-block index drift - #728

Merged
mhaack merged 3 commits into
mainfrom
qe-index-drift
Sep 8, 2026
Merged

fix(quick-edit): stop RELOAD storms from cross-block index drift#728
mhaack merged 3 commits into
mainfrom
qe-index-drift

Conversation

@mhaack

@mhaack mhaack commented Sep 8, 2026

Copy link
Copy Markdown
Contributor

Summary

In the quick-edit WYSIWYG plugin, createEditor looked up a block's DOM element by an exact data-prose-index match. When a concurrent remote edit to an earlier block shifted every downstream data-prose-index (without a full SET_BODY re-index — createEditor doesn't run updateInstrumentation the way handleTransaction does), that exact lookup missed and the mini-editor fell back to posting RELOAD, i.e. an unbounded full-body resync per message. Under multi-user editing this became a storm that pegged the main thread rebuilding the instrumented HTML.

Fix: on a miss, fall back to the nearest indexed block at-or-before cursorOffset — the same drift-tolerant lookup findImageAtProseIndex already uses for images — instead of forcing a RELOAD. findTextBlock/findNearestIndexed gain an exclude param so the fallback can't steal a different block's already-open .prosemirror-editor, and the remote-cursor badge is only copied on an exact match.

Pairs with da-live PR adobe/da-live#1302 (host-side fixes for the same multi-user editing investigation).

Test plan

  • Two users editing the same doc via quick-edit; edits to earlier blocks don't trigger a RELOAD storm on the other client.
  • Opening a mini-editor after upstream content changed resolves to the correct block (no wrong-block edit, no spurious reload).
  • Image selection / drift lookups unaffected.
  • Existing quick-edit tests pass (1769 passing locally).

🤖 Generated with Claude Code

createEditor looked up its target block by an exact data-prose-index
match, but that index is a global ProseMirror position that shifts
whenever an earlier block changes size. handleTransaction already
re-shifts every other block's index for edits inside an already-open
mini-editor, but createEditor -- the path taken the first time a block
is touched by a remote edit -- never did, so the first remote edit to
any not-yet-opened block left every later block's cached index stale.
Eventually a SET_EDITOR_STATE would arrive with a cursorOffset matching
nothing, and the portal gave up and asked the host to RELOAD (full body
resend) -- unbounded, so a sustained editing burst from one collaborator
could retrigger this indefinitely and peg the main thread.

Fall back to findTextBlock's existing nearest-indexed-block lookup
instead of giving up, the same drift-tolerant match
findImageAtProseIndex already relies on for images. Added an exclude
param so the fallback can't resolve to (and destructively replace) a
different block's already-open .prosemirror-editor, and only copy the
remote-cursor badge across on an exact match.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
@aem-code-sync

aem-code-sync Bot commented Sep 8, 2026

Copy link
Copy Markdown

Hello, I'm the AEM Code Sync Bot and I will run some actions to deploy your branch.
In case there are problems, just click the checkbox below to rerun the respective action.

  • Re-sync branch
Commits

anfibiacreativa
anfibiacreativa previously approved these changes Sep 8, 2026

@anfibiacreativa anfibiacreativa left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Approving to unblock but please follow-up

Comment thread nx/public/plugins/quick-edit/src/prose.js Outdated
Comment thread nx/public/plugins/quick-edit/src/dom-index.js
claude and others added 2 commits September 8, 2026 13:27
Normalize cursorOffset to Number in createEditor so the exact-match badge gate
(a strict ===) can't silently fail if it ever arrives as a string. Add unit
tests for findTextBlock covering the exact match, the nearest-block fallback,
and the exclude case that keeps a drifted offset from resolving to an
already-open .prosemirror-editor.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@mhaack
mhaack merged commit ba3088c into main Sep 8, 2026
3 checks passed
@mhaack
mhaack deleted the qe-index-drift branch September 8, 2026 13:36
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.

4 participants