refactor(workspace): unify YKeyValueLww reconciliation - #2447
Draft
braden-w wants to merge 3 commits into
Draft
Conversation
Route constructor hydration and live Y.Array events through one key-scoped pipeline. A transaction-owned overlay preserves local reads, while one winner boundary owns timestamp and positional conflict policy without sacrificing the no-conflict or bulk paths. Delete every visible version on a final local delete so repeated writes cannot resurrect a key before observer confirmation.
Contributor
Preview Deployment
Previews update automatically with new commits to this PR. No cleanup needed: previews are version aliases on the existing workers. Commit 00accb7 |
Use the additions map as the affected-key owner and require every reconciliation caller to name its cleanup origin. This removes duplicate bookkeeping and the optional cleanup branch without changing winner selection or transaction origins.
Deleted as REDUNDANT WITH A CALLER: - set stores value and get retrieves it - delete removes value - has returns true for a key set earlier - get returns an updated value for an existing key - delete removes a key set earlier - set after delete restores the key - entries yields values set earlier - entries prefers the transaction-local value - multiple transactions preserve prior keys - both standalone observer batching tests - transaction-local LWW still works - rapid set/get cycles - delete-then-get and delete-then-set - remote set after local delete - final set-delete-set and delete-set-delete - delete overlay wins after set-delete Deleted overlay-cleanup implementation checks as STRUCTURE-COUPLED, and removed the remote-different-key case because its setup had already closed the delete transaction before the remote update. The resolution matrix, mixed-operation test, and accessor-specific entries tests retain the observable coverage. Add, update, and delete events now share one lifecycle test.
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.
YKeyValueLww had two conflict resolvers: constructor hydration and a roughly 180-line observer callback. They implemented the same timestamp and positional policy through different branch trees, while overlay cleanup depended on Yjs net-delta entries that do not include add-then-delete operations.
This makes reconciliation one owned transition:
selectWinneris the single policy boundary: higher timestamp wins, with final Y.Array position deciding equal timestamps. The transaction-local read state is one discriminated, transaction-owned overlay rather than independent write and delete collections. Constructor hydration and live events preserve the same stored entry objects, so unchanged values keep the reference identity required by ADR-0077.The no-conflict path stays delta-sized. Array snapshots and entry-position maps remain lazy, so unique bulk inserts avoid an O(total rows) scan while bulk conflicts still resolve from one snapshot. Single-key writes keep eager cleanup; a final delete now removes every visible version for the key, preventing repeated unconfirmed writes from resurrecting it.
Persisted
{ key, val, ts }data, the published class andObservableKvStoresurfaces, original transaction origins, cleanup transactions, observer batching, stable references, and existing event actions remain unchanged.One existing boundary remains deliberately unresolved: a public change handler that writes while conflict cleanup is queued joins the private cleanup transaction in Yjs. Defining whether that write should emit a second public batch, and under which origin, is an event-contract decision outside this internal ownership rewrite.
Need help on this PR? Tag
/codesmithwith what you need. Autofix is disabled.