Make local delete races recoverable - #239
Merged
Merged
Conversation
XIAZY
force-pushed
the
deniz/ci-reliability-fixes
branch
from
August 4, 2026 01:11
229e7d0 to
e229f4b
Compare
XIAZY
force-pushed
the
deniz/ci-reliability-fixes
branch
from
August 4, 2026 04:13
e229f4b to
e963156
Compare
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
tracked root entry by its existing document ID after the move/replacement
correlation window expires.
tombstone outbox update and an exact root/document local-delete intent in one
SQLite transaction, retain the tracked identity through send/projection, and
clear the intent atomically with the successful root projection.
associated with the deleted document under that document ID. Recovery uses
both the persisted materialized path and a different current tracked path
after a post-commit move/rekey.
periodic scanning. Regular files and symlinks resolving to regular files
remain readable document content; directories, dangling symlinks, FIFOs,
sockets, and other non-regular occupants are skipped without blocking or
being moved as recovered bytes.
teardown diagnostics already carried by this stacked PR.
Root cause
A local
rmand the temporary gap in an unlink-and-create replacement have thesame observable prefix. Generation tracking, debounce, and a final path read
can reject stale candidates, but no filesystem read is atomic with the later
root-CRDT tombstone commit. A real stable local removal must still delete the
document, so making all local absence non-destructive is incorrect; conversely,
committing immediately after the last read can tombstone a replacement that
arrived in the final gap.
The durable intent closes the recoverability side of that boundary:
CREATE,WRITE, move, or present-path observations cancel them;observation errors retain them for retry.
confirmed absence tombstones the root entry by the already tracked ID.
failures requeue the root document, and projection/archive failures retain
the intent.
in-memory tracked lookup, then also visits a different live tracked path if
a post-commit move rekeyed it.
document ID, including identical-byte replacements. Absent or non-regular
occupants are left untouched. Only then is identity untracked.
transaction, preventing both lost recovery and permanently armed intents.
Explicit remote/UI tombstones keep the existing clean-delete/dirty-archive
behavior. This change does not pretend the local observation and remote commit
are atomic; it makes bytes that arrive after the final cutoff recoverable.
Validation
Exact replacement head:
229e7d0a01f58c4d277d68ba48ecb8be2e19a2ea(tree
cc438a437f50a3936d62e54b9921115361b78d14). All prior head seals arerevoked.
-racego test ./daemon/internal/syncer -count=1go test -race ./daemon/internal/syncer -count=1go vet ./daemon/internal/syncergo test ./... -count=1go test -tags=regression -count=1 -timeout 40m ./test/regression— GREEN in501.571s with complete compose cleanup
git diff --checkThe focused matrix covers candidate cancellation, observation retry,
pre-commit directory replacement, same-byte and changed-byte post-commit
replacement, persisted/current-path recovery after move/rekey, directory and
dangling-symlink occupants after commit, send retry, archive retry, actual
root-first restart, successful-clear restart, SQLite atomicity, scanner
symlink parity, and a Linux FIFO that must not block or error.
Causal mutations are RED:
Hosted exact-head CI run
30671251374and an independent execution/sourcereview are required before this draft can be resealed.