Skip to content

migration: promote staged versions#1089

Open
bootjp wants to merge 16 commits into
design/hotspot-split-m2-cross-groupfrom
design/hotspot-split-m2-promote
Open

migration: promote staged versions#1089
bootjp wants to merge 16 commits into
design/hotspot-split-m2-cross-groupfrom
design/hotspot-split-m2-promote

Conversation

@bootjp

@bootjp bootjp commented Jul 13, 2026

Copy link
Copy Markdown
Owner

Summary

  • add target-local PromotionState for staged MVCC promotion progress
  • add memory and Pebble promotion primitives that copy staged rows to live keys and physically remove promoted staged rows in one apply
  • add a Raft FSM command plus Internal.PromoteStagedVersions RPC
  • preserve commit_ts, tombstones, and TTL metadata during promotion

Tests

  • go test ./store ./kv ./adapter -run 'Test(PromoteVersions|ApplyMigrationPromote|MigrationPromoteTargetKey|InternalPromoteStagedVersions|InternalImportRangeVersions|ExportVersions|ImportVersions|FSMApplyBatchKeepsPerRequestResults)'\n- go test ./store\n- go test ./kv\n- go test -run '^$' ./...\n- GOCACHE=$(pwd)/.cache GOLANGCI_LINT_CACHE=$(pwd)/.golangci-cache golangci-lint run ./store ./kv ./adapter --timeout=5m\n\nAuthor: bootjp

@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: 10fe9348-893a-44b1-98e1-8703ea6372ba

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.

@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 (0df13a2):

  • kv/fsm.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

Validation for latest head 0df13a2:

  • go test ./store ./kv ./adapter -run 'Test(PromoteVersions|ApplyMigrationPromote|MigrationPromoteTargetKey|InternalPromoteStagedVersions|InternalImportRangeVersions|ExportVersions|ImportVersions|FSMApplyBatchKeepsPerRequestResults)'\n- go test ./store\n- go test ./kv\n- go test ./adapter -run 'TestInternal|TestDistribution|TestMigration'\n- go test -run '^$' ./...\n- golangci-lint run ./store ./kv ./adapter --timeout=5m

@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 a new feature to promote staged range-migration data into the live keyspace, adding the PromoteStagedVersions gRPC endpoint, a new Raft FSM command, and implementing the MigrationPromoter interface for both mvccStore and pebbleStore. While the implementation is well-tested, a critical issue was identified in store/migration_promote.go where a slice stored in the B-tree is mutated in-place during version removal. This can lead to data races or corruption for concurrent readers, and should be resolved by allocating a new slice and copying the elements instead.

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 store/migration_promote.go Outdated
if idx < 0 {
return false
}
versions = append(versions[:idx], versions[idx+1:]...)

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.

high

Mutating the versions slice in-place using append on versions[:idx] modifies the underlying array of the slice stored in the B-tree. Since this slice may be concurrently accessed or held by active iterators/readers (even if protected by s.mtx during the mutation, readers might have already obtained a reference to the slice), in-place mutation can lead to data races or unexpected data corruption. To ensure safety, allocate a new slice and copy the elements instead of mutating the existing slice's underlying array.

	newVersions := make([]VersionedValue, len(versions)-1)
	copy(newVersions, versions[:idx])
	copy(newVersions[idx:], versions[idx+1:])
	versions = newVersions

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

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

Fixed in b4f2477 by allocating a fresh version slice before removing the promoted staged version, so the tree-held backing array is not mutated in place.

@bootjp bootjp force-pushed the design/hotspot-split-m2-promote branch from 0df13a2 to 8c59f29 Compare July 13, 2026 15:52
@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 (8c59f29):

  • kv/fsm.go
  • store/mvcc_store.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

Validation for latest head 8c59f29:

  • go test ./store ./kv ./adapter -run 'Test(PromoteVersions|ApplyMigrationPromote|MigrationPromoteTargetKey|InternalPromoteStagedVersions|InternalImportRangeVersions|ExportVersions|ImportVersions|FSMApplyBatchKeepsPerRequestResults)'
  • go test ./store
  • go test ./kv
  • go test -run '^$' ./...
  • golangci-lint run ./store ./kv ./adapter --timeout=5m

@chatgpt-codex-connector

Copy link
Copy Markdown

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

