Skip to content

fix(numbering): prevent infinite appendTransaction loop in collaboration mode (SD-2060)#2224

Open
caio-pizzol wants to merge 1 commit intomainfrom
caio/sd-2060-fix-infinite-loop-and-list-loss-in-collaboration-mode
Open

fix(numbering): prevent infinite appendTransaction loop in collaboration mode (SD-2060)#2224
caio-pizzol wants to merge 1 commit intomainfrom
caio/sd-2060-fix-infinite-loop-and-list-loss-in-collaboration-mode

Conversation

@caio-pizzol
Copy link
Contributor

@caio-pizzol caio-pizzol commented Feb 28, 2026

No description provided.

…ion mode

SD-2060: When numberingPlugin sets listRendering via setNodeAttribute,
y-prosemirror syncs these changes to the Y.js XmlFragment, which then
echoes them back as a new transaction — triggering numberingPlugin again
in an infinite loop. This adds a guard using ySyncPluginKey metadata to
skip appendTransaction when the transaction originates from Y.js sync.
@linear
Copy link

linear bot commented Feb 28, 2026

@caio-pizzol caio-pizzol changed the title fix(numbering): prevent infinite appendTransaction loop in collaboration mode fix(numbering): prevent infinite appendTransaction loop in collaboration mode (SD-2060) Feb 28, 2026
@caio-pizzol caio-pizzol self-assigned this Feb 28, 2026
Copy link

@chatgpt-codex-connector chatgpt-codex-connector bot left a comment

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 12daeb162a

ℹ️ About Codex in GitHub

Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

Comment on lines +150 to 151
if (isFromPlugin || isFromYjsSync || (!forcePluginPass && !forceFullRecompute && !hasDocChanges)) {
return null;

Choose a reason for hiding this comment

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

P1 Badge Handle remote Yjs updates without skipping recomputation

The new early return on isFromYjsSync skips appendTransaction for every transaction tagged with ySyncPluginKey.isChangeOrigin, but that flag is used for all Yjs-origin updates (not only local echo-back). As a result, remote collaborator edits that change list structure never trigger a local numbering recompute, so merged concurrent edits can leave stale listRendering values until someone makes another non-Yjs edit. Please narrow this guard to skip only self-echo attribute transactions rather than all Yjs-origin document changes.

Useful? React with 👍 / 👎.

Copy link
Contributor

@tupizz tupizz left a comment

Choose a reason for hiding this comment

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

Lgtm

// sdBlockRev). Without this guard, y-prosemirror syncs our setNodeAttribute
// calls to the Y.XmlFragment, then fires a change event that dispatches a
// new transaction back to PM — creating an infinite appendTransaction loop.
const isFromYjsSync = transactions.some((tr) => {
Copy link
Contributor

Choose a reason for hiding this comment

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

Nice!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants