Fix delete-resurrection: atomic tombstone check on sync apply#133
Merged
Conversation
The Obie widget/intent opens a blank Obie draft in the inline editor; tapping the background with nothing typed persisted an empty pinned Obie. `saveInlineEdit`'s blank-discard test carried `&& !t.isObie`, which forced `isBlank` false for any Obie so it always saved. Drop that term so an Obie is discarded like any other never-saved blank Take — matching the locked- capture path (`saveLockedCapture`), which already discarded a blank Obie. An existing Obie whose text is cleared is still kept via `storedHadContent`. Device-confirmed on both the home-screen widget and the lock-screen control. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…h the write The pull loop's resurrection guard reads a tombstone snapshot taken at pull-start, so a user delete landing MID-PULL was invisible to it — the .takeRemote branch then re-upserted the Take and cleared its fresh tombstone (the re-opened delete-resurrection bug, 2026-07-20). TakeStore gains applyRemote(_:) — apply-unless-a-live-tombstone-supersedes, deletion wins ties, remote edits strictly after the deletion still land. EncryptedTakeStore runs the check and the write inside one queue.sync so a concurrent main-thread delete cannot interleave; InMemoryTakeStore mirrors the contract. SyncEngine's .takeRemote branch now routes through it. The 2026-07-20 log-only instrumentation (SyncEngine pull-window breadcrumbs + DailiesViewModel resurrection probes, both uncommitted) is superseded by the fix and not carried forward. Tests: store-level contract triplet (runs against BOTH stores via TakeStoreContractTests inheritance), a SyncEngine regression test driving a mid-pull delete through a wrapper store (verified to FAIL on the old upsert path), and mirrored coreverify checks. Co-Authored-By: Claude Fable 5 <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
TakeStore.applyRemote(_:)applies a remote Take unless a live tombstone supersedes it — checked atomically with the write inside the store's serial queue, so a concurrent delete cannot interleave. Deletion wins ties; a remote edit strictly after the deletion still resurrects (edit-wins preserved).Tests
applyRemoteruns against BOTH stores (InMemory + EncryptedTakeStore via the contract-suite subclass).upsertpath and pass with the fix.🤖 Generated with Claude Code