@bootjp bootjp force-pushed the design/hotspot-split-m2-promote branch from 8c59f29 to b4f2477 Compare July 13, 2026 15:54
@bootjp

bootjp commented Jul 13, 2026

Copy link
Copy Markdown
Owner Author

@codex review

Validation for latest head b4f2477:

  • go test ./store -run 'TestPromoteVersions'
  • golangci-lint run ./store ./kv ./adapter --timeout=5m

@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 (b4f2477):

  • kv/fsm.go
  • store/mvcc_store.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: b4f247751b

ℹ️ 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 store/migration_promote.go Outdated
return errors.WithStack(err)
}
}
if err := batch.Commit(s.directApplyWriteOpts()); 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 Persist applied index with promotion batches

When this path is reached from kvFSM.applyMigrationPromote, the batch has copied live versions and deleted staged rows but commits without writing metaAppliedIndex for f.pendingApplyIdx, unlike the other Raft data paths (ApplyMutationsRaftAt / DeletePrefixAtRaftAt). On disk-backed groups whose post-snapshot traffic is only promotion chunks, LastAppliedIndex stays behind the committed WAL tail, so every restart misses the cold-start skip gate and restores/replays the full FSM snapshot until some unrelated write or snapshot advances the meta key. Thread the apply index through promotion and include it in this batch.

Useful? React with 👍 / 👎.

@bootjp

bootjp commented Jul 13, 2026

Copy link
Copy Markdown
Owner Author

Addressed latest promotion applied-index feedback in c1afe27:

  • thread the Raft apply index from migration promotion apply into PromoteVersionsOptions
  • persist metaAppliedIndex in the same Pebble batch as promoted live versions, staged deletes, and promotion state
  • add Pebble coverage for promotion batches updating LastAppliedIndex

Validation:

  • go test ./store -run 'Test(PromoteVersions|ApplyMutationsRaftAt|DeletePrefixAtRaftAt)'\n- go test ./kv -run 'TestApplyMigrationPromote'\n- go test ./store ./kv\n- go test -run '^$' ./...\n- GOCACHE=$(pwd)/.cache GOLANGCI_LINT_CACHE=$(pwd)/.golangci-cache golangci-lint run ./store ./kv --timeout=5m\n- git diff --check\n\n@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 (c1afe27):

  • kv/fsm.go
  • store/mvcc_store.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: c1afe27060

