Skip to content

RTC: Fix empty revision from peer autosave - #79911

Merged
alecgeatches merged 9 commits into
trunkfrom
fix/rtc-multi-user-empty-autosave
Jul 15, 2026
Merged

RTC: Fix empty revision from peer autosave#79911
alecgeatches merged 9 commits into
trunkfrom
fix/rtc-multi-user-empty-autosave

Conversation

@alecgeatches

@alecgeatches alecgeatches commented Jul 6, 2026

Copy link
Copy Markdown
Contributor

What?

Follow-up to #79591, which fixed single-user "empty" autosaves. There's another workflow from multiple users (see collaboration-peer-blank-revision.spec.ts) that can result in the same outcome:

multi-revision-reproduction.mov

(middle sped up to wait for autosaves)

The expected behavior should be to show the - edit content diff, but instead the revisions page shows an empty save.

This PR changes the autosave controller to compare an incoming autosave against the most recent revision rather than the parent post.

Why?

#79591 fixed the single-user case, but autosaves from multiple users in collaborative sessions can still result in no-op revisions. That PR guarded the first autosave for a user and delegated every subsequent autosave to core with the assumption that core already de-duplicates. However, that's a bad assumption.

Both #79591 and core's create_post_autosave() compare the incoming autosave against the parent post. But with RTC, the parent draft is intentionally never updated as part of auto-saving. Peer edits are stored as revisions, regardless of whether the user is the original post author. Peers can share the same CRDT content but that content differs from the parent post until there's a real save, so each peer's autosave "looks different from the parent". Those revisions are still identical to one another, and look "blank" as described in #79591:

Why are revisions blank?

As shown in the reproduction above, clicking on "View the autosave" for a no-op autosave shows a "blank" revision:

blank-revision

This is because the revisions page just skips showing post content when there's no changes in the diff, but shows the post title as a special case. That means the revision is essentially showing "nothing changed", but due to the UI looks as though the revision itself is lost. A real "lost" revision would show a diff of all of the content removed.

How?

In short, don't create an autosave if there's already an autosave with the same content.

The autosave controller now determines a comparison baseline instead of always using the parent post before persisting a new revision:

  • get_autosave_comparison_baseline() returns the most recent revision when it is newer than the parent, where RTC autosaves are stored. This falls back to the parent when no revision exists yet or in non-RTC.
  • is_redundant_autosave() compares the revisioned fields (title, content, excerpt) and revisioned meta (e.g. footnotes) against that baseline.

The baseline can be another peer's autosave revision, and that is intentional. Under RTC all peers converge, so the most recent revision is the best snapshot of the shared state regardless of author. A match means the content is already persisted, so there's no point in creating a second revision with exactly the same content.

Testing Instructions

First, try a reproduction in trunk:

  1. Enable RTC.
  2. In one browser, create a new draft post with a title and content.
  3. In another browser as another WordPress user, join the same draft post.
  4. Make an edit in either browser (e.g. add - edited) and DO NOT SAVE
  5. Open DevTools and wait for both browsers to create an autosave.
  6. Reload both windows and see the autosave notification.
  7. Click into the revision and note the empty content.

Repeat on this branch (fix/rtc-multi-user-empty-autosave) and the only autosave shown should be the actual diff from the unsaved content, not a subsequent empty diff:

revision-diff-fixed.mov

Automated testing

See test failure for collaboration-peer-blank-revision.spec.ts in this run, and test passing after the fix was added in this branch.

Use of AI Tools

Claude (Opus 4.8) for reproduction and drafting the fix.

@alecgeatches alecgeatches self-assigned this Jul 6, 2026
@alecgeatches alecgeatches added [Type] Bug An existing feature does not function as intended [Feature] Real-time Collaboration Phase 3 of the Gutenberg roadmap around real-time collaboration labels Jul 6, 2026
@github-actions

github-actions Bot commented Jul 6, 2026

Copy link
Copy Markdown

Size Change: 0 B

Total Size: 7.72 MB

compressed-size-action

@alecgeatches
alecgeatches marked this pull request as ready for review July 6, 2026 19:39
@github-actions

github-actions Bot commented Jul 6, 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: alecgeatches <alecgeatches@git.wordpress.org>
Co-authored-by: ingeniumed <ingeniumed@git.wordpress.org>

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

@alecgeatches alecgeatches added the No Core Sync Required Indicates that any changes do not need to be synced to WordPress Core label Jul 6, 2026
@alecgeatches
alecgeatches requested a review from maxschmeling July 6, 2026 19:49
@github-actions

github-actions Bot commented Jul 6, 2026

Copy link
Copy Markdown

Flaky tests detected in 88eb4af.
Some tests passed with failed attempts. The failures may not be related to this commit but are still reported for visibility. See the documentation for more information.

🔍 Workflow run URL: https://github.com/WordPress/gutenberg/actions/runs/28817030704
📝 Reported issues:

@alecgeatches
alecgeatches marked this pull request as draft July 6, 2026 19:56
@alecgeatches

alecgeatches commented Jul 6, 2026

Copy link
Copy Markdown
Contributor Author

Put back into draft. I'm not 100% sold on the fix video:

revision-diff-fixed.mov

It's a bit weird to say "there's newer content" and show an autosave with the same content as the current page (~:35 in the video), even if the autosave contains a diff newer than the saved post content. It's more correct than showing an empty autosave on the revisions page, but I want to think about this a bit more.

@alecgeatches
alecgeatches marked this pull request as ready for review July 6, 2026 20:26
@alecgeatches

alecgeatches commented Jul 6, 2026

Copy link
Copy Markdown
Contributor Author

Okay, put this back up for review. I think the comment above is correct, but we should still merge this PR anyway.

The code in this PR still correctly removes the server-side logic causing "blank" (exactly equal) autosaves. Separately, the autosave notice should probably be changed in RTC to use a different metric for showing itself. Even though a newer autosave might exist when collaboratively editing a document, the CRDT usually will already contain the new content too, so the terminology and display is confusing.

We should likely gate the notice under something more robust than a more recent autosave timestamp and compare content. This PR addresses the server-side fix and unnecessary autosave, let's address the header in another PR.

@alecgeatches
alecgeatches requested a review from shekharnwagh July 8, 2026 15:43

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

The code itself is good, just need to add 2 more tests and tweak a doc.

* the correct baseline; otherwise (no revisions yet, or the parent was updated
* directly) the parent post is used.
*
* @since 7.0.0

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.

Should this be 7.1.0?

return $latest_revision;
}

return $post;

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.

There's currently a test missing for the case where the parent post is newer than the revision that's found. This case exists when collaboration isn't enabled but not for when it is. Worth adding that in?

// and an empty string as equivalent so the editor's empty default for
// an unset key is not mistaken for a change.
$old_meta = get_metadata_raw( 'post', $post->ID, $meta_key, true ) ?? '';
$old_meta = get_metadata_raw( 'post', $baseline->ID, $meta_key, true ) ?? '';

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.

Currently the existing post meta test only compares the changed post meta with the parent, not with the latest revision so this code isn't being tested for that case. Would add another test for that case

@alecgeatches
alecgeatches enabled auto-merge (squash) July 15, 2026 16:28
@alecgeatches

Copy link
Copy Markdown
Contributor Author

@ingeniumed Thank you for the review! I added 2 tests, updated versions (to 7.2.0), and re-merged trunk to hopefully get the unrelated e2e test failure fixed. Will merge when tests pass!

@alecgeatches
alecgeatches merged commit f5dae78 into trunk Jul 15, 2026
44 checks passed
@alecgeatches
alecgeatches deleted the fix/rtc-multi-user-empty-autosave branch July 15, 2026 17:06
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 No Core Sync Required Indicates that any changes do not need to be synced to WordPress Core [Type] Bug An existing feature does not function as intended

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants