fix: make children filters causally complete#184
Open
marcus-pousette wants to merge 2 commits into
Open
Conversation
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.
The bug
opRefs.children(parent)is meant to return the operations needed to replay that parent's direct-child view. It was not always replay-complete.The stored parent index could follow a requested parent even when a cycle/sentinel move was rejected, and it could miss committed effects such as moving a child away or restoring a deleted ancestor. The WASM adapter had a second problem: it selected only inserts and moves whose requested destination was
parent, so it omitted payload, delete, tombstone, move-away, and descendant operations that can change the direct-child result.A peer replaying that filtered set could therefore show stale or missing children even though full-log replay converged correctly.
What changes
ParentOpIndexsemantics and return the selected operations in canonical operation order.Replaying the returned closure from an empty tree now reproduces the same direct-child result as full replay. The closure can include a descendant operation when that operation is what restores a direct child. This is a convergence filter, not a confidentiality boundary; authorization still belongs in the sync/auth layer.
Fast paths and tradeoff
opRefs.childrenquery and uses no additional persistent state. It is the correct fallback today and can later be replaced with an in-memory maintained index without changing behavior.Tests
Coverage includes:
Rust, WASM runtime, TypeScript, formatting, and strict Clippy checks pass locally. CI re-runs on the published head.
Size
12 files, +905/-90 relative to #178: +325/-90 production, +574 tests/conformance, and a 6-line changeset.
Stack
Stacked after #178. Merge order: #177 → #180 → #178 → this PR.