Regression: undo/redo storm persists duplicate Note block IDs #225

Closed
opened 2026-09-27 10:34:06 +00:00 by kayg · 18 comments
Owner

Reproduction

On job/menu-icons at cdc09b1d (which includes the dev merge for #186), the seeded production adversarial run seed=25608414 opened a Note with duplicate, malformed and missing block IDs. Copy link repaired the selected duplicate before the history storm. After hostile paste/IME and 500 Ctrl+Z followed by 500 Ctrl+Shift+Z, the browser editor showed nine ^duplicate-id anchors.

The probe then waited 30 seconds for the expected block anchors to persist. It timed out. The saved Note body contained dozens of repeated ^duplicate-id lines, and did not contain all expected repaired anchors (0ra56t, dz62ke, 9m6jn5). This violates the #186 invariant that block IDs stay unique and undo restores exact content. Concurrent same-block edits, same-epoch offline reconciliation, delete/edit and external Note writes passed in the same run.

Full run log: target/tmp/menu-icons-adversarial-latest.log in the menu-icons worktree. Seed and exact body are in the FINDING editor browser editor paste, Unicode, and history storm entry. The reproduction uses the merged production web build and a real local server.

Please add a regression assertion for duplicate IDs across the 500-step undo/redo sequence, then fix the save/reconciliation path so undo and redo preserve unique block IDs and all expected anchors.

## Reproduction On `job/menu-icons` at `cdc09b1d` (which includes the `dev` merge for #186), the seeded production adversarial run `seed=25608414` opened a Note with duplicate, malformed and missing block IDs. Copy link repaired the selected duplicate before the history storm. After hostile paste/IME and 500 Ctrl+Z followed by 500 Ctrl+Shift+Z, the browser editor showed nine `^duplicate-id` anchors. The probe then waited 30 seconds for the expected block anchors to persist. It timed out. The saved Note body contained dozens of repeated `^duplicate-id` lines, and did not contain all expected repaired anchors (`0ra56t`, `dz62ke`, `9m6jn5`). This violates the #186 invariant that block IDs stay unique and undo restores exact content. Concurrent same-block edits, same-epoch offline reconciliation, delete/edit and external Note writes passed in the same run. Full run log: `target/tmp/menu-icons-adversarial-latest.log` in the menu-icons worktree. Seed and exact body are in the `FINDING editor browser editor paste, Unicode, and history storm` entry. The reproduction uses the merged production web build and a real local server. Please add a regression assertion for duplicate IDs across the 500-step undo/redo sequence, then fix the save/reconciliation path so undo and redo preserve unique block IDs and all expected anchors.
Author
Owner

This worktree's one-round adversarial run after the dev merge reproduced the undo/redo finding with seed=25608414 on the production web build and real local server. After the browser history storm, the editor rendered repeated ^duplicate-id anchors and the probe timed out waiting for saved block anchors nqmjeh, gpckky, and v4ehz2. The saved body lacked the expected repaired state. Concurrent writes, offline reconciliation, delete/edit, and external body-write probes passed in this run. Full log: target/tmp/phone-chrome-adversarial-retry.log in the phone-chrome worktree.

This worktree's one-round adversarial run after the `dev` merge reproduced the undo/redo finding with `seed=25608414` on the production web build and real local server. After the browser history storm, the editor rendered repeated `^duplicate-id` anchors and the probe timed out waiting for saved block anchors `nqmjeh`, `gpckky`, and `v4ehz2`. The saved body lacked the expected repaired state. Concurrent writes, offline reconciliation, delete/edit, and external body-write probes passed in this run. Full log: `target/tmp/phone-chrome-adversarial-retry.log` in the phone-chrome worktree.
Author
Owner

Post-merge adversarial round from CSP issue #118 on merged commit c2ff7b40, seed 25608414, reproduced this history-storm regression.

editor.mjs logged FINDING editor browser editor paste, Unicode, and history storm: after 500 undo and 500 redo keypresses, the UI showed many ^duplicate-id anchors. The expected anchors (av4lo4, i834ue, ofspaj) did not reach the saved Note within 30 seconds. The captured saved body had 160 paragraphs, dozens of repeated ^duplicate-id lines, and omitted those expected anchors. Other later collaboration probes completed, so the server stayed alive.

This is data corruption, not a latency-only result. The #118 run log is target/tmp/adversarial-postmerge.log in the CSP worktree. It needs a fix and regression test before merging the affected editor/collaboration changes.

Post-merge adversarial round from CSP issue #118 on merged commit `c2ff7b40`, seed 25608414, reproduced this history-storm regression. `editor.mjs` logged `FINDING editor browser editor paste, Unicode, and history storm`: after 500 undo and 500 redo keypresses, the UI showed many `^duplicate-id` anchors. The expected anchors (`av4lo4`, `i834ue`, `ofspaj`) did not reach the saved Note within 30 seconds. The captured saved body had 160 paragraphs, dozens of repeated `^duplicate-id` lines, and omitted those expected anchors. Other later collaboration probes completed, so the server stayed alive. This is data corruption, not a latency-only result. The #118 run log is `target/tmp/adversarial-postmerge.log` in the CSP worktree. It needs a fix and regression test before merging the affected editor/collaboration changes.
Author
Owner

Post-merge editor probe at c2ff7b40 reproduced persisted Note corruption after the browser history storm. The saved body had 160 paragraphs and many repeated ^duplicate-id anchors; expected repaired anchors av4lo4, i834ue, and ofspaj were missing. The probe timed out after 30 seconds waiting for those anchors to save. This is a data-integrity blocker; no editor behavior was changed in the CSP job.

Post-merge editor probe at c2ff7b40 reproduced persisted Note corruption after the browser history storm. The saved body had 160 paragraphs and many repeated ^duplicate-id anchors; expected repaired anchors av4lo4, i834ue, and ofspaj were missing. The probe timed out after 30 seconds waiting for those anchors to save. This is a data-integrity blocker; no editor behavior was changed in the CSP job.
Author
Owner

Post-merge replay on job/fonts at ffcc5d2a117ebafd4d32df9968230b3803f25a32, seed 25608414: after hostile paste/IME and 500 Ctrl+Z plus 500 Ctrl+Shift+Z, the expected repaired anchors were saved in 11 ms and the browser/history probe passed. The saved body kept unique IDs. The pre-merge timeout did not reproduce in this replay, so this font job made no editor fix.

Post-merge replay on `job/fonts` at `ffcc5d2a117ebafd4d32df9968230b3803f25a32`, seed `25608414`: after hostile paste/IME and 500 Ctrl+Z plus 500 Ctrl+Shift+Z, the expected repaired anchors were saved in 11 ms and the browser/history probe passed. The saved body kept unique IDs. The pre-merge timeout did not reproduce in this replay, so this font job made no editor fix.
Author
Owner

Repeat evidence from the required post-merge adversarial round for #219: on job/phone-chrome at merge head 3025699104e0b57ec2275edd5fee00b5374f3d9d, seed 25608414, the editor browser paste/Unicode/history storm again timed out after 30 seconds waiting for repaired block anchors yhy3by, oboj7b and a45sw9. The post-storm editor state contained repeated ^duplicate-id anchors, and the saved body did not contain the expected repaired anchors. The subsequent concurrent-edit and offline-reconciliation probes passed. This matches the existing duplicate-ID regression tracked here; no editor files changed in #219.

Repeat evidence from the required post-merge adversarial round for #219: on `job/phone-chrome` at merge head `3025699104e0b57ec2275edd5fee00b5374f3d9d`, seed `25608414`, the editor browser paste/Unicode/history storm again timed out after 30 seconds waiting for repaired block anchors `yhy3by`, `oboj7b` and `a45sw9`. The post-storm editor state contained repeated `^duplicate-id` anchors, and the saved body did not contain the expected repaired anchors. The subsequent concurrent-edit and offline-reconciliation probes passed. This matches the existing duplicate-ID regression tracked here; no editor files changed in #219.
Author
Owner

This round reproduced the same failure on job/fonts after merging dev (ac941215). With seed 25608414, the production editor applied hostile paste/IME input and 500 undo plus 500 redo actions. It waited 30 seconds for the repaired IDs n5cb3a, bgwfi3 and xgttj8; the saved Note body still had repeated ^duplicate-id anchors and did not satisfy the expected-ID check. The concurrent-write, offline-merge and delete/edit probes passed.

The editor.mjs output reported timed out waiting for block anchors saved. This run was on the shared host, so it does not establish a quiet-host reproduction. The server remained alive.

This round reproduced the same failure on `job/fonts` after merging `dev` (`ac941215`). With seed `25608414`, the production editor applied hostile paste/IME input and 500 undo plus 500 redo actions. It waited 30 seconds for the repaired IDs `n5cb3a`, `bgwfi3` and `xgttj8`; the saved Note body still had repeated `^duplicate-id` anchors and did not satisfy the expected-ID check. The concurrent-write, offline-merge and delete/edit probes passed. The `editor.mjs` output reported `timed out waiting for block anchors saved`. This run was on the shared host, so it does not establish a quiet-host reproduction. The server remained alive.
Author
Owner

Editor-integrity job final report — branch job/editor-integrity, head b824878e (pushed).

  • #332 and #364: fixed the Yrs conflict-shadow merge that discarded the surviving edit when another client deleted that block. Deterministic tests cover both update orders and a same-connection redo update. The real-server delete/edit probe passed.
  • #346: the concurrent delete/edit loss is fixed by the same change. The history-text finding is not closed by this work; see #314 and #363 below.
  • #225 and #262: added structure-level editor history coverage, but did not rerun the 500-step production browser ID storm after the final branch state. Persistence of unique IDs in that exact storm remains unconfirmed.
  • #280 and #281: the focused history test keeps one pasted image over 50 undo/redo pairs. The 500-step production browser image storm was not rerun after the final branch state, so this exact case remains unconfirmed.
  • #314 and #363: focused Yjs/ProseMirror structure tests pass. The fixed-seed production browser history probe remained timing-sensitive: clean runs reported a stale or mismatched mounted ProseMirror view after Ctrl+Z, while one instrumented run passed 50 paste and IME round trips. I removed the unverified key scheduling change and kept the failure evidence for follow-up.

Verification:

  • bun run test src/collaborationUndo.test.ts: 4 passed.
  • cargo fmt --check: exit 0, no output.
  • cargo clippy --all-targets -- -D warnings: stopped at the four-hour job limit (exit 130) while compiling workspace dependencies.
  • cargo test, bun run check, and bun run test for the full web workspace were not run before the time limit.

Decision: conflict-shadow merge filters each incoming Yrs update against that update's own delete set. This keeps a later text edit that follows a root deletion while avoiding replay of a duplicate root insertion from the same redo update. The issue-specific tests pass; the full gates and listed browser storms remain for follow-up. Issues remain open.

Editor-integrity job final report — branch `job/editor-integrity`, head `b824878e` (pushed). - #332 and #364: fixed the Yrs conflict-shadow merge that discarded the surviving edit when another client deleted that block. Deterministic tests cover both update orders and a same-connection redo update. The real-server delete/edit probe passed. - #346: the concurrent delete/edit loss is fixed by the same change. The history-text finding is not closed by this work; see #314 and #363 below. - #225 and #262: added structure-level editor history coverage, but did not rerun the 500-step production browser ID storm after the final branch state. Persistence of unique IDs in that exact storm remains unconfirmed. - #280 and #281: the focused history test keeps one pasted image over 50 undo/redo pairs. The 500-step production browser image storm was not rerun after the final branch state, so this exact case remains unconfirmed. - #314 and #363: focused Yjs/ProseMirror structure tests pass. The fixed-seed production browser history probe remained timing-sensitive: clean runs reported a stale or mismatched mounted ProseMirror view after Ctrl+Z, while one instrumented run passed 50 paste and IME round trips. I removed the unverified key scheduling change and kept the failure evidence for follow-up. Verification: - `bun run test src/collaborationUndo.test.ts`: 4 passed. - `cargo fmt --check`: exit 0, no output. - `cargo clippy --all-targets -- -D warnings`: stopped at the four-hour job limit (exit 130) while compiling workspace dependencies. - `cargo test`, `bun run check`, and `bun run test` for the full web workspace were not run before the time limit. Decision: conflict-shadow merge filters each incoming Yrs update against that update's own delete set. This keeps a later text edit that follows a root deletion while avoiding replay of a duplicate root insertion from the same redo update. The issue-specific tests pass; the full gates and listed browser storms remain for follow-up. Issues remain open.
Author
Owner

Starting editor-integrity work on branch job/editor-integrity at b824878eb5, based on dev 413ccaa7b7. I am merging the current dev tip first, then will reproduce the history failure in the component harness and trace the shared editor primitive.

Starting editor-integrity work on branch job/editor-integrity at b824878eb52aecf794293e2b8242fd896b792932, based on dev 413ccaa7b7f7f509ec74176a20569db049ae6171. I am merging the current dev tip first, then will reproduce the history failure in the component harness and trace the shared editor primitive.
Author
Owner

Baseline evidence after merging dev: EDITOR_ONLY=1 EDITOR_AREA=browser EDITOR_SEED=25608414 bash tests/adversarial/run.sh failed on the real local server. The 500 Ctrl+Z storm showed two ^duplicate-id anchors; after 500 Ctrl+Y, the mounted document had two pasted images, a repeated ^rktt91, and joined block text. The browser structural equality assertion failed. A fixed-seed mounted Notes component test with local Yjs history alone passed, which points to the server conflict-shadow response during the first root-block undo. I am adding a regression at that boundary before changing production code.

Baseline evidence after merging dev: `EDITOR_ONLY=1 EDITOR_AREA=browser EDITOR_SEED=25608414 bash tests/adversarial/run.sh` failed on the real local server. The 500 Ctrl+Z storm showed two `^duplicate-id` anchors; after 500 Ctrl+Y, the mounted document had two pasted images, a repeated `^rktt91`, and joined block text. The browser structural equality assertion failed. A fixed-seed mounted Notes component test with local Yjs history alone passed, which points to the server conflict-shadow response during the first root-block undo. I am adding a regression at that boundary before changing production code.
Author
Owner

The focused regression failed as expected in session::conflict_shadow_tests::local_undo_that_opens_conflict_shadow_does_not_replay_its_paste: merge_conflict_shadow returned a server update after the local undo, and that update restored the pre-undo paste into the live Yrs document. The shadow cloned the current live document but compared it with an older durable Markdown baseline. This makes the first local history delete look like an external edit. I will make the shadow's comparison point match the exact document snapshot it clones, while keeping the stale-edit merge path covered by the existing session tests.

The focused regression failed as expected in `session::conflict_shadow_tests::local_undo_that_opens_conflict_shadow_does_not_replay_its_paste`: `merge_conflict_shadow` returned a server update after the local undo, and that update restored the pre-undo paste into the live Yrs document. The shadow cloned the current live document but compared it with an older durable Markdown baseline. This makes the first local history delete look like an external edit. I will make the shadow's comparison point match the exact document snapshot it clones, while keeping the stale-edit merge path covered by the existing session tests.
Author
Owner

The fixed-seed component harness passes 500 undo and 500 redo shortcuts. It checks the mounted ProseMirror view against the editor state and Yjs projection after every step; they stay aligned.

The server regression reproduced the issue: opening a conflict shadow during local undo compared the pre-undo live document with the older durable Markdown baseline, so the shadow replayed the same connection's unsaved paste to that client. Commit 8d4afc46 marks root deletions from this connection's announced Yrs client IDs as local history and advances the shadow comparison point while retaining its mirror for later stale edits. Ordinary and mixed-client deletions keep the durable-baseline behavior.

Checks so far:

  • cargo test -p calternal-collab local_undo_that_opens_conflict_shadow_does_not_replay_its_paste: passed (1 test).
  • bun run test -- src/lib/notes/collaborationUndo.svelte.test.ts: passed (1 test; 70.67s including transforms).

I am running the seeded real-server browser storms next.

The fixed-seed component harness passes 500 undo and 500 redo shortcuts. It checks the mounted ProseMirror view against the editor state and Yjs projection after every step; they stay aligned. The server regression reproduced the issue: opening a conflict shadow during local undo compared the pre-undo live document with the older durable Markdown baseline, so the shadow replayed the same connection's unsaved paste to that client. Commit 8d4afc46 marks root deletions from this connection's announced Yrs client IDs as local history and advances the shadow comparison point while retaining its mirror for later stale edits. Ordinary and mixed-client deletions keep the durable-baseline behavior. Checks so far: - `cargo test -p calternal-collab local_undo_that_opens_conflict_shadow_does_not_replay_its_paste`: passed (1 test). - `bun run test -- src/lib/notes/collaborationUndo.svelte.test.ts`: passed (1 test; 70.67s including transforms). I am running the seeded real-server browser storms next.
Author
Owner

The single seeded real-server adversarial run still finds one #225 regression in the broad browser case. Seed 25608414 fails editorContentSnapshot equality after 500 Ctrl+Z plus 500 Ctrl+Y following copy-link repairs and drag attempts. The isolated mixed-paste/IME history case passes its 500-step storm, as do the other editor areas in that run.

The current classifier requires every root ID in one Yrs delete update to belong to the connection's Awareness client ID. The broad sequence can undo a block move that deletes both a new local root and an older room root. I am adding a deterministic mixed-ID regression and will adjust the classifier for that history update shape.

The single seeded real-server adversarial run still finds one #225 regression in the broad browser case. Seed `25608414` fails `editorContentSnapshot` equality after 500 Ctrl+Z plus 500 Ctrl+Y following copy-link repairs and drag attempts. The isolated mixed-paste/IME history case passes its 500-step storm, as do the other editor areas in that run. The current classifier requires every root ID in one Yrs delete update to belong to the connection's Awareness client ID. The broad sequence can undo a block move that deletes both a new local root and an older room root. I am adding a deterministic mixed-ID regression and will adjust the classifier for that history update shape.
Author
Owner

The mixed-ID regression passed with commit 360f232f: its Yrs update deletes one room-authored root and one root authored by the connected editor. The classifier now recognizes the update as local history when any deleted root ID belongs to that editor; separate nonlocal root-delete updates in the same WebSocket batch still use the durable-baseline path. All 6 conflict-shadow tests pass.

I am running the editor-only real-server sweep again, with both 500-step browser storms enabled and the already-built production web bundle.

The mixed-ID regression passed with commit `360f232f`: its Yrs update deletes one room-authored root and one root authored by the connected editor. The classifier now recognizes the update as local history when any deleted root ID belongs to that editor; separate nonlocal root-delete updates in the same WebSocket batch still use the durable-baseline path. All 6 conflict-shadow tests pass. I am running the editor-only real-server sweep again, with both 500-step browser storms enabled and the already-built production web bundle.
Author
Owner

Finding: the fixed-seed component run keeps the mounted ProseMirror view and Yjs projection aligned, while the real-server browser storm still diverges. The server currently infers local history only from root-block delete/insert shapes; text-only Yjs UndoManager updates have no such signal and can enter conflict-shadow replay. I am adding a one-update origin marker and a regression at the provider/server boundary.

Finding: the fixed-seed component run keeps the mounted ProseMirror view and Yjs projection aligned, while the real-server browser storm still diverges. The server currently infers local history only from root-block delete/insert shapes; text-only Yjs UndoManager updates have no such signal and can enter conflict-shadow replay. I am adding a one-update origin marker and a regression at the provider/server boundary.
Author
Owner

Committed 7d484282 (Mark UndoManager updates before conflict replay). The provider tags only updates whose Yjs origin is a Y.UndoManager; the server validates and strips the one-update marker before Yrs handling and relay, then skips that update in conflict-shadow replay. Regression evidence: bun run test -- src/lib/notes/collab.test.ts passed 8 tests; bun run test -- src/lib/notes/collaborationUndo.svelte.test.ts passed 1 seeded 500-step test; cargo test -p calternal-collab conflict_shadow_tests -- --nocapture passed 7 tests. Next I am running the real-server editor adversarial sweep with seed 25608414.

Committed `7d484282` (`Mark UndoManager updates before conflict replay`). The provider tags only updates whose Yjs origin is a `Y.UndoManager`; the server validates and strips the one-update marker before Yrs handling and relay, then skips that update in conflict-shadow replay. Regression evidence: `bun run test -- src/lib/notes/collab.test.ts` passed 8 tests; `bun run test -- src/lib/notes/collaborationUndo.svelte.test.ts` passed 1 seeded 500-step test; `cargo test -p calternal-collab conflict_shadow_tests -- --nocapture` passed 7 tests. Next I am running the real-server editor adversarial sweep with seed 25608414.
Author
Owner

Adversarial sweep (EDITOR_SEED=25608414) outcome: both the broad browser history storm and the isolated browser history storm completed 500 Ctrl+Z plus 500 Ctrl+Y operations and returned to their pre-storm editor structure; the isolated probe passed in 37,549 ms. The single runner finding was a 15-second wait timeout while opening one of the copied heading/block links after the broad storm. Before that wait, block anchors had saved in 21 ms, the mixed paste saved in 534 ms, and IME content saved in 1,462 ms; no history structure or image duplication assertion failed. I cannot distinguish a slow route from a deep-link reveal failure from this run, so I am carrying it as a known gap. Full log: target/tmp/editor-adversarial.log.

Adversarial sweep (`EDITOR_SEED=25608414`) outcome: both the broad browser history storm and the isolated browser history storm completed 500 Ctrl+Z plus 500 Ctrl+Y operations and returned to their pre-storm editor structure; the isolated probe passed in 37,549 ms. The single runner finding was a 15-second wait timeout while opening one of the copied heading/block links after the broad storm. Before that wait, block anchors had saved in 21 ms, the mixed paste saved in 534 ms, and IME content saved in 1,462 ms; no history structure or image duplication assertion failed. I cannot distinguish a slow route from a deep-link reveal failure from this run, so I am carrying it as a known gap. Full log: `target/tmp/editor-adversarial.log`.
Author
Owner

Final report — editor integrity

Built and committed the editor history integrity fix. NoteCollabProvider now marks Yjs updates whose origin is a Y.UndoManager. The collaboration server consumes that marker, strips it before Yrs handling and relay, and excludes marked local history updates from conflict-shadow replay. Existing root-delete and block-redo inference remains as a fallback. The seeded mounted-editor test uses a Yrs-authored server fixture and checks the ProseMirror view and Yjs projection through 500 undo plus 500 redo operations.

Files: crates/calternal-collab/src/session.rs, apps/web/src/lib/notes/collab.ts, apps/web/src/lib/notes/collab.test.ts, apps/web/src/lib/notes/collaborationUndo.svelte.test.ts.

Head: 7d4842822d2d706a0758d0681fb1332fcec76b81 (Mark UndoManager updates before conflict replay). Pushed to origin/job/editor-integrity; no merge into dev.

Final gates (verbatim result lines)

  • cargo fmt --all -- --check: no output; exit status 0.
  • OPENSSL_NO_VENDOR=1 CARGO_PROFILE_DEV_DEBUG=line-tables-only CARGO_INCREMENTAL=0 CARGO_BUILD_JOBS=4 TMPDIR=$PWD/target/tmp cargo clippy --all-targets -- -D warnings:
    Finished \dev` profile [unoptimized + debuginfo] target(s) in 8m 04s`
  • cargo test -p calternal-collab:
    test result: ok. 22 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.59s
    All integration suites also passed, including the 60.24-second cross-language vector test.
  • bun run check:
    svelte-check found 0 errors and 0 warnings
  • bun run test:
    Test Files 117 passed (117)
    Tests 760 passed (760)
    Duration 108.38s (transform 54%, environment 17%, import 15%, tests 10%, setup 4%)

Adversarial run with seed 25608414: the broad and isolated browser storms each completed 500 Ctrl+Z and 500 Ctrl+Y operations and returned to their pre-storm structure. The isolated probe reported PASS editor isolated editor paste history storm seed=25608414 ms=37549. The sole finding was FINDING editor browser editor paste, Unicode, and block actions seed=25608414: waitForFunction: Timeout 15000ms exceeded. It occurred while waiting for a copied heading or block link to become visible after the broad storm. Block anchors had saved in 21 ms, mixed paste in 534 ms, and IME text in 1,462 ms. I cannot distinguish a slow route from a reveal failure in this run; this remains a known gap. The run log was under target/tmp and was removed by the requested Cargo cleanup.

Decisions not specified in the design docs

  • I assigned internal custom y-protocol message type 101 to an empty client-to-server marker immediately before one Sync Update or SyncStep2. The server consumes it and never relays it, so clients continue to receive ordinary y-sync messages. No dependency or user-facing protocol change was added.
  • The single copied-link visibility timeout is recorded as unresolved because this run did not identify which of the heading or block reveal waits timed out.

Cleanup: cargo clean removed 20,347 files (12.1 GiB); apps/web/build and apps/web/.svelte-kit/output were removed.

## Final report — editor integrity Built and committed the editor history integrity fix. `NoteCollabProvider` now marks Yjs updates whose origin is a `Y.UndoManager`. The collaboration server consumes that marker, strips it before Yrs handling and relay, and excludes marked local history updates from conflict-shadow replay. Existing root-delete and block-redo inference remains as a fallback. The seeded mounted-editor test uses a Yrs-authored server fixture and checks the ProseMirror view and Yjs projection through 500 undo plus 500 redo operations. Files: `crates/calternal-collab/src/session.rs`, `apps/web/src/lib/notes/collab.ts`, `apps/web/src/lib/notes/collab.test.ts`, `apps/web/src/lib/notes/collaborationUndo.svelte.test.ts`. Head: `7d4842822d2d706a0758d0681fb1332fcec76b81` (`Mark UndoManager updates before conflict replay`). Pushed to `origin/job/editor-integrity`; no merge into `dev`. ### Final gates (verbatim result lines) - `cargo fmt --all -- --check`: no output; exit status 0. - `OPENSSL_NO_VENDOR=1 CARGO_PROFILE_DEV_DEBUG=line-tables-only CARGO_INCREMENTAL=0 CARGO_BUILD_JOBS=4 TMPDIR=$PWD/target/tmp cargo clippy --all-targets -- -D warnings`: `Finished \`dev\` profile [unoptimized + debuginfo] target(s) in 8m 04s` - `cargo test -p calternal-collab`: `test result: ok. 22 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.59s` All integration suites also passed, including the 60.24-second cross-language vector test. - `bun run check`: `svelte-check found 0 errors and 0 warnings` - `bun run test`: `Test Files 117 passed (117)` `Tests 760 passed (760)` `Duration 108.38s (transform 54%, environment 17%, import 15%, tests 10%, setup 4%)` Adversarial run with seed `25608414`: the broad and isolated browser storms each completed 500 Ctrl+Z and 500 Ctrl+Y operations and returned to their pre-storm structure. The isolated probe reported `PASS editor isolated editor paste history storm seed=25608414 ms=37549`. The sole finding was `FINDING editor browser editor paste, Unicode, and block actions seed=25608414: waitForFunction: Timeout 15000ms exceeded.` It occurred while waiting for a copied heading or block link to become visible after the broad storm. Block anchors had saved in 21 ms, mixed paste in 534 ms, and IME text in 1,462 ms. I cannot distinguish a slow route from a reveal failure in this run; this remains a known gap. The run log was under `target/tmp` and was removed by the requested Cargo cleanup. ### Decisions not specified in the design docs - I assigned internal custom y-protocol message type `101` to an empty client-to-server marker immediately before one Sync Update or SyncStep2. The server consumes it and never relays it, so clients continue to receive ordinary y-sync messages. No dependency or user-facing protocol change was added. - The single copied-link visibility timeout is recorded as unresolved because this run did not identify which of the heading or block reveal waits timed out. Cleanup: `cargo clean` removed 20,347 files (12.1 GiB); `apps/web/build` and `apps/web/.svelte-kit/output` were removed.
Author
Owner

Correction to the final report: cargo clean removed the configured external Cargo target and did not remove the worktree's target/tmp. The adversarial log is still present at target/tmp/editor-adversarial.log; the generated .svelte-kit and build directories were removed separately.

Correction to the final report: `cargo clean` removed the configured external Cargo target and did not remove the worktree's `target/tmp`. The adversarial log is still present at `target/tmp/editor-adversarial.log`; the generated `.svelte-kit` and `build` directories were removed separately.
kayg closed this issue 2026-09-29 03:37:56 +00:00
Sign in to join this conversation.
No labels
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set

Reference
kayg/calternal#225
No description provided.