feat: Verify SDKs read all three persistent-store tombstone shapes - #438
Open
jsonbailey wants to merge 1 commit into
Open
feat: Verify SDKs read all three persistent-store tombstone shapes#438jsonbailey wants to merge 1 commit into
jsonbailey wants to merge 1 commit into
Conversation
kinyoklion
approved these changes
Aug 21, 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 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.
SDK-2959
What
Adds contract tests that plant tombstone records directly in a persistent store and check that the SDK reading them behaves correctly, for each of the three tombstone shapes our SDKs write.
A tombstone is the record an SDK writes to mark an item deleted, so that version-based conflict resolution can reject a stale out-of-order update. The store already addresses the record by key (Redis hash field, Consul key, DynamoDB sort key), so the
keyinside the JSON body is redundant. Three incompatible shapes are in circulation:{"version":N,"deleted":true}{"key":"<real-key>","version":N,"deleted":true}"key":"$deleted"Two confirmed bugs motivated this: Python failed its entire all-flags read on the keyless shape (SDK-2941 / FROPS-511), and Rust parses the Go/Relay shape as a live flag, resurrecting deleted flags. These tests prove no SDK depends on the inner key, which is the prerequisite for eventually dropping it.
Tests
New file
sdktests/server_side_persistence_tombstones.go, registered with one line fromServerSidePersistentTests.Runinside the existingdaemon modesub-tree (no data source,CacheModeOff). No new capability: it runs automatically for every store an SDK declares (persistent-data-store-redis/-consul/-dynamodb).tombstones/flags/<shape>— plants a valid flag plus a tombstone in onefeatureswrite, then asserts:$flagsState(catches a reader that resurrects a tombstone as a live flag);FLAG_NOT_FOUND, matching what the neighbouring daemon-mode tests assert.tombstones/segments/<shape>— plants a tombstone in thesegmentsnamespace plus a flag whose rule matches that segment key, then asserts the valid flag is still readable and the segment-matching flag serves its no-match variation. The$deletedfull-object segment includes the evaluation context in itsincludedlist, so an SDK that reads it as a live segment would servematchedinstead.All assertions are behavioral, so they read identically across Redis, Consul, and DynamoDB. Every planted shape carries a parseable
version, which DynamoDB'sWriteMaprequires.Out of scope
No changes to
basicDeletedFlagValidationMatcher, no v3 port (the file is self-contained so the port is a copy plus one line), no capability changes, no CHANGELOG/version edits.Verification
make lint→0 issues.make build,go vet ./..., andmake testall pass. The tests themselves need a live SDK test service plus Redis/Consul/DynamoDB, so they were not executed end to end here.To run against an SDK, start Redis / Consul / DynamoDB-local and the SDK's test service, then:
./sdk-test-harness -url http://localhost:8000 \ -enable-persistence-tests \ -run 'persistent data store/./daemon mode/tombstones'The full test path is
persistent data store/<store>/daemon mode/tombstones/{flags,segments}/<shape>. Drop the-runfilter to exercise the whole persistence suite.Note
Overview
Adds daemon-mode contract tests that plant deleted-item tombstones in Redis/Consul/DynamoDB and assert SDKs treat them as deleted, regardless of which of the three JSON shapes other SDKs write.
For flags, each shape is stored next to a live flag. The suite checks that the live flag still evaluates, the tombstoned key is absent from all-flags (value and
$flagsState), and a direct eval returns the default withFLAG_NOT_FOUND. For segments, a tombstone sits in the segments collection while a segment-match flag must serve the no-match variation (the$deletedfull-object shape includes the context so a false resurrection would match).Tests run under existing
persistent data store/*/daemon modewith cache off and no new capability.Reviewed by Cursor Bugbot for commit c95ea45. Bugbot is set up for automated code reviews on this repo. Configure here.