ℹ️ 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 store/migration_promote.go Outdated
Comment on lines +220 to +221
if opts.JobID != 0 && state.Done {
return PromoteVersionsResult{Done: true, TotalPromotedRows: state.PromotedRows}, 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 Persist applied index for completed promotions

When a retry/controller proposes another PromoteStagedVersions entry after the job state is already Done, this Pebble path returns before commitPebblePromoteVersions, so opts.AppliedIndex is never written to metaAppliedIndex. The promotion is idempotent, but LastAppliedIndex remains at the previous entry, so the cold-start skip gate can replay this log entry on every restart until a later mutating entry advances the meta key; persist the applied index in this no-op branch too.

Useful? React with 👍 / 👎.

Comment thread kv/fsm.go
@bootjp

bootjp commented Jul 13, 2026

Copy link
Copy Markdown
Owner Author

Addressed current-head promotion blockers in dd52db8.

Changes:

  • completed Pebble promotion retries now persist metaAppliedIndex when AppliedIndex is provided
  • PromoteStagedVersions is gated before proposing 0x0b entries; default gate stays closed until ELASTICKV_ENABLE_MIGRATION_PROMOTE_OPCODE is enabled after rollout
  • migration promote apply failures now return HaltApply-marked errors instead of ordinary apply errors

Validation:

  • go test ./store -run 'TestPromoteVersions_BundlesMetaAppliedIndex|Test(PromoteVersions|MigrationPromotion)'
  • go test ./kv -run 'TestApplyMigrationPromote|TestMigrationPromote'
  • go test ./adapter -run 'TestInternalPromoteStagedVersions|TestInternalImportRangeVersions'
  • go test ./store -run '^TestPebbleStore_RestoreWaitsForMaintenanceLock$' -count=1
  • go test ./adapter -run '^TestInternalPromoteStagedVersions' -count=1
  • git diff --check

Note: attempted go test ./store ./kv ./adapter; kv passed, store hit a timeout in TestPebbleStore_RestoreWaitsForMaintenanceLock during the combined run, and that exact test passed when rerun alone.

@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 (dd52db8):

  • kv/fsm.go
  • store/mvcc_store.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: dd52db8198

ℹ️ 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 store/migration_promote.go Outdated
for _, version := range versions {
targets = append(targets, version.target)
}
if err := s.applyImportVersionsBatch(batch, targets); 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.

P1 Badge Keep promotion applies off the direct-write gate

When storage envelopes are active and this node has not yet marked its writer registration for the active DEK, this call routes promoted live values through applyImportVersionsBatch, which invokes encryptForKey(..., true) and returns ErrWriterNotRegistered. Unlike direct writes, promotion is applied from the Raft FSM (applyMigrationPromote), and the existing Raft apply path explicitly passes gateRegistration=false so committed entries can replay deterministically before local registration catches up; with the new HaltApply wrapping, a promotion chunk containing any non-tombstone value can halt the apply loop on such replicas during an encrypted migration.

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 (b04d30f):

  • kv/fsm.go
  • store/mvcc_store.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

Addressed current-head P1 promotion gate feedback in b04d30f.

Changes:

  • threaded the writer-registration gate choice through applyImportVersionsBatch
  • kept migration import on its existing gate behavior
  • promotion now applies promoted target versions with gateRegistration=false so Raft replay is not blocked by this node's local writer-registration state
  • added encrypted registration-gate regression coverage for PromoteVersions

Validation:

  • go test ./store -run '^TestRegistrationGate_PromoteVersionsNeverGated$' -count=1
  • go test ./store -run 'TestRegistrationGate|TestPromoteVersions|TestMigrationPromotion|TestPromoteVersions_BundlesMetaAppliedIndex' -count=1
  • go test ./kv -run 'TestApplyMigrationPromote|TestMigrationPromote' -count=1
  • go test ./adapter -run 'TestInternalPromoteStagedVersions|TestInternalImportRangeVersions' -count=1
  • go test -run '^$' ./...
  • golangci-lint run ./... --timeout=5m
  • git diff --check

Note: attempted go test ./...; adapter package timed out after 10m while unrelated full-package network/raft adapter tests were still running. The targeted adapter migration tests above passed, and the all-package compile-only check passed.

@codex review

@chatgpt-codex-connector

Copy link
Copy Markdown

Codex Review: Didn't find any major issues. You're on a roll.

Reviewed commit: b04d30fe3c

ℹ️ 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 (a9c9afe):

  • kv/fsm.go
  • store/mvcc_store.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. Chef's kiss.

Reviewed commit: a9c9afef3b

ℹ️ 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 (5254a43):

  • kv/fsm.go
  • store/mvcc_store.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

Resolved the merge conflict against design/hotspot-split-m2-cross-group in 5254a43.

Integrated the newer exact-key migration metadata/export cursor changes with the staged promotion implementation by keeping promotion state under the reserved _migpromote metadata key and preserving the normalized export cursor path for promotion scans.

Validation:

  • go test ./store -run 'Test(ExportVersions|PebbleExport|ImportVersions|PromoteVersions|PebblePromoteVersions|PebbleImportMetadataPersistsAcrossReopen|PebbleSnapshotPreservesMigrationMetadata|PebbleWriterRegistry|PebbleRejectsMVCCKey)' -count=1 -timeout=240s
  • go test ./store ./kv ./adapter ./distribution ./internal/backup ./internal/s3keys -count=1 -timeout=300s (store/kv/distribution/internal passed; full adapter package timed out)
  • go test ./adapter -run 'Test(Milestone1SplitRange|DistributionServer|BuildCatalogSplitOps|GRPCServer_Raw|Internal(ExportRangeVersions|ImportRangeVersions|PromoteStagedVersions))' -count=1 -timeout=240s
  • golangci-lint --config=.golangci.yaml run ./store ./kv ./adapter ./distribution ./internal/backup ./internal/s3keys --timeout=5m
  • git diff --check HEAD

@codex review

@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: 5254a4330d

ℹ️ 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".

if endKey != nil && bytes.Compare(pos.key, endKey) >= 0 {
return errors.WithStack(ErrInvalidExportCursor)
}
return 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.

P1 Badge Reject skipped-key cursors before proposing promotion

When the supplied cursor uses the skipped-key tag for a key inside the staged prefix, this helper returns nil because it only checks bounds. PromoteStagedVersions then proposes the command, but the FSM path revalidates through ExportVersions/validateExportCursorRange and treats the same cursor as ErrInvalidExportCursor, which applyMigrationPromote wraps as a halting apply error. With the promote opcode gate enabled, a malformed or buggy cursor can therefore be committed to Raft and halt apply instead of being rejected as InvalidArgument before propose; mirror the skipped-cursor rule used by the store here.

Useful? React with 👍 / 👎.

Comment thread store/migration_promote.go Outdated
if opts.JobID == 0 {
return PromotionState{}, opts.Cursor
}
state := clonePromotionState(s.migrationPromotions[opts.JobID])

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 Clear restored promotion state before resuming jobs

For an in-memory store that snapshots before promotion, then later records migrationPromotions[jobID] and restores that snapshot on the same store, restoreStreamingSnapshot replaces the tree and clears the import/HLC maps but leaves this promotion map intact. This lookup can then reuse a cursor or Done bit from the pre-restore timeline, so a restored staged range for the same job may be reported done or resumed mid-range and never promoted; reset the promotion map during restore like the other migration metadata.

Useful? React with 👍 / 👎.

Comment thread adapter/internal.go Outdated

func validatePromoteStagedVersionsRequest(req *pb.PromoteStagedVersionsRequest) error {
prefix := distribution.MigrationStagedDataKeyPrefix(req.GetJobId())
if err := store.ValidateExportCursorForRange(req.GetCursor(), prefix, store.PrefixScanEnd(prefix)); 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.

P1 Badge Restrict promotion cursors to emitted positions

This RPC accepts any decoded cursor that falls inside the staged prefix, but promotion scans never legitimately return scanned/pruned cursor tags because they have no key filter or min-timestamp pruning. If a retry or controller bug passes one of those cursors, the store interprets it as already-processed state: scanned skips that exact staged version, and pruned skips the rest of the staged key, allowing promotion to finish while leaving rows unpromoted. Validate that promotion cursors are empty or emitted cursors before proposing the Raft command.

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 (b1381f3):

  • kv/fsm.go
  • store/mvcc_store.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 14, 2026

Copy link
Copy Markdown
Owner Author

Addressed the current-head promotion blockers in b1381f3.

Changes:

  • reject skipped-key cursors inside the requested range and restrict promotion resume cursors to empty or emitted positions before proposing to Raft
  • reject scanned/pruned/skipped promotion cursors at the Internal RPC boundary with InvalidArgument
  • clear restored in-memory promotion state during MVCC snapshot restore and cover same-job resume after restore

Validation:

  • go test ./store ./adapter -run 'Test(ValidateExportCursorForRangeRejectsSkippedCursorInsideRange|ValidatePromotionCursorForRangeAcceptsOnlyEmittedPositions|MVCCStore_RestoreClearsMigrationMetadata|InternalPromoteStagedVersionsRejectsInvalidCursorBeforePropose)' -count=1 -timeout=240s
  • go test ./store ./kv ./adapter -run 'Test(ExportVersions|ValidateExportCursor|ValidatePromotionCursor|PromoteVersions|PebblePromoteVersions|MVCCStore_RestoreClearsMigrationMetadata|ApplyMigrationPromote|MigrationPromote|InternalPromoteStagedVersions)' -count=1 -timeout=240s
  • go test ./store -count=1 -timeout=300s
  • golangci-lint --config=.golangci.yaml run ./store ./adapter --timeout=5m
  • git diff --check

@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: b1381f3afb

ℹ️ 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".

if !exportSkippedCursorOutsideRange(opts, pos.key) {
return errors.WithStack(ErrInvalidExportCursor)
}
return 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 Keep skipped cursors from resuming before the range

This accepts a skipped-key cursor whose key is below startKey, but the in-memory exporter resumes from pos.key whenever a cursor is present and only treats PrunedKey as a whole-key skip. If that below-range key has older versions than the cursor timestamp, those older versions are emitted despite the requested start bound (for example, StartKey=m with a skipped cursor for a@10 exports a@5). That can leak/import versions outside the migration bracket; either keep rejecting below-start skipped cursors or make the memory resume path skip the whole key and re-seek to the requested range.

Useful? React with 👍 / 👎.

Comment thread store/migration_promote.go Outdated
Comment on lines +128 to +130
if len(state.Cursor) == 0 {
return state, opts.Cursor
}

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 Ignore stale client cursors when promotion state is missing

When a job has no stored PromotionState (for example after the MVCC snapshot restore path clears migrationPromotions), this falls back to the caller-provided cursor. If the migration driver retries with the last NextCursor from before that restore while the restored snapshot still contains staged rows before that cursor, those rows are skipped and never promoted; a job-scoped promotion with absent local state needs to restart from the empty cursor/remaining staged rows rather than trusting a stale client cursor.

Useful? React with 👍 / 👎.

@bootjp

bootjp commented Jul 14, 2026

Copy link
Copy Markdown
Owner Author

@codex review

Merged latest design/hotspot-split-m2-cross-group into this branch in b4b8664 and resolved the adapter/internal.go + adapter/internal_migration_test.go conflicts.

Conflict resolution:

  • kept promote opcode gate and promotion cursor validation from this branch.
  • kept import job_id/bracket_id validation and S3 auxiliary route/export fixes from the updated base.
  • retained staged S3 auxiliary routing/read-key test coverage and promotion restore metadata tests.

Validation:

  • go test ./adapter ./kv ./store -run "Test(Internal(ExportRangeVersions|ImportRangeVersions|PromoteStagedVersions)|Validate(Export|Promotion)Cursor|PromoteVersions|PebblePromoteVersions|ApplyMigration(Promote|Import)|Migration(Promote|Import)|ShardedCoordinatorRoutesS3BucketAuxiliaryWriteToStagedOwner|GroupReadKeysByShardID_RoutesS3BucketAuxiliaryToStagedOwner|ShardStore.*Staged|MVCCStore_RestoreClearsMigrationMetadata)" -count=1 -timeout=240s
  • golangci-lint --config=.golangci.yaml run ./adapter ./kv ./store --timeout=5m
  • git diff --check / git diff --cached --check

@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 (b4b8664):

  • kv/fsm.go
  • store/mvcc_store.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: b4b8664c84

ℹ️ 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 on lines +305 to +307
state.Cursor = bytes.Clone(exported.NextCursor)
state.Done = exported.Done
state.PromotedRows += promoted.PromotedRows

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 Persist promoted timestamp floor across retries

When a promotion chunk commits, the store persists only the cursor/done/row count, while applyMigrationPromote observes MaxPromotedTS only after PromoteVersions returns. If the process crashes after the Pebble batch commits but before that observe, the retry resumes from this persisted cursor and never reports the skipped chunk's max timestamp again; when imported source timestamps are ahead of the local clock, the leader can later issue commit timestamps below already-promoted live versions. The promotion resume state needs to carry the max promoted timestamp (or otherwise return a durable floor) just like import retries do.

Useful? React with 👍 / 👎.

Comment thread store/migration_promote.go Outdated
Comment on lines +321 to +322
if !ok || len(state.Cursor) == 0 {
return state, opts.Cursor, 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.

P1 Badge Reject client cursors before promotion state exists

When there is no target-local promotion state yet, this trusts the request cursor as the starting point. The RPC-side check only proves that the cursor decodes to an emitted position inside the job prefix, so a first PromoteStagedVersions call with a later valid cursor can skip all earlier staged MVCC rows, then persist progress/done from that point. The target can report promotion complete while the skipped staged rows were never copied to live, which becomes data loss once staged visibility is cleared.

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 (40c2f52):

  • kv/fsm.go
  • store/mvcc_store.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 14, 2026

Copy link
Copy Markdown
Owner Author

@codex review

Addressed current-head stale promotion cursor handling in 40c2f52.

Changes:

  • job-scoped memory/Pebble promotion now restart from the target-local state when present and from an empty cursor when state is missing, instead of trusting a stale caller cursor.
  • added memory/Pebble regression coverage that passes a stale in-range cursor with no PromotionState and verifies all staged rows are promoted.

Validation:

  • go test ./store -run 'Test(PromoteVersionsIgnoresClientCursorWhenStateMissing|PromoteVersionsMovesStagedVersionsAndDeletesStagedRows|PebblePromoteVersionsAdvancesLastCommitTS|ValidatePromotionCursorForRangeAcceptsOnlyEmittedPositions)' -count=1 -timeout=240s
  • go test ./store -count=1 -timeout=300s
  • go test ./adapter ./kv ./store -run 'Test(InternalPromoteStagedVersionsRejectsWhenOpcodeGateClosed|InternalPromoteStagedVersionsRejectsInvalidCursorBeforePropose|ApplyMigrationPromote|MigrationPromote|ValidateExportCursorForRangeRejectsSkippedCursorInsideRange|ValidatePromotionCursorForRangeAcceptsOnlyEmittedPositions|PromoteVersionsIgnoresClientCursorWhenStateMissing|PromoteVersionsMovesStagedVersionsAndDeletesStagedRows|PebblePromoteVersionsAdvancesLastCommitTS|MVCCStore_RestoreClearsMigrationMetadata)' -count=1 -timeout=240s
  • golangci-lint --config=.golangci.yaml run ./store --timeout=5m
  • git diff --check / git diff --cached --check

@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 (327cb1c):

  • kv/fsm.go
  • store/mvcc_store.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

Synced PR #1089 with latest origin/design/hotspot-split-m2-cross-group at 19a28e9 via merge commit 327cb1c.

Current head includes the stale promotion cursor fix from 40c2f52:

  • job-scoped memory/Pebble promotion now uses target-local PromotionState when present and restarts from an empty cursor when that state is missing, instead of trusting a stale caller cursor.
  • regression coverage verifies stale in-range client cursors do not skip staged rows when PromotionState is absent.

Validation after the base merge:

  • go test ./adapter ./kv ./store -run 'Test(InternalPromoteStagedVersionsRejectsWhenOpcodeGateClosed|InternalPromoteStagedVersionsRejectsInvalidCursorBeforePropose|ApplyMigrationPromote|MigrationPromote|ValidateExportCursorForRangeRejectsSkippedCursorInsideRange|ValidatePromotionCursorForRangeAcceptsOnlyEmittedPositions|PromoteVersionsIgnoresClientCursorWhenStateMissing|PromoteVersionsMovesStagedVersionsAndDeletesStagedRows|PebblePromoteVersionsAdvancesLastCommitTS|MVCCStore_RestoreClearsMigrationMetadata|ShardedCoordinatorRoutesS3BucketAuxiliaryWriteToStagedOwner|GroupReadKeysByShardID_RoutesS3BucketAuxiliaryToStagedOwner|ShardStore(GetAt_MergesStagedVisibilityForS3BucketAuxiliary|ScanAt_ContinuesStagedVisibilityAfterCandidateWindow|ScanAtRestrictsStagedVisibilityToSafeFrontier|ExplicitGroupReads_MergeStagedVisibility))' -count=1 -timeout=240s
  • go test ./kv -count=1 -timeout=300s
  • golangci-lint --config=.golangci.yaml run ./kv ./store --timeout=5m
  • git diff --check

@bootjp

bootjp commented Jul 14, 2026

Copy link
Copy Markdown
Owner Author

@codex review

Merged latest design/hotspot-split-m2-cross-group into this branch in 4b1d950 after the #1088 base advanced.

Validation:

  • go test ./store ./kv -run "Test(PromoteVersionsIgnoresClientCursorWhenStateMissing|PromoteVersionsMovesStagedVersionsAndDeletesStagedRows|PebblePromoteVersionsAdvancesLastCommitTS|ValidatePromotionCursorForRangeAcceptsOnlyEmittedPositions|ShardStore.*Raft|ApplyMutationsRaft|DeletePrefixAtRaft)" -count=1 -timeout=240s
  • go test ./adapter ./distribution -run "Test(DistributionServer(GetRouteOwnership|GetIntersectingRoutes|OwnershipRPCs|SplitRange)|RouteHistorySnapshot|EngineSnapshotAt|EngineGetIntersectingRoutes)" -count=1 -timeout=240s
  • golangci-lint --config=.golangci.yaml run ./adapter ./distribution ./kv ./store --timeout=5m
  • git diff --check

@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 (4b1d950):

  • kv/fsm.go
  • store/mvcc_store.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

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

Reviewed commit: 4b1d950f97

ℹ️ 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