test: pin the duplicated tail from concurrent same-spot splits - #3142
Merged
Conversation
Two editors seeded with the same block each perform `insert.break` at offset 4 of the same span, then exchange their emitted local patches through a lossless relay. Each editor mints its own `_key` for the new tail block (`ea-k2`, `eb-k2`), both keyed inserts apply on both sides, and the editors settle on a document with the tail duplicated: three blocks, `bar baz` twice. Nothing in the patches relates the two inserts, so no receiver can recognize them as the same intent. The pin ships as `test.fails` asserting the sane outcome (two blocks, tail once, both editors agreeing on the text projection): it passes while the defect exists and starts failing the day concurrent same-spot splits stop duplicating, at which point it flips to a plain `test`. The assertions compare `getTersePt` projections, not raw values, deliberately: the raw documents also diverge in block order (each editor sandwiches the foreign tail before its own, since both inserts anchor after the same block). That order divergence is a second defect in its own right, out of scope here. Net behavior unchanged: test-only.
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
|
Contributor
📦 Bundle Stats —
|
| Metric | Value | vs main (98d9969) |
|---|---|---|
| Internal (raw) | 781.4 KB | - |
| Internal (gzip) | 174.0 KB | - |
| Bundled (raw) | 1.40 MB | - |
| Bundled (gzip) | 343.2 KB | - |
| Import time | 97ms | -1ms, -1.4% |
@portabletext/editor/behaviors
| Metric | Value | vs main (98d9969) |
|---|---|---|
| Internal (raw) | 4.2 KB | - |
| Internal (gzip) | 1.4 KB | - |
| Bundled (raw) | 3.9 KB | - |
| Bundled (gzip) | 1.3 KB | - |
| Import time | 2ms | -0ms, -0.7% |
@portabletext/editor/plugins
| Metric | Value | vs main (98d9969) |
|---|---|---|
| Internal (raw) | 5.2 KB | - |
| Internal (gzip) | 1.8 KB | - |
| Bundled (raw) | 5.0 KB | - |
| Bundled (gzip) | 1.7 KB | - |
| Import time | 7ms | +0ms, +0.3% |
@portabletext/editor/selectors
| Metric | Value | vs main (98d9969) |
|---|---|---|
| Internal (raw) | 96.4 KB | - |
| Internal (gzip) | 22.2 KB | - |
| Bundled (raw) | 92.6 KB | - |
| Bundled (gzip) | 21.0 KB | - |
| Import time | 8ms | +0ms, +0.2% |
@portabletext/editor/traversal
| Metric | Value | vs main (98d9969) |
|---|---|---|
| Internal (raw) | 40.7 KB | - |
| Internal (gzip) | 10.6 KB | - |
| Bundled (raw) | 41.1 KB | - |
| Bundled (gzip) | 10.6 KB | - |
| Import time | 6ms | +0ms, +1.5% |
@portabletext/editor/utils
| Metric | Value | vs main (98d9969) |
|---|---|---|
| Internal (raw) | 34.1 KB | - |
| Internal (gzip) | 8.7 KB | - |
| Bundled (raw) | 32.5 KB | - |
| Bundled (gzip) | 8.5 KB | - |
| Import time | 6ms | +0ms, +0.5% |
🗺️ . · ./behaviors · ./plugins · ./selectors · ./traversal · ./utils · Artifacts
Details
- Import time regressions over 10% are flagged with
⚠️ - Sizes shown as raw / gzip 🗜️. Internal bytes = own code only. Total bytes = with all dependencies. Import time = Node.js cold-start median.
📦 Bundle Stats — @portabletext/markdown
Compared against main (98d99698)
| Metric | Value | vs main (98d9969) |
|---|---|---|
| Internal (raw) | 53.0 KB | - |
| Internal (gzip) | 11.6 KB | - |
| Bundled (raw) | 351.8 KB | - |
| Bundled (gzip) | 99.4 KB | - |
| Import time | 40ms | +1ms, +2.0% |
🗺️ View treemap · Artifacts
Details
- Import time regressions over 10% are flagged with
⚠️ - Sizes shown as raw / gzip 🗜️. Internal bytes = own code only. Total bytes = with all dependencies. Import time = Node.js cold-start median.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
When two editors split the same block at the same offset at the same time, both converge on a document with the tail duplicated. Each editor performs the split locally as a text shortening plus an insert of a new tail block, and each mints its own
_keyfor that tail. The two inserts carry nothing that relates them, so when the patches cross, both apply on both sides: three blocks, the tail twice. The nearest existing coverage (the two-client collision suite'sblock-splitscenario) splits at different offsets and asserts only convergence and validity, so this outcome was unpinned.This PR adds the pin: two independent editors in the collaborative-editing suite, seeded identically, both performing
insert.breakat the same offset, exchanging their emitted patches through a lossless relay. The test asserts the sane outcome (two blocks, the tail once, both editors agreeing) astest.fails: it passes while the defect exists and starts failing the day concurrent same-spot splits stop duplicating, at which point it flips to a plaintest.test.failsis new in this repo; the alternative was a red test parked on a branch, and a living pin in CI seemed strictly better.The run surfaced a second, separate defect, which shapes how the test asserts. The two editors do not even agree on the order of the duplicated tails: each editor placed its own tail after the original block when it split, and the other's tail then arrives as "insert after" the same original block, landing in front of it, so editor A ends with Ben's tail first and editor B with Ann's first. Because of that, the test compares the sequence of block texts (via
getTersePt) rather than raw blocks: raw comparison would fail on the ordering defect and leave this pin red for reasons unrelated to duplication. The ordering defect is tracked separately as a follow-up, and this test doubles as its repro (flip the final comparison to rawtoEqual).Note
Low Risk
Test-only pin of an existing collab bug; no production code changes.
Overview
Pins a known collab defect: two editors that
insert.breakat the same offset currently duplicate the tail after patches cross.Adds a
test.failsscenario incollaborative-editing.test.tsxthat relays local patches between two independent editors and asserts they converge on two blocks (foo/bar baz) viagetTersePt. It stays green while the duplication exists and will fail once the split is fixed, at which point it should become a regulartest. Text-only comparison avoids a separate tail-ordering bug.Reviewed by Cursor Bugbot for commit a335ea4. Bugbot is set up for automated code reviews on this repo. Configure here.