Fix production panic regressions#943
Merged
zxch3n merged 16 commits intoloro-dev:mainfrom Apr 21, 2026
Merged
Conversation
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: a28c207df2
ℹ️ About Codex in GitHub
Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".
…c-hardening # Conflicts: # crates/loro-internal/src/handler.rs
Three production blobs in loro-debug reliably panic inside doc.import on loro-crdt@1.10.6: - DagCausalIter assertion at dag/iter.rs: when a peer has multiple node segments in the target span and the later segment's deps fall outside the span, both segments reach the initial stack with zero in-degree and LIFO pops the higher counter first. Fix: in DagCausalIter::new, after out_degrees and succ are built, synthesize per-peer ordering edges so the lower counter must drain before the higher one is released. - OnceCell::set(..).unwrap() double-set at oplog/loro_dag.rs:917 during ensure_vv_for on a diamond dep (loro-dev#929): a shared ancestor gets pushed onto the iterative-DFS stack by multiple paths and the second pop tries to initialize an already-filled cell. Fix: skip nodes whose vv is already Some at the top of the loop and swallow the Err from the final set as a defensive measure. - list_state Index-out-of-range panic for the mads-bootstrap fixture: the ListDiffCalculator cold-starts its RichtextTracker via new_with_unknown() and never learns about the snapshot's real list content. During replay the tracker's per-change checkouts temporarily retreat some snapshot ops, so a new op's fugue anchor lands inside the unknown prefix. CrdtRope::get_diff() then emits Retain(N) where N is larger than ListState.len(). Fix: change ContainerState::apply_diff (and DocState::apply_diff, init_with_states_and_version) to return LoroResult<()>; ListState::apply_diff pre-validates the delta against current length and returns LoroError::internal(..) on mismatch so doc.import surfaces the error instead of panicking. Root cause in the tracker cold-start path still needs follow-up. Regression tests for all three live in crates/loro/tests/march_2026_panics.rs with the captured production blobs in fixtures_march_2026/. Additional targeted unit tests in dag/iter.rs and oplog/loro_dag.rs cover the smallest synthetic DAG shapes that triggered each bug. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
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
IdToCursorfragment-tail updates and zero-width update handlingimport_batch()regression that exercises the same split-tracking path seen in productionPoisonErrorpanicsMutexusers follow the same recovery ruleVerification
cargo test -p loro-internal stale_iterator_state_repairs_missing_same_peer_continuation -- --nocapturecargo test -p loro-internal larger_node_only_advances_consumed_slice -- --nocapturecargo test -p loro-internal repeated_tail_splits_keep_id_to_cursor_consistent -- --nocapturecargo test -p loro-internal zero_width_small_update_keeps_insert_set_non_empty -- --nocapturecargo test -p loro-internal large_update_can_replace_the_tail_range -- --nocapturecargo test -p loro-internal list_import_batch_stays_consistent_after_repeated_tail_splits -- --nocapturecargo test -p loro-internal poison -- --nocapturecargo check -p loro-internalNotes
ImVersionVectorexport panic still was not reproducible in this checkout; no speculative fix was included for that path/Users/zxch3n/Code/loro-ffion branchcodex/unpoison-locksand is not part of this PR