Skip to content

RTC: fix #77532, rich text offset mismatch with diff API#77658

Merged
dmsnell merged 6 commits into
WordPress:trunkfrom
danluu:try/offset-space-bug-pr
May 5, 2026
Merged

RTC: fix #77532, rich text offset mismatch with diff API#77658
dmsnell merged 6 commits into
WordPress:trunkfrom
danluu:try/offset-space-bug-pr

Conversation

@danluu

@danluu danluu commented Apr 24, 2026

Copy link
Copy Markdown
Contributor

What?

Closes #77532.
See also #77862.

This is AI generated code from codex (5.4 and 5.5). Codex's description of what the fix does is:

The fix carries the editor selection as a scoped rich-text cursor hint, including the selected block clientId, attribute key, and rich-text text offset. When merging a rich-text block attribute, it only applies that cursor hint to the matching block/attribute and converts the editor text offset into the HTML string index expected by diffWithCursor().

It also verifies the cursor-guided delta on a temporary Y.Text before applying it to shared content. If the cursor hint would produce the wrong HTML, it falls back to a regular diff instead of risking content corruption.

[end AI generated text]

Note that the isDeltaVerificationMatch function isn't necessary for this fix. It's part of a proposed defense-in-depth solution that aims to prevent analogous bugs. Also note that the e2e repro with Playwright is not checked in here. My reasoning for this is:

  1. The fuzzer is turning up a decent number of bugs (of which this is the first to be filed). If we add a bunch of a tiny tests that spin up a browser for each one, that will end up slowing down running tests quite a bit.
  2. Many of these bugs are quite finicky and small changes in the code that don't fix the bug can make the repro in a top-level test stop failing. Typing a few characters is not a reliable method to hit any particular bug even if it happens to expose a bug at a moment in time.

My proposal here is to defer putting in the playwright tests for these issues until we have quite a few and then have an integration or end-to-end test that does things that would cover many bugs.

Testing Instructions

The repro instructions from #77532 also work here, except that the top-level playwright repro is not checked in for reasons noted above. That test can be run via the branch linked to in #77532, if desired.

Unit Repros

Run the lower-level RTC write-path repros:

npm run test:unit -- packages/core-data/src/utils/test/rtc-rich-text-offset-space.test.js

Run the higher-level useEntityBlockEditor().onInput() repro:

npm run test:unit -- packages/core-data/src/test/rtc-rich-text-offset-space.test.js

Use of AI Tools

As noted above, the original issue and this PR are AI generated. @dmsnell and @alecgeatches looked at the original issue and think that it's a real bug (thanks again for taking a look, all, and @alecgeatches also looked at the proposed fix.

@danluu danluu requested a review from nerrad as a code owner April 24, 2026 18:19
@github-actions github-actions Bot added the [Package] Core data /packages/core-data label Apr 24, 2026
@github-actions

github-actions Bot commented Apr 24, 2026

Copy link
Copy Markdown

The following accounts have interacted with this PR and/or linked issues. I will continue to update these lists as activity occurs. You can also manually ask me to refresh this list by adding the props-bot label.

If you're merging code through a pull request on GitHub, copy and paste the following into the bottom of the merge commit message.

Co-authored-by: danluu <danluu@git.wordpress.org>
Co-authored-by: dmsnell <dmsnell@git.wordpress.org>
Co-authored-by: peterwilsoncc <peterwilsoncc@git.wordpress.org>
Co-authored-by: alecgeatches <alecgeatches@git.wordpress.org>

To understand the WordPress project's expectations around crediting contributors, please review the Contributor Attribution page in the Core Handbook.

@github-actions github-actions Bot added the First-time Contributor Pull request opened by a first-time contributor to Gutenberg repository label Apr 24, 2026
@github-actions

Copy link
Copy Markdown

👋 Thanks for your first Pull Request and for helping build the future of Gutenberg and WordPress, @danluu! In case you missed it, we'd love to have you join us in our Slack community.

If you want to learn more about WordPress development in general, check out the Core Handbook full of helpful information.

@danluu danluu changed the title Try/offset space bug pr RTC: fix #77532, rich text offset mismatch with diff API Apr 24, 2026
@alecgeatches alecgeatches added [Feature] Real-time Collaboration Phase 3 of the Gutenberg roadmap around real-time collaboration [Type] Bug An existing feature does not function as intended labels Apr 24, 2026
@danluu danluu force-pushed the try/offset-space-bug-pr branch 2 times, most recently from c4128a8 to cfcfe75 Compare April 24, 2026 18:47
@dmsnell dmsnell mentioned this pull request Apr 27, 2026

@peterwilsoncc peterwilsoncc left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Are you able to add docblocks for the items that are missing them.

@dmsnell

dmsnell commented Apr 28, 2026

Copy link
Copy Markdown
Member

@peterwilsoncc I will add the docs and handle WPCS issues.

currentVal,
newVal,
resolveRichTextCursorPosition( cursorPosition, cursorScope, newVal )
);

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.

we’ve added a cursorScope parameter to mergeYMapValues() in this patch, but transformed the existing cursorPosition for mergeRichTextUpdate().

is there a reason to avoid including the cursor scope here as well? do calls to the mergeRichTextUpdate() often not carry cursor-scope relevance?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Following up on this and one of your comments elsewhere, I tried adding types to this in 610e02e. That's pushed to this PR, although I'm not sure if that should be in this PR or in an independent PR (or if the change there really makes sense).

dmsnell added a commit that referenced this pull request Apr 30, 2026
…ckages.

The `WPBlockSelection` type is more complicated than it may seem at face value.
This change expands the docblock information on the type and links together the
currently-existing duplicates in other packages, which are duplicated to avoid
creating circular dependencies.

This is prepartory work for #77658, but stands on its own as a clarifying update.
dmsnell added a commit that referenced this pull request May 1, 2026
…ckages.

The `WPBlockSelection` type is more complicated than it may seem at face value.
This change expands the docblock information on the type and links together the
currently-existing duplicates in other packages, which are duplicated to avoid
creating circular dependencies.

This is prepartory work for #77658, but stands on its own as a clarifying update.
dmsnell added a commit that referenced this pull request May 1, 2026
…ckages.

The `WPBlockSelection` type is more complicated than it may seem at face value.
This change expands the docblock information on the type and links together the
currently-existing duplicates in other packages, which are duplicated to avoid
creating circular dependencies.

This is prepartory work for #77658, but stands on its own as a clarifying update.
@danluu danluu force-pushed the try/offset-space-bug-pr branch from 610e02e to f136c42 Compare May 1, 2026 07:23
dmsnell added a commit that referenced this pull request May 2, 2026
…ckages.

The `WPBlockSelection` type is more complicated than it may seem at face value.
This change expands the docblock information on the type and links together the
currently-existing duplicates in other packages, which are duplicated to avoid
creating circular dependencies.

This is prepartory work for #77658, but stands on its own as a clarifying update.
dmsnell added a commit that referenced this pull request May 4, 2026
…ckages.

The `WPBlockSelection` type is more complicated than it may seem at face value.
This change expands the docblock information on the type and links together the
currently-existing duplicates in other packages, which are duplicated to avoid
creating circular dependencies.

This is prepartory work for #77658, but stands on its own as a clarifying update.
dmsnell added a commit that referenced this pull request May 4, 2026
…ckages. (#77862)

The `WPBlockSelection` type is more complicated than it may seem at face value.
This change expands the docblock information on the type and links together the
currently-existing duplicates in other packages, which are duplicated to avoid
creating circular dependencies.

This is prepartory work for #77658, but stands on its own as a clarifying update.
@dmsnell dmsnell requested a review from ellatrix as a code owner May 5, 2026 03:41
@dmsnell dmsnell requested a review from alecgeatches May 5, 2026 04:14

@dmsnell dmsnell 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.

Thanks @danluu — the fuzzing was effective and efficient at finding this somewhat concerning bug, as well as proposing the initial patch.

@dmsnell dmsnell merged commit 54af1ce into WordPress:trunk May 5, 2026
41 of 46 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

[Feature] Real-time Collaboration Phase 3 of the Gutenberg roadmap around real-time collaboration First-time Contributor Pull request opened by a first-time contributor to Gutenberg repository [Package] Block editor /packages/block-editor [Package] Core data /packages/core-data [Package] Sync [Type] Bug An existing feature does not function as intended

Projects

None yet

Development

Successfully merging this pull request may close these issues.

RTC: potential data corruption on block merge write path due to rich-text text offset directly into a diff API that operates on HTML string indices

4 participants