Repository navigation
Conversation
Importing while detached only adds records to the history. The next checkout or checkoutToLatest found no runs "deleted by" such a delete in the sequence's deletion index and skipped it, so the deleted content stayed visible. Inserts imported while detached already fell back to a replay because #canTransitionRecords checks them. Check deletes the same way: fall back unless the sequence has recorded every element the delete removes. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Contributor
WASM Size Report
|
Member
Author
|
Closing: covered by #1126 ( Checked on |
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
A Text/List delete imported while a
loro.jsdocument was detached was lost when the document moved to a version that includes it:The same happens for
checkout(frontiers)to any version that contains the delete, and for lists. Afterwards the replica disagrees with every other peer. This was one of the "peers do not converge with a replay of the same updates" classes found by fuzzing.Rationale
Importing while detached only integrates the records into the history; the container state (including the sequence's deletion index) is updated by the next transition.
#canTransitionRecordsalready refuses the incremental transition when an insert is not materialized in the sequence, which falls back to a replay. It accepted any delete, though.#applyVersionTransitionthen looked the delete up withidRunsDeletedBy, found nothing, and skipped it. The fix makes#canTransitionRecordsrequire that the sequence has recorded every element a delete removes (idRunsDeletedBycovers the op's full length). Otherwise it falls back like the insert case. Deletes integrated normally keep the incremental path; the extra check is O(log n + runs) per delete op in a transition, the same lookup the transition itself does.Map, Tree, and MovableList transitions read per-subject histories that are indexed on integration even while detached, so they were not affected.
Validation
loro-js/tests/runtime.test.ts: text and list, viacheckoutToLatest()and viacheckout(oplogFrontiers). All four fail onmain, and the expected values equalloro-crdt(WASM build of thismain) and a fresh import.pnpm --dir loro-js format:check,lint,typecheck,test(251 passed),build.bench:complexity(1k–8k), 7 alternating rounds vsmain, loadavg 12–13: 284 items, none both >1.5× and >0.3 ms slower. Total 922 ms onmain, 938 ms here. (An earlier run at loadavg 40 with a concurrent fuzz job flagged unrelated map-import items that do not reach this code; they did not reproduce.)🤖 Generated with Claude Code