Skip to content

Stop re-logging a replicated delete that is re-delivered onto its own tombstone (#2761 → v5.2) - #2815

Merged
kriszyp merged 2 commits into
v5.2from
cherry-pick/v5.2/pr-2761
Sep 25, 2026
Merged

kriszyp merged 2 commits into
v5.2from
cherry-pick/v5.2/pr-2761

Conversation

@kriszyp

@kriszyp kriszyp commented Sep 25, 2026 •

Copy link
Copy Markdown
Member

Backport of #2761 to v5.2: a replicated delete that is re-delivered onto the tombstone it already left is no longer applied and logged again (#1162).

When a delete is delivered again with the same version and origin, the key already holds the tombstone it left. _writeDelete used to skip only a strictly older write, so a tie re-applied and appended a fresh audit entry on every delivery. In a mesh each copy is new log tail that every peer forwards and re-logs in turn. Now such a delete returns without writing. It still stages the removal, so later writes in the transaction see the key as removed.

For the human reviewer

  1. Requirement: port Stop re-logging a replicated delete that is re-delivered onto its own tombstone #2761 closely. v5.2 has the in-transaction staged-write chain (priorStagedWrite, stagedEntry, priorWrite), so this keeps main's removalBefore walk:

    • it uses the nearest earlier write in the transaction that staged state, otherwise the stored entry;
    • it passes over writes marked skipped;
    • it never treats an invalidation stub as a removal.

    v5.2 has neither isAuditEntryWrite nor a transaction-log key separate from the version. So the identity check is isSameRemoval: no record, the same version as this transaction, and the same origin id.

  2. A retried commit repeats its first round's decision. On an ERR_BUSY recommit the kept write batch shows this write's own round-one tombstone as the existing entry, and conflict recovery depends on writing the key again. The Stop re-logging a replicated delete that is re-delivered onto its own tombstone (#2761 → v5.1) #2813 review flagged this for v5.1, and the same fix is applied here.

  3. A local delete's origin compares as 0, which is the id this node's own name is pinned to. The node-id map is not read on every delete.

  4. Test note. main's replicatedDeleteRedelivery.test.js is ported unchanged. Two of its cases pass a version option that this line doesn't read ("reuses the tombstone version under a new log key", "shares its version with the live record"), so on v5.2 they never produce a version tie.

Changes

Verification

  • The ported test passes 16 of 16 here. On unmodified v5.2, 6 fail.
  • npm run test:unit:resources: 1807 passing.

Complexity: medium

🤖 Generated with Claude Code

Review-Coverage: authored=claude; ran=codex,gemini; adjudicated=domain; blocked=cursor-composer(auth); declined=cursor-grok,cursor-kimi,cursor-muse; rounds=1; full=1 @ 7123cf9

Human-Review-Need: 3 (decisions: dedup-by-tombstone-identity, carry-first-round-decision-on-retry, receiver-side-idempotency-vs-relay-fix) @ 74ad415

kriszyp and others added 2 commits September 25, 2026 10:57
… tombstone (#2761 → v5.2)

A replicated delete whose key already holds the tombstone it left (same origin, same version) re-applied
and appended a fresh audit entry on every delivery; in a mesh each copy is new log tail that every peer
forwards and re-logs in turn. The delete now returns without writing, checking the nearest staged write in
the transaction (or the stored entry) as main does. This line has no isAuditEntryWrite or separate log
key, so identity is compared as version and origin. A retry round repeats its first round's decision.

(ported from commit df188d9)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…the node-id map

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@kriszyp kriszyp added this to the v5.2 milestone Sep 25, 2026

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request prevents replicated deletes that are re-delivered onto the state they already produced from being re-logged. It introduces a check in resources/Table.ts to detect redelivered deletes, marking them as skipped and returning early to avoid appending redundant audit entries. Additionally, a comprehensive test suite is added in unitTests/resources/replicatedDeleteRedelivery.test.js to verify various scenarios of redelivered deletes. There are no review comments, so we have no feedback to provide.

@kriszyp
kriszyp marked this pull request as ready for review September 25, 2026 17:28
@kriszyp
kriszyp merged commit 17241c9 into v5.2 Sep 25, 2026
38 of 47 checks passed
@kriszyp
kriszyp deleted the cherry-pick/v5.2/pr-2761 branch September 25, 2026 17:29
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant