fill the diff before draining buffered head updates - #776
Merged
Conversation
FillDiff bulk-Sets the diff from a storage snapshot. Draining first let a just-applied RemoveId be undone by that older snapshot, resurrecting a deleted tree in the diff and persisting a space hash for a tree the space no longer has; nothing corrected it afterwards. Subscribing from Init made this reachable: updates now buffer for the whole Run phase instead of being dropped, so the drain flushes a burst exactly when FillDiff runs. Filling first makes the snapshot the baseline and lets buffered updates apply on top, where they converge.
Coverage provided by https://github.com/seriousben/go-patch-cover-action |
requilence
approved these changes
Sep 1, 2026
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 subscribe to this conversation on GitHub.
Already have an account?
Sign in.
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.
Follow-up to #772.
FillDiffbulk-Sets the diff from a storage snapshot. With the drain goroutine started first, aRemoveIdthe drain had just applied got undone by that older snapshot — resurrecting a deleted tree in the diff and persisting a space hash for a tree the space no longer has. Nothing corrected it afterwards, so head sync kept advertising the tree until the next unrelated update for that id.The race predates #772, but #772 made it reachable: subscribing from
Initmeans updates buffer for the whole Run phase (~13 components) instead of being dropped, so the drain flushes a burst at exactly the momentFillDiffruns. Previously the window was microseconds and nothing was pending.Filling first makes the storage snapshot the baseline and lets buffered updates apply on top, where they converge — the last queued event for an id always matches storage. The reverse order could not converge, because the bulk
Sethad no later event to correct it.FillDiffstays inRun: it is ctx-bound I/O that can fail, andInithas no context. Only the two statements swap — no component lifecycle changes.go test -race ./...green (58 packages).🤖 Generated with Claude Code
https://claude.ai/code/session_01HXNxMzxa6rK3bAwcULTt4x