Skip to content

Add migration fence drain guards#1087

Open
bootjp wants to merge 27 commits into
design/hotspot-split-m2-store-exportfrom
design/hotspot-split-m2-fence-drain
Open

Add migration fence drain guards#1087
bootjp wants to merge 27 commits into
design/hotspot-split-m2-store-exportfrom
design/hotspot-split-m2-fence-drain

Conversation

@bootjp

@bootjp bootjp commented Jul 13, 2026

Copy link
Copy Markdown
Owner

Summary

Author: bootjp

Implements the M2-PR5 migration guards:

  • reject writes that target WriteFenced routes in the coordinator and FSM
  • reject DEL_PREFIX by route-footprint intersection, including full-range deletes
  • add a route-faithful transaction-lock drain helper that scans lock storage and filters by decoded route key
  • reject same-group SplitRange requests that overlap a live split job while allowing disjoint same-group splits

Validation

  • GOCACHE=$(pwd)/.cache GOTMPDIR=$(pwd)/.cache/tmp go test ./kv ./distribution ./adapter -run 'TestFSMRejects|TestShardedCoordinatorRejects|TestPendingTxnLocksInRoute|TestDistributionServerSplitRange_(RejectsLiveSplitJobOverlap|AllowsDisjointRouteWhileSplitJobLive|Success|UsesCoordinatorForCatalogWrites)|TestPlanMigrationBrackets|TestMigrationKnownInternalPrefixes|TestValidateMigrationRouteRange|TestSplitJobPlanner|TestVerifyComposed1|TestKvFSM' -count=1 -timeout=240s
  • GOCACHE=$(pwd)/.cache GOTMPDIR=$(pwd)/.cache/tmp go test ./kv ./distribution -count=1 -timeout=240s
  • GOCACHE=$(pwd)/.cache GOLANGCI_LINT_CACHE=$(pwd)/.golangci-cache golangci-lint run ./kv ./distribution ./adapter --timeout=5m

@coderabbitai

coderabbitai Bot commented Jul 13, 2026

Copy link
Copy Markdown

Important

Review skipped

Auto reviews are disabled on base/target branches other than the default branch.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: a5288981-fcfa-4048-bf5d-164a22435b1b

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@bootjp

bootjp commented Jul 13, 2026

Copy link
Copy Markdown
Owner Author

@codex review

@github-actions

Copy link
Copy Markdown
Contributor

TLA+ spec divergence review (auto-triggered)

This PR touches files that the TLA+ safety spec has an anchor on (per
docs/design/2026_05_28_implemented_tla_safety_spec.md §3),
so an AI review is requested below to verify the implementation has not drifted
from the model.

Anchored files changed in this PR head (eab9622):

  • distribution/engine.go
  • distribution/split_job_catalog.go
  • kv/fsm.go
  • kv/sharded_coordinator.go

What to check, by subsystem:

  • kv/hlc*.goNext() must respect the HLC-4 preconditions (i)/(ii)/(iii) from the design doc: bounded skew, logical-counter handoff on leader change (strategy (c) Observe(MaxAppliedHLC)), and the commit-time ceiling fence (fail-closed when wall_now >= physicalCeiling). Any change to the bit layout (48/16), the CAS loop, or the ceiling getter/setter is in scope.
  • kv/coordinator.go, kv/sharded_coordinator.goRunHLCLeaseRenewal, hlcRenewalInterval, hlcPhysicalWindowMs constants, and the new-term detection that calls Observe(fsm.MaxAppliedHLC()) (strategy (c)). Any change to renewal cadence, group selection, or fail-closed behaviour is in scope.
  • kv/transaction.go, kv/lock_resolver.go — OCC commit-ts assignment, lock-map encoding (key, lock_ts) -> start_ts, and the LockResolver action OCC-3 depends on. (M2 spec will land OCC-1..OCC-5; until then the spec doc §5.2 is the contract.)
  • kv/fsm.go — FSM apply of HLC lease entries (SetPhysicalCeiling), and any future MaxAppliedHLC() accessor that strategy (c) needs.
  • store/mvcc_store.go — version visibility, snapshot install, and the MVCC-1..MVCC-4 invariants (M3 scope).
  • distribution/** — route catalog versioning, SplitRange atomicity, and CatalogWatcher async fan-out (M4 scope).

If the change is correct but requires a spec update, edit tla/hlc/HLC.tla (or the corresponding M2..M5 module once landed) and the design doc in the same PR. The tla-check workflow runs the TLC model check on the same paths.


@claude review please verify TLA+ spec divergence per the checklist above.

@codex review please verify TLA+ spec divergence per the checklist above.

@chatgpt-codex-connector

Copy link
Copy Markdown

To use Codex here, create a Codex account and connect to github.

@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 introduces mechanisms to reject write operations and prefix deletions on write-fenced routes during split migrations, ensuring data consistency. It also adds a utility to scan and drain pending transaction locks within a route. The review feedback suggests two key improvements: optimizing the route intersection search in distribution/engine.go by breaking early from the sorted routes loop, and enhancing robustness in kv/migrator_lock_drain.go by checking for context cancellation within the lock scanning loop.

Important

The consumer version of Gemini Code Assist on GitHub is being sunset. Starting June 18, 2026, new organization installations will be blocked, and all code review activity will officially cease on July 17, 2026.
For more details on the timeline and next steps, please review the Help Documentation.

Comment thread distribution/engine.go
Comment thread kv/migrator_lock_drain.go Outdated
@github-actions

Copy link
Copy Markdown
Contributor

TLA+ spec divergence review (auto-triggered)

This PR touches files that the TLA+ safety spec has an anchor on (per
docs/design/2026_05_28_implemented_tla_safety_spec.md §3),
so an AI review is requested below to verify the implementation has not drifted
from the model.

Anchored files changed in this PR head (07a428e):

  • distribution/engine.go
  • distribution/split_job_catalog.go
  • kv/fsm.go
  • kv/sharded_coordinator.go

What to check, by subsystem:

  • kv/hlc*.goNext() must respect the HLC-4 preconditions (i)/(ii)/(iii) from the design doc: bounded skew, logical-counter handoff on leader change (strategy (c) Observe(MaxAppliedHLC)), and the commit-time ceiling fence (fail-closed when wall_now >= physicalCeiling). Any change to the bit layout (48/16), the CAS loop, or the ceiling getter/setter is in scope.
  • kv/coordinator.go, kv/sharded_coordinator.goRunHLCLeaseRenewal, hlcRenewalInterval, hlcPhysicalWindowMs constants, and the new-term detection that calls Observe(fsm.MaxAppliedHLC()) (strategy (c)). Any change to renewal cadence, group selection, or fail-closed behaviour is in scope.
  • kv/transaction.go, kv/lock_resolver.go — OCC commit-ts assignment, lock-map encoding (key, lock_ts) -> start_ts, and the LockResolver action OCC-3 depends on. (M2 spec will land OCC-1..OCC-5; until then the spec doc §5.2 is the contract.)
  • kv/fsm.go — FSM apply of HLC lease entries (SetPhysicalCeiling), and any future MaxAppliedHLC() accessor that strategy (c) needs.
  • store/mvcc_store.go — version visibility, snapshot install, and the MVCC-1..MVCC-4 invariants (M3 scope).
  • distribution/** — route catalog versioning, SplitRange atomicity, and CatalogWatcher async fan-out (M4 scope).

If the change is correct but requires a spec update, edit tla/hlc/HLC.tla (or the corresponding M2..M5 module once landed) and the design doc in the same PR. The tla-check workflow runs the TLC model check on the same paths.


@claude review please verify TLA+ spec divergence per the checklist above.

@codex review please verify TLA+ spec divergence per the checklist above.

@bootjp

bootjp commented Jul 13, 2026

Copy link
Copy Markdown
Owner Author

@codex review

@chatgpt-codex-connector

Copy link
Copy Markdown

To use Codex here, create a Codex account and connect to github.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 07a428ee88

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread kv/fsm.go
@github-actions

Copy link
Copy Markdown
Contributor

TLA+ spec divergence review (auto-triggered)

This PR touches files that the TLA+ safety spec has an anchor on (per
docs/design/2026_05_28_implemented_tla_safety_spec.md §3),
so an AI review is requested below to verify the implementation has not drifted
from the model.

Anchored files changed in this PR head (7c17803):

  • distribution/engine.go
  • distribution/split_job_catalog.go
  • kv/fsm.go
  • kv/sharded_coordinator.go

What to check, by subsystem:

  • kv/hlc*.goNext() must respect the HLC-4 preconditions (i)/(ii)/(iii) from the design doc: bounded skew, logical-counter handoff on leader change (strategy (c) Observe(MaxAppliedHLC)), and the commit-time ceiling fence (fail-closed when wall_now >= physicalCeiling). Any change to the bit layout (48/16), the CAS loop, or the ceiling getter/setter is in scope.
  • kv/coordinator.go, kv/sharded_coordinator.goRunHLCLeaseRenewal, hlcRenewalInterval, hlcPhysicalWindowMs constants, and the new-term detection that calls Observe(fsm.MaxAppliedHLC()) (strategy (c)). Any change to renewal cadence, group selection, or fail-closed behaviour is in scope.
  • kv/transaction.go, kv/lock_resolver.go — OCC commit-ts assignment, lock-map encoding (key, lock_ts) -> start_ts, and the LockResolver action OCC-3 depends on. (M2 spec will land OCC-1..OCC-5; until then the spec doc §5.2 is the contract.)
  • kv/fsm.go — FSM apply of HLC lease entries (SetPhysicalCeiling), and any future MaxAppliedHLC() accessor that strategy (c) needs.
  • store/mvcc_store.go — version visibility, snapshot install, and the MVCC-1..MVCC-4 invariants (M3 scope).
  • distribution/** — route catalog versioning, SplitRange atomicity, and CatalogWatcher async fan-out (M4 scope).

If the change is correct but requires a spec update, edit tla/hlc/HLC.tla (or the corresponding M2..M5 module once landed) and the design doc in the same PR. The tla-check workflow runs the TLC model check on the same paths.


@claude review please verify TLA+ spec divergence per the checklist above.

@codex review please verify TLA+ spec divergence per the checklist above.

@chatgpt-codex-connector

Copy link
Copy Markdown

To use Codex here, create a Codex account and connect to github.

@bootjp

bootjp commented Jul 13, 2026

Copy link
Copy Markdown
Owner Author

@codex review

Updated in 7c17803:

  • Treat broad route-mapped DEL_PREFIX namespaces as full-keyspace route coverage when the raw prefix cannot be normalized to a concrete route prefix.
  • Apply the same coverage in coordinator pre-dispatch checks and FSM apply checks.
  • Added regression coverage for Redis/wide-column broad prefixes and S3 bucket cleanup prefix classification.

Validation:

  • GOCACHE=$(pwd)/.cache GOTMPDIR=$(pwd)/.cache/tmp go test ./kv -run 'TestRoutePrefixRangeTreatsBroadMappedPrefixesAsFullKeyspace|TestFSMRejects.*WriteFenced|TestShardedCoordinatorRejects.*WriteFenced|TestShardedCoordinator_DelPrefix' -count=1 -timeout=180s
  • GOCACHE=$(pwd)/.cache GOTMPDIR=$(pwd)/.cache/tmp go test ./kv -count=1 -timeout=240s
  • GOCACHE=$(pwd)/.cache GOLANGCI_LINT_CACHE=$(pwd)/.golangci-cache golangci-lint run ./kv --timeout=5m
  • git diff --check

@chatgpt-codex-connector

Copy link
Copy Markdown

Codex Review: Didn't find any major issues. Chef's kiss.

Reviewed commit: 7c1780323e

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Base automatically changed from design/hotspot-split-m2-migrator-plan to design/hotspot-split-m2-store-export July 14, 2026 05:09
…port' into design/hotspot-split-m2-fence-drain
@bootjp

bootjp commented Jul 14, 2026

Copy link
Copy Markdown
Owner Author

@codex review

Merged the latest design/hotspot-split-m2-store-export base into this branch at 585e5ac. No conflicts remained after the merge.

Validation:

  • GOCACHE=$(pwd)/.cache GOTMPDIR=$(pwd)/.cache/tmp go test ./kv -run 'TestRoutePrefixRangeTreatsBroadMappedPrefixesAsFullKeyspace|TestFSMRejects.*WriteFenced|TestShardedCoordinatorRejects.WriteFenced|TestShardedCoordinator_DelPrefix|TestPendingTxnLocksInRoute.|TestEngineGetIntersectingRoutes' -count=1 -timeout=240s
  • GOCACHE=$(pwd)/.cache GOTMPDIR=$(pwd)/.cache/tmp go test ./distribution -run 'TestEngineGetIntersectingRoutes|Test.*Route.*Intersect|TestSplitJob.*Fence|TestSplitJob.*Drain' -count=1 -timeout=240s
  • GOCACHE=$(pwd)/.cache GOTMPDIR=$(pwd)/.cache/tmp go test ./kv -count=1 -timeout=300s
  • GOCACHE=$(pwd)/.cache GOTMPDIR=$(pwd)/.cache/tmp go test ./distribution -count=1 -timeout=300s
  • GOCACHE=$(pwd)/.cache GOTMPDIR=$(pwd)/.cache/tmp go test ./adapter -run 'TestDistribution|Test.*Migration|Test.*Split|Test.*Fence|Test.*RawRead' -count=1 -timeout=300s
  • GOCACHE=$(pwd)/.cache GOLANGCI_LINT_CACHE=$(pwd)/.golangci-cache golangci-lint --config=.golangci.yaml run ./kv ./distribution ./adapter --timeout=5m
  • git diff --check

Caller audit for the fail-closed write-fence path:

  • rg -n "routePrefixRange\(|verifyRouteNotFencedFor|rejectWriteFenced|PendingTxnLocksInRoute\(|WriteFencedIntersects\(|WriteFencedForKey\(|GetIntersectingRoutes\(" kv distribution adapter -g "*.go"

@github-actions

Copy link
Copy Markdown
Contributor

TLA+ spec divergence review (auto-triggered)

This PR touches files that the TLA+ safety spec has an anchor on (per
docs/design/2026_05_28_implemented_tla_safety_spec.md §3),
so an AI review is requested below to verify the implementation has not drifted
from the model.

Anchored files changed in this PR head (585e5ac):

  • distribution/engine.go
  • distribution/split_job_catalog.go
  • kv/fsm.go
  • kv/sharded_coordinator.go

What to check, by subsystem:

  • kv/hlc*.goNext() must respect the HLC-4 preconditions (i)/(ii)/(iii) from the design doc: bounded skew, logical-counter handoff on leader change (strategy (c) Observe(MaxAppliedHLC)), and the commit-time ceiling fence (fail-closed when wall_now >= physicalCeiling). Any change to the bit layout (48/16), the CAS loop, or the ceiling getter/setter is in scope.
  • kv/coordinator.go, kv/sharded_coordinator.goRunHLCLeaseRenewal, hlcRenewalInterval, hlcPhysicalWindowMs constants, and the new-term detection that calls Observe(fsm.MaxAppliedHLC()) (strategy (c)). Any change to renewal cadence, group selection, or fail-closed behaviour is in scope.
  • kv/transaction.go, kv/lock_resolver.go — OCC commit-ts assignment, lock-map encoding (key, lock_ts) -> start_ts, and the LockResolver action OCC-3 depends on. (M2 spec will land OCC-1..OCC-5; until then the spec doc §5.2 is the contract.)
  • kv/fsm.go — FSM apply of HLC lease entries (SetPhysicalCeiling), and any future MaxAppliedHLC() accessor that strategy (c) needs.
  • store/mvcc_store.go — version visibility, snapshot install, and the MVCC-1..MVCC-4 invariants (M3 scope).
  • distribution/** — route catalog versioning, SplitRange atomicity, and CatalogWatcher async fan-out (M4 scope).

If the change is correct but requires a spec update, edit tla/hlc/HLC.tla (or the corresponding M2..M5 module once landed) and the design doc in the same PR. The tla-check workflow runs the TLC model check on the same paths.


@claude review please verify TLA+ spec divergence per the checklist above.

@codex review please verify TLA+ spec divergence per the checklist above.

@chatgpt-codex-connector

Copy link
Copy Markdown

To use Codex here, create a Codex account and connect to github.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 585e5acb5f

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread kv/sharded_coordinator.go Outdated
if elem == nil || len(elem.Key) == 0 {
continue
}
route, ok := c.engine.GetRoute(routeKey(elem.Key))

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P1 Badge Fence S3 bucket auxiliary point writes

For bucket-level S3 mutations such as ACL/bucket-meta updates, routeKey returns the raw !s3|bucket|meta|... key, while migration export/drain treats that row as belonging to the bucket's !s3route|... object route via s3BucketAuxiliaryRouteInRange. If that object route is WriteFenced, this pre-routing check misses it and allows the metadata-only write to commit during the fence; the FSM check uses the same routeKey-only predicate, so bypass/direct proposals are not caught either.

Useful? React with 👍 / 👎.

Comment thread adapter/distribution_server.go Outdated
if err := validateSplitKey(parent, splitKey); err != nil {
return nil, err
}
if err := s.rejectLiveSplitJobOverlap(ctx, snapshot, parent); err != nil {

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Make split-job overlap checks atomic

This checks only the split jobs visible at snapshot.ReadTS, but the subsequent saveSplitResultViaCoordinator transaction writes route/version keys and does not include the scanned !dist|job|... rows in its read set. If another controller creates or advances an overlapping live split job after this snapshot but before the split catalog write commits, both operations can commit because they touch disjoint keys, defeating the new overlap guard.

Useful? React with 👍 / 👎.

Comment thread distribution/engine.go Outdated
Comment on lines +426 to +430
return Route{
RouteID: r.RouteID,
Start: CloneBytes(r.Start),
End: CloneBytes(r.End),
GroupID: r.GroupID,

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Preserve migration route metadata in history clones

The new RouteHistorySnapshot.RouteOf and IntersectingRoutes APIs return cloneRoute(r), but this clone omits migration fields such as StagedVisibilityActive, MigrationJobID, and MinWriteTSExclusive. Any caller consulting a current or historical snapshot for those route properties during migration will see zero values even though the engine snapshot retained them, unlike GetRoute, Stats, and GetIntersectingRoutes.

Useful? React with 👍 / 👎.

Comment thread kv/fsm.go
@github-actions

Copy link
Copy Markdown
Contributor

TLA+ spec divergence review (auto-triggered)

This PR touches files that the TLA+ safety spec has an anchor on (per
docs/design/2026_05_28_implemented_tla_safety_spec.md §3),
so an AI review is requested below to verify the implementation has not drifted
from the model.

Anchored files changed in this PR head (5acb33f):

  • distribution/engine.go
  • distribution/split_job_catalog.go
  • kv/fsm.go
  • kv/sharded_coordinator.go

What to check, by subsystem:

  • kv/hlc*.goNext() must respect the HLC-4 preconditions (i)/(ii)/(iii) from the design doc: bounded skew, logical-counter handoff on leader change (strategy (c) Observe(MaxAppliedHLC)), and the commit-time ceiling fence (fail-closed when wall_now >= physicalCeiling). Any change to the bit layout (48/16), the CAS loop, or the ceiling getter/setter is in scope.
  • kv/coordinator.go, kv/sharded_coordinator.goRunHLCLeaseRenewal, hlcRenewalInterval, hlcPhysicalWindowMs constants, and the new-term detection that calls Observe(fsm.MaxAppliedHLC()) (strategy (c)). Any change to renewal cadence, group selection, or fail-closed behaviour is in scope.
  • kv/transaction.go, kv/lock_resolver.go — OCC commit-ts assignment, lock-map encoding (key, lock_ts) -> start_ts, and the LockResolver action OCC-3 depends on. (M2 spec will land OCC-1..OCC-5; until then the spec doc §5.2 is the contract.)
  • kv/fsm.go — FSM apply of HLC lease entries (SetPhysicalCeiling), and any future MaxAppliedHLC() accessor that strategy (c) needs.
  • store/mvcc_store.go — version visibility, snapshot install, and the MVCC-1..MVCC-4 invariants (M3 scope).
  • distribution/** — route catalog versioning, SplitRange atomicity, and CatalogWatcher async fan-out (M4 scope).

If the change is correct but requires a spec update, edit tla/hlc/HLC.tla (or the corresponding M2..M5 module once landed) and the design doc in the same PR. The tla-check workflow runs the TLC model check on the same paths.


@claude review please verify TLA+ spec divergence per the checklist above.

@codex review please verify TLA+ spec divergence per the checklist above.

@chatgpt-codex-connector

Copy link
Copy Markdown

To use Codex here, create a Codex account and connect to github.

@bootjp

bootjp commented Jul 14, 2026

Copy link
Copy Markdown
Owner Author

@codex review

Addressed the current-head P1 S3 bucket auxiliary write-fence finding in 5acb33f.

Changes:

  • Reused the S3 bucket auxiliary route projection from migration export filtering for write-fence checks.
  • Reject BucketMetaKey and BucketGenerationKey point writes when the corresponding !s3route|bucket|... object route is WriteFenced.
  • Apply the same fail-closed check in both the coordinator pre-dispatch path and the FSM apply path.
  • Added regression coverage for both bucket meta and generation writes.

Validation:

  • GOCACHE=$(pwd)/.cache GOTMPDIR=$(pwd)/.cache/tmp go test ./kv -run 'TestFSMRejects.*WriteFenced|TestShardedCoordinatorRejects.*WriteFenced|TestRouteKeyFilterIncludesS3BucketAuxiliary' -count=1 -timeout=240s
  • GOCACHE=$(pwd)/.cache GOTMPDIR=$(pwd)/.cache/tmp go test ./kv -count=1 -timeout=300s
  • GOCACHE=$(pwd)/.cache GOTMPDIR=$(pwd)/.cache/tmp go test ./adapter -run 'TestS3Server_(BucketAndObjectLifecycle|PutBucketAcl_ChangeToPublicAndBack|GetBucketAcl_Private|GetBucketAcl_PublicRead|AdminDeleteBucket|PutBucketAcl_RejectsXMLBody)' -count=1 -timeout=240s
  • GOCACHE=$(pwd)/.cache GOLANGCI_LINT_CACHE=$(pwd)/.golangci-cache golangci-lint --config=.golangci.yaml run ./kv --timeout=5m
  • git diff --check

Caller audit:

  • rg -n 's3BucketAuxiliaryRouteRange|s3BucketAuxiliaryRouteInRange|verifyRouteNotFencedForKey|verifyRouteNotFencedForPrefix|verifyRouteNotFencedForMutations|rejectWriteFencedPointElems|rejectWriteFencedDelPrefixes|routePrefixRange\(|WriteFencedForKey\(|WriteFencedIntersects\(|GetIntersectingRoutes\(|RouteKeyFilter\(' kv distribution adapter internal store -g '*.go'

@chatgpt-codex-connector

Copy link
Copy Markdown

Codex Review: Didn't find any major issues. Nice work!

Reviewed commit: 5acb33f426

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

@github-actions

Copy link
Copy Markdown
Contributor

TLA+ spec divergence review (auto-triggered)

This PR touches files that the TLA+ safety spec has an anchor on (per
docs/design/2026_05_28_implemented_tla_safety_spec.md §3),
so an AI review is requested below to verify the implementation has not drifted
from the model.

Anchored files changed in this PR head (f1aeeeb):

  • distribution/engine.go
  • distribution/engine_test.go
  • distribution/split_job_catalog.go
  • kv/fsm.go
  • kv/sharded_coordinator.go

What to check, by subsystem:

  • kv/hlc*.goNext() must respect the HLC-4 preconditions (i)/(ii)/(iii) from the design doc: bounded skew, logical-counter handoff on leader change (strategy (c) Observe(MaxAppliedHLC)), and the commit-time ceiling fence (fail-closed when wall_now >= physicalCeiling). Any change to the bit layout (48/16), the CAS loop, or the ceiling getter/setter is in scope.
  • kv/coordinator.go, kv/sharded_coordinator.goRunHLCLeaseRenewal, hlcRenewalInterval, hlcPhysicalWindowMs constants, and the new-term detection that calls Observe(fsm.MaxAppliedHLC()) (strategy (c)). Any change to renewal cadence, group selection, or fail-closed behaviour is in scope.
  • kv/transaction.go, kv/lock_resolver.go — OCC commit-ts assignment, lock-map encoding (key, lock_ts) -> start_ts, and the LockResolver action OCC-3 depends on. (M2 spec will land OCC-1..OCC-5; until then the spec doc §5.2 is the contract.)
  • kv/fsm.go — FSM apply of HLC lease entries (SetPhysicalCeiling), and any future MaxAppliedHLC() accessor that strategy (c) needs.
  • store/mvcc_store.go — version visibility, snapshot install, and the MVCC-1..MVCC-4 invariants (M3 scope).
  • distribution/** — route catalog versioning, SplitRange atomicity, and CatalogWatcher async fan-out (M4 scope).

If the change is correct but requires a spec update, edit tla/hlc/HLC.tla (or the corresponding M2..M5 module once landed) and the design doc in the same PR. The tla-check workflow runs the TLC model check on the same paths.


@claude review please verify TLA+ spec divergence per the checklist above.

@codex review please verify TLA+ spec divergence per the checklist above.

@github-actions

Copy link
Copy Markdown
Contributor

TLA+ spec divergence review (auto-triggered)

This PR touches files that the TLA+ safety spec has an anchor on (per
docs/design/2026_05_28_implemented_tla_safety_spec.md §3),
so an AI review is requested below to verify the implementation has not drifted
from the model.

Anchored files changed in this PR head (04e8053):

  • distribution/engine.go
  • distribution/engine_test.go
  • distribution/split_job_catalog.go
  • kv/coordinator.go
  • kv/fsm.go
  • kv/sharded_coordinator.go

What to check, by subsystem:

  • kv/hlc*.goNext() must respect the HLC-4 preconditions (i)/(ii)/(iii) from the design doc: bounded skew, logical-counter handoff on leader change (strategy (c) Observe(MaxAppliedHLC)), and the commit-time ceiling fence (fail-closed when wall_now >= physicalCeiling). Any change to the bit layout (48/16), the CAS loop, or the ceiling getter/setter is in scope.
  • kv/coordinator.go, kv/sharded_coordinator.goRunHLCLeaseRenewal, hlcRenewalInterval, hlcPhysicalWindowMs constants, and the new-term detection that calls Observe(fsm.MaxAppliedHLC()) (strategy (c)). Any change to renewal cadence, group selection, or fail-closed behaviour is in scope.
  • kv/transaction.go, kv/lock_resolver.go — OCC commit-ts assignment, lock-map encoding (key, lock_ts) -> start_ts, and the LockResolver action OCC-3 depends on. (M2 spec will land OCC-1..OCC-5; until then the spec doc §5.2 is the contract.)
  • kv/fsm.go — FSM apply of HLC lease entries (SetPhysicalCeiling), and any future MaxAppliedHLC() accessor that strategy (c) needs.
  • store/mvcc_store.go — version visibility, snapshot install, and the MVCC-1..MVCC-4 invariants (M3 scope).
  • distribution/** — route catalog versioning, SplitRange atomicity, and CatalogWatcher async fan-out (M4 scope).

If the change is correct but requires a spec update, edit tla/hlc/HLC.tla (or the corresponding M2..M5 module once landed) and the design doc in the same PR. The tla-check workflow runs the TLC model check on the same paths.


@claude review please verify TLA+ spec divergence per the checklist above.

@codex review please verify TLA+ spec divergence per the checklist above.

@chatgpt-codex-connector

Copy link
Copy Markdown

To use Codex here, create a Codex account and connect to github.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 04e8053bcb

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread kv/sharded_coordinator.go
Comment on lines +1007 to +1010
if !errors.Is(err, ErrComposed1VersionGCd) || attempt == composed1RetryAttempts || c.engine == nil {
return resp, err
}
reqs.ObservedRouteVersion = c.engine.Version()

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Avoid replaying successful raw shards on version-GC retry

When a raw OperationGroup spans multiple groups (including DEL_PREFIX broadcasts), ErrComposed1VersionGCd can be returned after some groups have already committed: ShardRouter.processGrouped continues past per-group errors, and the broadcast path can also partially succeed. This retry reissues the entire batch with a fresh route version and fresh raw timestamps, so a group that already applied a Del/DelPrefix can apply it again later and tombstone writes that arrived after the first attempt. Please retry only groups known not to have committed, or limit this automatic retry to single-group/no-side-effect failures.

Useful? React with 👍 / 👎.

Comment thread kv/fsm.go
return []byte(""), nil
}
start := routeKey(prefix)
return start, prefixScanEnd(start)

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Treat exact Dynamo cleanup routes as point keys

For DynamoDB table-delete cleanup prefixes, routeKey(prefix) returns the exact table route key !ddb|route|table|<encoded-table>, but this turns it into a prefix interval. With tables such as foo and foobar (Zm9v/Zm9vYmFy), a WriteFenced route for the latter intersects the cleanup DEL_PREFIX for the former even though the physical cleanup prefix only targets foo; because this cleanup runs after table metadata is gone, an unrelated migration can make the async sweep give up and leave old item/GSI rows behind. Special-case exact per-table route keys (or use a prefix-free route-key range) instead of prefixScanEnd(start) here.

Useful? React with 👍 / 👎.

Comment thread main.go
if prepared == nil || prepared.preparedServer == nil || prepared.preparedServer.runner == nil {
return errors.New("distribution runtime server is not prepared")
}
if err := prepared.preparedServer.runner.startRaftTransport(); err != nil {

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Gate distribution reads until route setup completes

Starting the shared raft gRPC server here also registers DistributionServer, but the startup gate only blocks selected mutators such as SplitRange; GetRoute, ListRoutes, and GetIntersectingRoutes remain callable until waitForRaftStartupAfterTransport and setupDistributionAndRegistration have applied the durable catalog back into the engine. During replay or catalog bootstrap those methods can return the stale/default route view while the data plane is still held back, so route-aware clients or admins can cache incorrect ownership. Either delay these distribution reads or include them in the startup gate when binding transport before setup.

Useful? React with 👍 / 👎.

@github-actions

Copy link
Copy Markdown
Contributor

TLA+ spec divergence review (auto-triggered)

This PR touches files that the TLA+ safety spec has an anchor on (per
docs/design/2026_05_28_implemented_tla_safety_spec.md §3),
so an AI review is requested below to verify the implementation has not drifted
from the model.

Anchored files changed in this PR head (d818602):

  • distribution/engine.go
  • distribution/engine_test.go
  • distribution/split_job_catalog.go
  • kv/coordinator.go
  • kv/fsm.go
  • kv/sharded_coordinator.go

What to check, by subsystem:

  • kv/hlc*.goNext() must respect the HLC-4 preconditions (i)/(ii)/(iii) from the design doc: bounded skew, logical-counter handoff on leader change (strategy (c) Observe(MaxAppliedHLC)), and the commit-time ceiling fence (fail-closed when wall_now >= physicalCeiling). Any change to the bit layout (48/16), the CAS loop, or the ceiling getter/setter is in scope.
  • kv/coordinator.go, kv/sharded_coordinator.goRunHLCLeaseRenewal, hlcRenewalInterval, hlcPhysicalWindowMs constants, and the new-term detection that calls Observe(fsm.MaxAppliedHLC()) (strategy (c)). Any change to renewal cadence, group selection, or fail-closed behaviour is in scope.
  • kv/transaction.go, kv/lock_resolver.go — OCC commit-ts assignment, lock-map encoding (key, lock_ts) -> start_ts, and the LockResolver action OCC-3 depends on. (M2 spec will land OCC-1..OCC-5; until then the spec doc §5.2 is the contract.)
  • kv/fsm.go — FSM apply of HLC lease entries (SetPhysicalCeiling), and any future MaxAppliedHLC() accessor that strategy (c) needs.
  • store/mvcc_store.go — version visibility, snapshot install, and the MVCC-1..MVCC-4 invariants (M3 scope).
  • distribution/** — route catalog versioning, SplitRange atomicity, and CatalogWatcher async fan-out (M4 scope).

If the change is correct but requires a spec update, edit tla/hlc/HLC.tla (or the corresponding M2..M5 module once landed) and the design doc in the same PR. The tla-check workflow runs the TLC model check on the same paths.


@claude review please verify TLA+ spec divergence per the checklist above.

@codex review please verify TLA+ spec divergence per the checklist above.

@chatgpt-codex-connector

Copy link
Copy Markdown

To use Codex here, create a Codex account and connect to github.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: d818602593

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

// Prewrite cleanup runs on the snapshot receive hot path before gRPC starts
// draining payload chunks. Only do a footer/token check here; full-payload
// CRC remains in the actual restore/open paths.
return fsmSnapshotFooterMatchesToken(fsmSnapPath(fsmSnapDir, index), tok.CRC32C) == nil

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Verify retained snapshot payloads before pruning fallbacks

When prewrite cleanup runs before receiving/writing a newer snapshot, a prior .snap/.fsm pair is now considered restorable just because the .fsm footer still contains the token CRC. That does not recompute the payload CRC, so a body-corrupted .fsm with its original footer can be selected as the sole fallback and purgeUnretainedPrewriteSnapshots may delete an older valid pair before the new write finishes; if the incoming snapshot then fails, restart has only a corrupt retained snapshot. Please keep full verification for the pair that justifies pruning older fallbacks, or keep additional fallbacks when using the cheap footer check.

Useful? React with 👍 / 👎.

Comment on lines 2423 to 2427
if len(ch) >= cap(ch) {
if msg.GetType() == raftpb.MsgHeartbeatResp && coalesceHeartbeatResp(ch, msg) {
return nil
}
e.recordDroppedDispatch(msg)

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Preserve incoming ReadIndex heartbeat responses

Fresh evidence in this revision is that the new coalescer only protects already queued context-bearing responses: when the heartbeat-response lane is full of ReadIndex MsgHeartbeatResps (all with Context), an incoming response with its own Context falls through this branch and recordDroppedDispatch drops it. handleRead waits for that encoded context via handleReadStates, so under bursts of linearizable reads the dropped response can make a completed ReadIndex wait until its deadline; context-bearing incoming responses need a non-dropping path or reserved space.

Useful? React with 👍 / 👎.

Comment thread main.go
if prepared == nil || prepared.preparedServer == nil || prepared.preparedServer.runner == nil {
return errors.New("distribution runtime server is not prepared")
}
if err := prepared.preparedServer.runner.startRaftTransport(); err != nil {

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Gate raw reads until raft replay completes

Binding the raft transport here also starts the per-group gRPC server that registers RawKV/TransactionalKV; write methods go through the startup-gated coordinator, but read methods such as RawGet, Get, RawScanAt, and Scan read the store directly. Because this now happens before waitForRaftStartupAfterTransport has drained committed replay and before catalog/registration setup, any internal client using the raft gRPC address during that window can observe stale MVCC state; either delay registering those read services or gate them until WaitStarted completes.

Useful? React with 👍 / 👎.

@github-actions

Copy link
Copy Markdown
Contributor

TLA+ spec divergence review (auto-triggered)

This PR touches files that the TLA+ safety spec has an anchor on (per
docs/design/2026_05_28_implemented_tla_safety_spec.md §3),
so an AI review is requested below to verify the implementation has not drifted
from the model.

Anchored files changed in this PR head (db9843a):

  • distribution/engine.go
  • distribution/engine_test.go
  • distribution/split_job_catalog.go
  • kv/coordinator.go
  • kv/fsm.go
  • kv/sharded_coordinator.go

What to check, by subsystem:

  • kv/hlc*.goNext() must respect the HLC-4 preconditions (i)/(ii)/(iii) from the design doc: bounded skew, logical-counter handoff on leader change (strategy (c) Observe(MaxAppliedHLC)), and the commit-time ceiling fence (fail-closed when wall_now >= physicalCeiling). Any change to the bit layout (48/16), the CAS loop, or the ceiling getter/setter is in scope.
  • kv/coordinator.go, kv/sharded_coordinator.goRunHLCLeaseRenewal, hlcRenewalInterval, hlcPhysicalWindowMs constants, and the new-term detection that calls Observe(fsm.MaxAppliedHLC()) (strategy (c)). Any change to renewal cadence, group selection, or fail-closed behaviour is in scope.
  • kv/transaction.go, kv/lock_resolver.go — OCC commit-ts assignment, lock-map encoding (key, lock_ts) -> start_ts, and the LockResolver action OCC-3 depends on. (M2 spec will land OCC-1..OCC-5; until then the spec doc §5.2 is the contract.)
  • kv/fsm.go — FSM apply of HLC lease entries (SetPhysicalCeiling), and any future MaxAppliedHLC() accessor that strategy (c) needs.
  • store/mvcc_store.go — version visibility, snapshot install, and the MVCC-1..MVCC-4 invariants (M3 scope).
  • distribution/** — route catalog versioning, SplitRange atomicity, and CatalogWatcher async fan-out (M4 scope).

If the change is correct but requires a spec update, edit tla/hlc/HLC.tla (or the corresponding M2..M5 module once landed) and the design doc in the same PR. The tla-check workflow runs the TLC model check on the same paths.


@claude review please verify TLA+ spec divergence per the checklist above.

@codex review please verify TLA+ spec divergence per the checklist above.

@chatgpt-codex-connector

Copy link
Copy Markdown

To use Codex here, create a Codex account and connect to github.

@github-actions

Copy link
Copy Markdown
Contributor

TLA+ spec divergence review (auto-triggered)

This PR touches files that the TLA+ safety spec has an anchor on (per
docs/design/2026_05_28_implemented_tla_safety_spec.md §3),
so an AI review is requested below to verify the implementation has not drifted
from the model.

Anchored files changed in this PR head (a6d7d76):

  • distribution/engine.go
  • distribution/engine_test.go
  • distribution/split_job_catalog.go
  • kv/coordinator.go
  • kv/fsm.go
  • kv/sharded_coordinator.go

What to check, by subsystem:

  • kv/hlc*.goNext() must respect the HLC-4 preconditions (i)/(ii)/(iii) from the design doc: bounded skew, logical-counter handoff on leader change (strategy (c) Observe(MaxAppliedHLC)), and the commit-time ceiling fence (fail-closed when wall_now >= physicalCeiling). Any change to the bit layout (48/16), the CAS loop, or the ceiling getter/setter is in scope.
  • kv/coordinator.go, kv/sharded_coordinator.goRunHLCLeaseRenewal, hlcRenewalInterval, hlcPhysicalWindowMs constants, and the new-term detection that calls Observe(fsm.MaxAppliedHLC()) (strategy (c)). Any change to renewal cadence, group selection, or fail-closed behaviour is in scope.
  • kv/transaction.go, kv/lock_resolver.go — OCC commit-ts assignment, lock-map encoding (key, lock_ts) -> start_ts, and the LockResolver action OCC-3 depends on. (M2 spec will land OCC-1..OCC-5; until then the spec doc §5.2 is the contract.)
  • kv/fsm.go — FSM apply of HLC lease entries (SetPhysicalCeiling), and any future MaxAppliedHLC() accessor that strategy (c) needs.
  • store/mvcc_store.go — version visibility, snapshot install, and the MVCC-1..MVCC-4 invariants (M3 scope).
  • distribution/** — route catalog versioning, SplitRange atomicity, and CatalogWatcher async fan-out (M4 scope).

If the change is correct but requires a spec update, edit tla/hlc/HLC.tla (or the corresponding M2..M5 module once landed) and the design doc in the same PR. The tla-check workflow runs the TLC model check on the same paths.


@claude review please verify TLA+ spec divergence per the checklist above.

@codex review please verify TLA+ spec divergence per the checklist above.

@chatgpt-codex-connector

Copy link
Copy Markdown

To use Codex here, create a Codex account and connect to github.

@bootjp

bootjp commented Jul 15, 2026

Copy link
Copy Markdown
Owner Author

@codex review

Updated in a6d7d76:

  • Drop cached raft peer gRPC connections after Unavailable dispatch failures so a restarted follower is redialed on the next heartbeat instead of waiting for the old ClientConn backoff.
  • Added regression coverage for clearing cached peer clients after unary Unavailable.

Validation:

  • go test ./internal/raftengine/etcd -run 'TestDispatchRegularDropsCachedPeerConnAfterUnaryUnavailable|TestDispatchRegularUsesUnaryForPriorityMessages|TestDispatchRegularFallsBackToUnaryWhenSendStreamDisabled|TestDispatchRegularFallsBackToUnaryWhenSendStreamDisabledDuringOpen|TestEnqueueDispatchMessagePreservesIncomingReadIndexHeartbeatWhenRespLaneFull' -count=1 -timeout=240s
  • go test ./internal/raftengine/etcd -count=1 -timeout=300s
  • go test ./adapter -count=1 -timeout=600s -failfast -v
  • golangci-lint --config=.golangci.yaml run --fix ./internal/raftengine/etcd
  • git diff --check

Operational note:

  • n3 temporarily took about two minutes to rejoin after restart because n5 held a stale refused ClientConn. After gRPC backoff recovered, n1/n3/n5 converged again on n5 as leader with matched commit/applied indexes and healthy negative HLC skew. This patch removes that rollout delay for future restarts.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: a6d7d7609c

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread kv/fsm.go
Comment on lines +915 to +916
rKey := routeKey(mut.Key)
if snap.WriteFencedForKey(rKey) {

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Preserve resolver-owned writes at the FSM fence

For resolver-owned SQS partition keys, the coordinator now deliberately skips the byte-route write-fence precheck, but the real FSM still runs this unconditional routeKey fence and normalizes those keys to the byte-route namespace (for example !sqs|route|global). In a partitioned queue whose byte route is WriteFenced, the request can be routed to the resolver's group and then fail at apply time with ErrRouteWriteFenced, so the partition-resolver path that the coordinator allows still cannot commit in production. Carry an explicit resolver-bypass marker to the FSM or avoid bypassing the coordinator precheck until the apply-time fence can make the same distinction.

Useful? React with 👍 / 👎.

@github-actions

Copy link
Copy Markdown
Contributor

TLA+ spec divergence review (auto-triggered)

This PR touches files that the TLA+ safety spec has an anchor on (per
docs/design/2026_05_28_implemented_tla_safety_spec.md §3),
so an AI review is requested below to verify the implementation has not drifted
from the model.

Anchored files changed in this PR head (c8f865e):

  • distribution/engine.go
  • distribution/engine_test.go
  • distribution/split_job_catalog.go
  • kv/coordinator.go
  • kv/fsm.go
  • kv/sharded_coordinator.go

What to check, by subsystem:

  • kv/hlc*.goNext() must respect the HLC-4 preconditions (i)/(ii)/(iii) from the design doc: bounded skew, logical-counter handoff on leader change (strategy (c) Observe(MaxAppliedHLC)), and the commit-time ceiling fence (fail-closed when wall_now >= physicalCeiling). Any change to the bit layout (48/16), the CAS loop, or the ceiling getter/setter is in scope.
  • kv/coordinator.go, kv/sharded_coordinator.goRunHLCLeaseRenewal, hlcRenewalInterval, hlcPhysicalWindowMs constants, and the new-term detection that calls Observe(fsm.MaxAppliedHLC()) (strategy (c)). Any change to renewal cadence, group selection, or fail-closed behaviour is in scope.
  • kv/transaction.go, kv/lock_resolver.go — OCC commit-ts assignment, lock-map encoding (key, lock_ts) -> start_ts, and the LockResolver action OCC-3 depends on. (M2 spec will land OCC-1..OCC-5; until then the spec doc §5.2 is the contract.)
  • kv/fsm.go — FSM apply of HLC lease entries (SetPhysicalCeiling), and any future MaxAppliedHLC() accessor that strategy (c) needs.
  • store/mvcc_store.go — version visibility, snapshot install, and the MVCC-1..MVCC-4 invariants (M3 scope).
  • distribution/** — route catalog versioning, SplitRange atomicity, and CatalogWatcher async fan-out (M4 scope).

If the change is correct but requires a spec update, edit tla/hlc/HLC.tla (or the corresponding M2..M5 module once landed) and the design doc in the same PR. The tla-check workflow runs the TLC model check on the same paths.


@claude review please verify TLA+ spec divergence per the checklist above.

@codex review please verify TLA+ spec divergence per the checklist above.

@chatgpt-codex-connector

Copy link
Copy Markdown

To use Codex here, create a Codex account and connect to github.

@bootjp

bootjp commented Jul 15, 2026

Copy link
Copy Markdown
Owner Author

@codex review

Updated in c8f865e:

  • Limited outbound FSM snapshot sends to one in-flight stream per transport and reject duplicate received FSM snapshot indexes before draining payload bytes.
  • Preserved resolver-owned point writes through the FSM write-fence check with a durable request marker; DEL_PREFIX and unmarked keys remain fenced.
  • Added regression coverage for duplicate snapshot protection, early receive rejection, resolver-owned fence bypass, and DEL_PREFIX fail-closed behavior.

Validation:

  • make -C proto gen
  • go test ./internal/raftengine/etcd -run 'TestSnapshotSendGateAllowsOnlyOneInFlightSnapshot|TestReceiveSnapshotStreamRejectsProtectedIndexBeforePayload|TestProtectReceivedFSMSnapshotRejectsDuplicateInFlightIndex|TestReceiveSnapshotStream|TestDrainSnapshotChunks|TestDispatchRegularDropsCachedPeerConnAfterUnaryUnavailable' -count=1 -timeout=240s
  • go test ./kv -run 'TestFSMWriteFenceBypassAllowsMarkedRawPointWrite|TestFSMWriteFenceBypassDoesNotAllowDelPrefix|TestFSMRejectsCurrentWriteFencedRawPointWrite|TestShardedCoordinatorWriteFencePrecheckHonoursPartitionResolver|TestShardedCoordinatorTxnCarriesResolverWriteFenceBypassKeys|TestShardedCoordinatorWriteFencePrecheckSkipsUnresolvedPartitionKey|TestShardedCoordinator_DispatchSplitsMutationsByResolverGroup' -count=1 -timeout=240s
  • go test ./internal/raftengine/etcd -count=1 -timeout=300s
  • go test ./kv -count=1 -timeout=300s
  • go test ./...
  • git diff --check

Caller audit:

  • rg -n "verifyWriteFenceFromSnapshot\(|onePhaseTxnRequestWithPrevCommit\(|buildTxnLogs\(|GetWriteFenceBypassKeys\(|WriteFenceBypassKeys" kv proto internal adapter cmd -g"*.go"

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: c8f865ea84

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

}

func isRetryableTransactWriteError(err error) bool {
return errors.Is(err, store.ErrWriteConflict) || errors.Is(err, kv.ErrTxnLocked) || errors.Is(err, kv.ErrRouteWriteFenced)

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Avoid swallowing route-fence errors in SQS receives

When ReceiveMessage tries to rotate a visible SQS candidate while that route is write-fenced, the coordinator returns ErrRouteWriteFenced before applying anything. Adding that sentinel to this broad retryable helper also changes existing skip-on-race call sites such as tryDeliverCandidate, where isRetryableTransactWriteError(err) returns skip=true, nil; in that migration window consumers can get an empty/smaller 200 response even though the message is still visible, instead of retrying or surfacing backpressure. Use the narrower non-fence race predicate at swallow sites, or keep the fence retry classification out of this shared helper.

Useful? React with 👍 / 👎.

@bootjp

bootjp commented Jul 15, 2026

Copy link
Copy Markdown
Owner Author

@codex review

Addressed the current SQS receive route-fence finding.

Changes:

  • commitReceiveRotation now treats only non-fence OCC races (ErrWriteConflict / ErrTxnLocked) as candidate skip.
  • ErrRouteWriteFenced now propagates from SQS receive rotation instead of returning an empty/smaller success response.
  • Added a focused receive-rotation test covering ErrWriteConflict, ErrTxnLocked, and ErrRouteWriteFenced classification.

Validation:

  • go test ./adapter -run 'TestSQSReceiveRotationClassifiesDispatchErrors|TestWriteFenceErrorsAreAdapterRetryable' -count=1 -timeout=240s
  • go test ./adapter -count=1 -timeout=600s
  • go test ./...
  • git diff --check HEAD~1 HEAD
  • caller audit: rg -n "isRetryableTransactWriteError|isIgnorableTransactRaceError|ErrRouteWriteFenced|tryDeliverCandidate|commitReceiveRotation" adapter kv -g'*.go'

Head: b553090

@github-actions

Copy link
Copy Markdown
Contributor

TLA+ spec divergence review (auto-triggered)

This PR touches files that the TLA+ safety spec has an anchor on (per
docs/design/2026_05_28_implemented_tla_safety_spec.md §3),
so an AI review is requested below to verify the implementation has not drifted
from the model.

Anchored files changed in this PR head (b553090):

  • distribution/engine.go
  • distribution/engine_test.go
  • distribution/split_job_catalog.go
  • kv/coordinator.go
  • kv/fsm.go
  • kv/sharded_coordinator.go

What to check, by subsystem:

  • kv/hlc*.goNext() must respect the HLC-4 preconditions (i)/(ii)/(iii) from the design doc: bounded skew, logical-counter handoff on leader change (strategy (c) Observe(MaxAppliedHLC)), and the commit-time ceiling fence (fail-closed when wall_now >= physicalCeiling). Any change to the bit layout (48/16), the CAS loop, or the ceiling getter/setter is in scope.
  • kv/coordinator.go, kv/sharded_coordinator.goRunHLCLeaseRenewal, hlcRenewalInterval, hlcPhysicalWindowMs constants, and the new-term detection that calls Observe(fsm.MaxAppliedHLC()) (strategy (c)). Any change to renewal cadence, group selection, or fail-closed behaviour is in scope.
  • kv/transaction.go, kv/lock_resolver.go — OCC commit-ts assignment, lock-map encoding (key, lock_ts) -> start_ts, and the LockResolver action OCC-3 depends on. (M2 spec will land OCC-1..OCC-5; until then the spec doc §5.2 is the contract.)
  • kv/fsm.go — FSM apply of HLC lease entries (SetPhysicalCeiling), and any future MaxAppliedHLC() accessor that strategy (c) needs.
  • store/mvcc_store.go — version visibility, snapshot install, and the MVCC-1..MVCC-4 invariants (M3 scope).
  • distribution/** — route catalog versioning, SplitRange atomicity, and CatalogWatcher async fan-out (M4 scope).

If the change is correct but requires a spec update, edit tla/hlc/HLC.tla (or the corresponding M2..M5 module once landed) and the design doc in the same PR. The tla-check workflow runs the TLC model check on the same paths.


@claude review please verify TLA+ spec divergence per the checklist above.

@codex review please verify TLA+ spec divergence per the checklist above.

@chatgpt-codex-connector

Copy link
Copy Markdown

To use Codex here, create a Codex account and connect to github.

@chatgpt-codex-connector

Copy link
Copy Markdown

Codex Review: Didn't find any major issues. Swish!

Reviewed commit: b553090f29

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

@github-actions

Copy link
Copy Markdown
Contributor

TLA+ spec divergence review (auto-triggered)

This PR touches files that the TLA+ safety spec has an anchor on (per
docs/design/2026_05_28_implemented_tla_safety_spec.md §3),
so an AI review is requested below to verify the implementation has not drifted
from the model.

Anchored files changed in this PR head (d2b22ac):

  • distribution/engine.go
  • distribution/engine_test.go
  • distribution/split_job_catalog.go
  • kv/coordinator.go
  • kv/fsm.go
  • kv/sharded_coordinator.go

What to check, by subsystem:

  • kv/hlc*.goNext() must respect the HLC-4 preconditions (i)/(ii)/(iii) from the design doc: bounded skew, logical-counter handoff on leader change (strategy (c) Observe(MaxAppliedHLC)), and the commit-time ceiling fence (fail-closed when wall_now >= physicalCeiling). Any change to the bit layout (48/16), the CAS loop, or the ceiling getter/setter is in scope.
  • kv/coordinator.go, kv/sharded_coordinator.goRunHLCLeaseRenewal, hlcRenewalInterval, hlcPhysicalWindowMs constants, and the new-term detection that calls Observe(fsm.MaxAppliedHLC()) (strategy (c)). Any change to renewal cadence, group selection, or fail-closed behaviour is in scope.
  • kv/transaction.go, kv/lock_resolver.go — OCC commit-ts assignment, lock-map encoding (key, lock_ts) -> start_ts, and the LockResolver action OCC-3 depends on. (M2 spec will land OCC-1..OCC-5; until then the spec doc §5.2 is the contract.)
  • kv/fsm.go — FSM apply of HLC lease entries (SetPhysicalCeiling), and any future MaxAppliedHLC() accessor that strategy (c) needs.
  • store/mvcc_store.go — version visibility, snapshot install, and the MVCC-1..MVCC-4 invariants (M3 scope).
  • distribution/** — route catalog versioning, SplitRange atomicity, and CatalogWatcher async fan-out (M4 scope).

If the change is correct but requires a spec update, edit tla/hlc/HLC.tla (or the corresponding M2..M5 module once landed) and the design doc in the same PR. The tla-check workflow runs the TLC model check on the same paths.


@claude review please verify TLA+ spec divergence per the checklist above.

@codex review please verify TLA+ spec divergence per the checklist above.

@chatgpt-codex-connector

Copy link
Copy Markdown

To use Codex here, create a Codex account and connect to github.

@bootjp

bootjp commented Jul 15, 2026

Copy link
Copy Markdown
Owner Author

@codex review

Updated in d2b22ac:

  • Added raw TCP forwarding for redis-only proxy mode and deployed it on 192.168.0.64:6379.
  • Added pprof support for redis-proxy and bounded retry for transient secondary retry-limit/write-conflict/read-compacted failures.
  • Reduced raft restart/snapshot pressure and tightened snapshot skip/retention behavior.
  • Tuned HLC renewal and Redis SET/ZSet replacement paths covered by regression tests.

Validation:

  • go test ./proxy ./cmd/redis-proxy -count=1 -timeout=180s
  • go test ./adapter ./proxy ./cmd/redis-proxy ./kv ./internal/raftengine/etcd ./monitoring -count=1 -timeout=300s
  • golangci-lint --config=.golangci.yaml run ./proxy ./cmd/redis-proxy --timeout=5m
  • commit hook: golangci-lint --config=.golangci.yaml run --fix

Runtime verification:

  • Deployed ghcr.io/bootjp/elastickv/redis-proxy:pr1087-d2b22acc-sec-retry-202607151946-amd64 to redis-proxy and redis-proxy-canary-dual on 192.168.0.64.
  • redis-cli -h 192.168.0.64 -p 6379 PING => PONG.
  • redis-benchmark -h 192.168.0.64 -p 6379 -n 10000 -c 50 -r 1000000 -t set,get,zadd --csv: SET 34965 rps, GET 34602 rps, ZADD 36232 rps.
  • Production proxy metrics: primary/secondary/shadow errors 0, async drops/backpressure 0.
  • Raft status after benchmark: n1 leader, n3/n5 followers, commit/applied/last_log all 109782709, fsm_pending 0.

@chatgpt-codex-connector

Copy link
Copy Markdown

Codex Review: Didn't find any major issues. Bravo.

Reviewed commit: d2b22acc76

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

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