Editor undo/redo storm duplicates pasted image #280

Closed
opened 2026-09-28 01:55:43 +00:00 by kayg · 3 comments
Owner

The required adversarial editor probe found a content duplication in the production browser editor.

Evidence from seed 25608414 in tests/adversarial/editor.mjs:

  • After hostile paste and IME: 1 image, 11 paragraphs, and 4 list items.
  • After the undo storm: 1 image, 11 paragraphs, and two blocks with anchor ^duplicate-id.
  • After history replay: 3 images and 13 paragraphs.
  • Probe result: FINDING editor browser editor paste, Unicode, and history storm seed=25608414: undo/redo duplicated the pasted image.

Please reproduce and fix the editor history corruption with a regression test. This was found during the #236 merged-build adversarial round; it is outside the capsule change.

The required adversarial editor probe found a content duplication in the production browser editor. Evidence from seed `25608414` in `tests/adversarial/editor.mjs`: - After hostile paste and IME: 1 image, 11 paragraphs, and 4 list items. - After the undo storm: 1 image, 11 paragraphs, and two blocks with anchor `^duplicate-id`. - After history replay: 3 images and 13 paragraphs. - Probe result: `FINDING editor browser editor paste, Unicode, and history storm seed=25608414: undo/redo duplicated the pasted image`. Please reproduce and fix the editor history corruption with a regression test. This was found during the #236 merged-build adversarial round; it is outside the capsule change.
Author
Owner

Additional evidence from the rebuilt merged-tree adversarial run at HEAD d7926f80, seed 25608414: the failure appears after one undo/redo pair, before the 500-step history storm. In tests/adversarial/editor.mjs the unchanged assertion near line 483 compares editor.textContent; expected Anchor headingparentchildsibling..., actual Anchor heading ^q02y8bparentchildsibling.... The round trip inserts a block anchor into inline heading text and changes the text separator. This is text corruption, not a load-only failure. The probe did not change its expectation.

Additional evidence from the rebuilt merged-tree adversarial run at HEAD `d7926f80`, seed `25608414`: the failure appears after one undo/redo pair, before the 500-step history storm. In `tests/adversarial/editor.mjs` the unchanged assertion near line 483 compares `editor.textContent`; expected `Anchor headingparentchildsibling...`, actual `Anchor heading ^q02y8bparentchildsibling...`. The round trip inserts a block anchor into inline heading text and changes the text separator. This is text corruption, not a load-only failure. The probe did not change its expectation.
Author
Owner

Follow-up from the #278 adversarial round, seed 25608414: before the 500-step history storm, the probe already found that one Ctrl+Z/Ctrl+Shift+Z round trip after paste and IME changed adjacent-block textContent from Anchor headingparent... to Anchor heading parent.... The assertion stops the probe before its save check. The same run later timed out at its 7-minute cap after search and task probes; this editor finding remains covered by #280.

Follow-up from the #278 adversarial round, seed `25608414`: before the 500-step history storm, the probe already found that one Ctrl+Z/Ctrl+Shift+Z round trip after paste and IME changed adjacent-block `textContent` from `Anchor headingparent...` to `Anchor heading parent...`. The assertion stops the probe before its save check. The same run later timed out at its 7-minute cap after search and task probes; this editor finding remains covered by #280.
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.
kayg closed this issue 2026-09-29 03:37:58 +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#280
No description provided.