fix: crash-proof concurrent value sync on top of #2974#2975
Draft
snorrees wants to merge 3 commits into
Draft
Conversation
Guard updateBlock keyed unsets against the live engine tree and widen the updateValue try/catch so a stale-key removal degrades to a safe re-sync instead of an unhandled rejection that freezes the sync actor. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…f paths arrayifyPath returns null instead of throwing on unexpected diff-patch paths (e.g. array slices from clearing multiple marks); convertPatches drops unconvertible ops and flags the batch incomplete; applySync then falls back to an authoritative full value update / resync. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Credits #2974 for the engine routing fix and documents our residual (updateValue try/catch widening + arrayifyPath/slice resilience).
🦋 Changeset detectedLatest commit: faf811c The changes in this PR will be included in the next version bump. This PR includes changesets to release 14 packages
Not sure what this means? Click here to learn what changesets are. Click here if you're a maintainer who wants to add another changeset to this PR |
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
Contributor
📦 Bundle Stats —
|
| Metric | Value | vs fix-sidecar-array-remote-patches (57f64bf) |
|---|---|---|
| Internal (raw) | 803.5 KB | +1.2 KB, +0.1% |
| Internal (gzip) | 153.9 KB | +194 B, +0.1% |
| Bundled (raw) | 1.41 MB | +1.2 KB, +0.1% |
| Bundled (gzip) | 318.2 KB | +210 B, +0.1% |
| Import time | 71ms | +11ms, +17.6% |
@portabletext/editor/behaviors
| Metric | Value | vs fix-sidecar-array-remote-patches (57f64bf) |
|---|---|---|
| Internal (raw) | 467 B | - |
| Internal (gzip) | 207 B | - |
| Bundled (raw) | 424 B | - |
| Bundled (gzip) | 171 B | - |
| Import time | 1ms | +0ms, +19.4% |
@portabletext/editor/plugins
| Metric | Value | vs fix-sidecar-array-remote-patches (57f64bf) |
|---|---|---|
| Internal (raw) | 2.7 KB | - |
| Internal (gzip) | 894 B | - |
| Bundled (raw) | 2.5 KB | - |
| Bundled (gzip) | 827 B | - |
| Import time | 5ms | +1ms, +17.7% |
@portabletext/editor/selectors
| Metric | Value | vs fix-sidecar-array-remote-patches (57f64bf) |
|---|---|---|
| Internal (raw) | 81.2 KB | - |
| Internal (gzip) | 14.9 KB | - |
| Bundled (raw) | 76.9 KB | - |
| Bundled (gzip) | 13.8 KB | - |
| Import time | 5ms | +0ms, +2.7% |
@portabletext/editor/traversal
| Metric | Value | vs fix-sidecar-array-remote-patches (57f64bf) |
|---|---|---|
| Internal (raw) | 28.1 KB | - |
| Internal (gzip) | 5.6 KB | - |
| Bundled (raw) | 28.1 KB | - |
| Bundled (gzip) | 5.5 KB | - |
| Import time | 4ms | +0ms, +7.8% |
@portabletext/editor/utils
| Metric | Value | vs fix-sidecar-array-remote-patches (57f64bf) |
|---|---|---|
| Internal (raw) | 29.7 KB | - |
| Internal (gzip) | 6.2 KB | - |
| Bundled (raw) | 27.4 KB | - |
| Bundled (gzip) | 5.9 KB | - |
| Import time | 4ms | +0ms, +2.9% |
🗺️ . · ./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 fix-sidecar-array-remote-patches (57f64bf8)
| Metric | Value | vs fix-sidecar-array-remote-patches (57f64bf) |
|---|---|---|
| Internal (raw) | 53.8 KB | - |
| Internal (gzip) | 9.8 KB | - |
| Bundled (raw) | 348.9 KB | - |
| Bundled (gzip) | 96.3 KB | - |
| Import time | 26ms | +0ms, +1.8% |
🗺️ 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.
Summary
This is the combined crx snapshot publish platform hotfix: Ryan Bonial's engine
routing fix (#2974) with our residual client-side crash-proofing stacked on top.
The PR is opened with base =
fix-sidecar-array-remote-patches(the branchbehind #2974), so the diff shown here is only our residual — two
fixcommitsplus a changeset.
✅ Released under the
crxdist-tagThe combined fix (this PR + #2974) is published to npm under the
crxdist-tag. This does not touch
latest— it's a snapshot hotfix for affectedusers to pin to today:
@portabletext/editor7.10.8-crx.0@portabletext/plugin-sdk-value7.0.35-crx.0Install:
Verified end-to-end against real Content Lake with the published packages: two
tabs editing the same field concurrently (typing + toggling bold/link) → no crash,
no document corruption, tabs converge. (See the SAFETY matrix in the repro repo:
crash-and-corrupt → recoverable silent-loss.)
Root cause — credit to #2974
#2974 (Ryan Bonial,
fix-sidecar-array-remote-patches) is the actual root-cause fix. Remote patchesproduced by diffing tools address elements of sidecar arrays
(
span.marks[0],span.marks[-1],block.markDefs[_key==...]). The enginepreviously routed those through structural child insertion/removal, which:
Cannot apply an "unset" (node removal) operation ... because the node was not found, killing the consumer's sync; andchildrenarray onto spans on insert, corrupting thedocument once pushed back to the datastore.
#2974 makes the engine detect these non-structural paths and apply them as plain
data patches on the root block. That is the fix; everything below is defense in
depth layered on top of it.
Our residual (this PR's diff)
@portabletext/editor(sync-machine.ts): keyedupdateBlockunsets areguarded against the live engine tree, and the
updateValuetry/catch is widenedso a stale-key removal degrades to a safe re-sync instead of surfacing an
unhandled rejection that freezes the sync actor. Some of the per-
updateBlockunset guards now overlap with fix: apply remote patches addressing marks and markDefs elements as data patches #2974 and are intentionally kept as belt-and-braces.
@portabletext/plugin-sdk-value(plugin.sdk-value.tsx):arrayifyPathreturns
nullinstead of throwing on diff-patch paths it cannot convert (e.g.array slices produced when clearing multiple
marks);convertPatchesdrops theunconvertible ops and flags the batch incomplete;
applySyncthen falls back toan authoritative full value update / resync.
Scope / what this does NOT fix
racing on the same block can still overwrite each other's changes. That remains
to be addressed separately.
Status
latest.crxdist-tag (see above) — the interimhotfix affected users can pin to now.
sanity-labs/editor-crx-fix#1.unit 10 passed; plugin browser (chromium) 12 passed.
pnpm buildall packages green.🤖 Generated with Claude Code