Skip to content

Assert replayed deletes classify as 'delete', not 'put', across every subscription replay variant - #3159

Merged
kriszyp merged 2 commits into
mainfrom
test/audit-replay-delete-classification
Oct 12, 2026
Merged

kriszyp merged 2 commits into
mainfrom
test/audit-replay-delete-classification

Conversation

@kriszyp

@kriszyp kriszyp commented Oct 12, 2026 •

Copy link
Copy Markdown
Member

⊙ Problem

harper#2735 reported that single-record audit replay (a subscription with startTime, history backfill) stamped every replayed entry as put, including genuine deletes, via an unconditional if (getFullRecord) auditRecord.type = 'put'. That line no longer exists on main: Skip superseded subscription updates during catch-up rewrote the path into eventFromAudit, which classifies a superseded-skip replay from the current entry's own state (put/invalidate/delete) and only rewrites patch to put when getFullRecord is set. The fix shipped with no regression test, so nothing proves it holds or would catch a reintroduction.

❓ Your call: Is a code fix still needed, or only the missing test? Only the test. Traced eventFromAudit for a create→patch→patch→delete sequence across all three replay variants (default/superseded-skip, includeSuperseded, rawEvents) — every variant already classifies the delete correctly on main. Reverted to the old unconditional type = 'put' stamp, rebuilt, and reran: the default and includeSuperseded delete assertions failed exactly as the issue describes; rawEvents stayed green, since that path has getFullRecord: false and was never reachable by the old bug. Reverted before this commit — this PR carries no production change.

💡 Solution

Extends the existing create→patch→patch→delete delete-replay test to also assert the rawEvents: true case — the one replay variant the suite checked for value but not for type. The comment above it names the three variants the test now covers.

❓ Your call: rawEvents: true, includeSuperseded: false after a delete (the one remaining untested combination, per pre-push review) is deliberately out of scope — it exercises the same eventFromAudit branch as plain rawEvents (type is preserved unmodified either way) and isn't one of the three variants #2735 names. Left as optional follow-on coverage, not added here.

✅ Verification

  • npx mocha unitTests/resources/subscriptionSuperseded.test.js — 29 passing, including the new rawEvents assertion for both the collection and single-record scopes.
  • Confirmed the test is red against the regression: reintroduced the old unconditional type = 'put' stamp in eventFromAudit, rebuilt dist/, reran — the default and includeSuperseded delete assertions failed with 'put' where 'delete' was expected; rawEvents was unaffected, matching the issue's own description of which paths the bug touched. Reverted before committing.
  • Ran the surrounding subscription-replay suite (subscriptionReplay, subscriptionSuperseded, subscribeResume, subscriptionPreviousCountScanBound, subscribeProgress, subscriptionBufferedState) for regression confidence: 113 passing, 9 pending, no failures.

Fixes #2735. Refs #2767 (the production fix this test covers). Refs #2439 — a different mechanism (the live-subscription listener recomputing event type at dispatch time, not the replay/backfill path) and intentionally not touched here.

Co-Authored-By: Claude Sonnet 5 noreply@anthropic.com
Claude-Session: https://claude.ai/code/session_01F7P8KyqX84mj6E3ToSmSYi

Release target: main — test-only regression coverage for a defect PR #2767 already fixed in production code; no v5.4 branch exists yet, so there is nothing to backport
Related PRs: #2767 independent (supplies the production fix this test covers; merged before this branch, nothing to reconcile), #2826 independent (unrelated fixture/CI-timing change)
Complexity: easy

Origin — the dispatch brief this PR was written from

Verify and lock in correct event types on single-record audit replay (#2735)

harper#2735 reports that single-record audit replay (a subscription with startTime, history backfill) stamped every replayed entry as type 'put', including genuine deletes, because of an unconditional if (getFullRecord) auditRecord.type = 'put' in resources/Table.ts. That line no longer exists on main: PR #2767 ("Skip superseded subscription updates during catch-up", commit 63f1615) rewrote the path into eventFromAudit (resources/Table.ts ~7349-7372). There, the default path classifies from the current entry (INVALIDATED ? 'invalidate' : value ? 'put' : 'delete'), and the includeSuperseded/non-mutation path only rewrites 'patch' to 'put' when getFullRecord is set. The issue looks fixed but has no regression test. Your job: (1) prove on current main, with a test, that a create → update → delete sequence on one record replays with true event types (the delete arrives as 'delete', never as a 'put' with no record) on every replay variant: default (superseded skipped), includeSuperseded, and rawEvents (getFullRecord false). Compare against the live stream of the same sequence where useful. (2) If any variant still mis-types an event, fix it in eventFromAudit and keep the fix local to that function. (3) Open a PR that adds the regression test and closes #2735.

Acceptance

A new test that would fail if a replayed delete were reported as 'put' (show it red by temporarily reverting to the unconditional overwrite), covering default, includeSuperseded, and rawEvents replay. Test passes on the PR head. PR body states whether #2767 already fixed the defect or what remained. Don't touch the live-subscription listener (#2439).

Dispatch: task harper-2735 · queued by kris-session · ran by claude/sonnet/xhigh · worker kzyp-xps-1

Review-Coverage: authored=claude; ran=gemini,codex; adjudicated=domain; declined=cursor-grok,cursor-composer,cursor-kimi,cursor-muse; rounds=2; full=1 @ 186ff48

Review-Attention: skim ~2m (decisions: delete-assertion-placement) @ 186ff48

kriszyp and others added 2 commits October 11, 2026 22:50
…n replay variant

harper#2735 reported single-record audit replay stamping every replayed entry
as 'put', including genuine deletes, via an unconditional `if (getFullRecord)
auditRecord.type = 'put'` in Table.ts. That line no longer exists on main:
PR #2767 rewrote the path into eventFromAudit, which classifies a superseded-skip
replay from the current entry's state (put/invalidate/delete) and only rewrites
'patch' to 'put' for the includeSuperseded/rawEvents paths when getFullRecord is
set.

Extends the existing create->patch->patch->delete regression test to also cover
rawEvents (getFullRecord: false), the one variant not previously asserted for
type. Confirmed red by temporarily reintroducing the unconditional `type = 'put'`
stamp (reverted before this commit) — it failed exactly the default and
includeSuperseded delete assertions, never rawEvents, matching the issue's own
description of which paths the bug touched.

No production code change: eventFromAudit already types every variant
correctly on main. This closes #2735 with the regression test it was missing.

Dispatch-Task: harper-2735
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01F7P8KyqX84mj6E3ToSmSYi
…ally asserts

Pre-push review (adjudicated nit): the comment claimed "any replay variant" but
only checks default, includeSuperseded, and rawEvents — not previousCount replay
or rawEvents+includeSuperseded:false.

Dispatch-Task: harper-2735
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01F7P8KyqX84mj6E3ToSmSYi

@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 adds a test case and explanatory comments to unitTests/resources/subscriptionSuperseded.test.js to verify that a replayed delete is never reported as a 'put' event when using raw events. Specifically, it asserts that subscribing with rawEvents: true correctly preserves the event types as ['put', 'patch', 'patch', 'delete']. There are no review comments to evaluate, and we have no additional feedback to provide.

@kriszyp
kriszyp marked this pull request as ready for review October 12, 2026 17:06
@kriszyp
kriszyp merged commit 5e2d52f into main Oct 12, 2026
51 checks passed
@kriszyp
kriszyp deleted the test/audit-replay-delete-classification branch October 12, 2026 17:06
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.

Single-record audit replay stamps every entry as put, including deletes

1 participant