Skip to content

Sync Engine: Merge UI & Exploration #96

Description

@alecgeatches

In our current exploration of sync engines, @chriszarate and I are testing three contenders that handle conflicts in different ways:

  • yjs-server: CRDT-based, uses “conflict-free” data structures. Conflicts happen, but Yjs’s merge algorithm guarantees a deterministic answer. This is most similar to the current RTC implementation in Gutenberg. There’s no concept of a user-facing merge conflict.
  • Distributed Editing (DE-RTC) takes a merge-friendly approach. On each sync, clients send the entire post content (and base version), and the server merges the user’s changed content into a canonical copy. Any unmergeable block state (e.g. both users changed the same part of a block) is parked for review.
  • intent-log: Operational transform engine that speaks Gutenberg-specific verbs like block splitting and transformations. Users communicate individual actions (e.g. insert text “i” at position 4, split block 123e4567 at position 6) and the server orders the actions in a canonical log. Actions that conflict with earlier transforms (e.g. adding text to a deleted block) are parked for review.

Let's explore a possible editor UI for block sequestration and human-guided merges when edits from multiple users are incompatible. It’s not guaranteed that we’ll need all of these states depending on which sync engine we use.

Note that while these UI experiments are based on sync engine capabilities, they are currently only implemented as one-off visual experiments (read “staged demos”) in the experimental/merge-dialog-prototype branch. The videos below were recorded using the intent-log engine.

Visual Format for Conflicts

Rather than a new sidebar or trying to fit information into the Notes UI, we opt to show a static conflict alert within the block editor:

Image

After clicking “Review conflict”, we view the incompatible incoming changes, along with a rich editor for making manual adjustments:

Image

All text conflicts and block sequestration follow this format.

Let’s look at some examples!

Text Conflicts

While most text changes should be resolvable without human interaction, the DE-RTC and intent-log engines escalate situations where there’s no obviously correct merge path. Here’s a text conflict example where changes between users overlap:

demo1-text-conflict.mov

Note that this reuses the excellent revisions diff viewer introduced to Gutenberg this year in In-editor revisions: add visual diffing.

As mentioned above, this sort of text conflict would not apply to the yjs-server engine, as its CRDT data structure never creates a merge conflict and instead produces a deterministic (and sometimes unexpected) result.

Block Sequestration

All three engines make use of sequestration or sanitization for block changes that need elevated permissions from users. Using the same review flow as merge conflicts, here’s what sequestration can look like for a newly inserted block from a user without sufficient permissions. Below, the right user is an admin and the left user is an author without unfiltered_html permissions:

demo2-sequestration.mov

Sequestration Diffing

It might be difficult to see what’s changed in a larger block of code, e.g. a long snippet of JS analytics code. In the case where a previously approved code block is changed, we can also show a diff view of the changed code:

demo2.1-sequestration-diff.mov

Multi-block Conflicts

Complex operations like block splitting, transformations, and ordering changes mixed with content edits can cause a merge to span multiple blocks. Here’s an example of a conflict that involves the left user splitting a block and changing content at the same time as another user:

demo3-multi-block.mov

Custom Merging

Some block types like core/table have complex inner data structures that don’t map well to simple text merges. We can also provide block-aware diffing modes for these cases:

demo4-tables.mov

This was an attempt to test a robust merge UI without crowding the editor canvas or sidebar, or cramming too much information into a small space. So far the UI for these is implemented in experimental/merge-dialog-prototype, but have not been adapted for each engine. When we make an engine choice, if the result is a system that requires merge conflict handling, we may bring this work into the engine choice.

Activity

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

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions