Skip to content

distribution: add migration wire contracts#1084

Open
bootjp wants to merge 26 commits into
mainfrom
design/hotspot-split-m2-wire
Open

distribution: add migration wire contracts#1084
bootjp wants to merge 26 commits into
mainfrom
design/hotspot-split-m2-wire

Conversation

@bootjp

@bootjp bootjp commented Jul 13, 2026

Copy link
Copy Markdown
Owner

Summary

  • add M2 migration RPCs and internal export/import wire contracts, with generated protobuf code
  • add RouteDescriptor migration fields to protobuf and durable route codec v2 while preserving v1 encoding for zero-field routes
  • plumb migration route fields through ListRoutes responses and cover the codec/protobuf conversion paths

Tests

  • make -C proto check-tools
  • make -C proto gen
  • go test ./distribution -count=1 -timeout=120s
  • go test ./adapter -run 'TestDistributionServer|TestMilestone1SplitRange' -count=1 -timeout=180s
  • go test ./kv ./proto -count=1 -timeout=180s
  • GOCACHE=$(pwd)/.cache GOLANGCI_LINT_CACHE=$(pwd)/.golangci-cache golangci-lint run ./distribution ./adapter --timeout=5m
  • git diff --check

Note: full adapter-package testing exceeded the local timeout in existing raft/gRPC integration coverage; the targeted distribution adapter tests above passed.

Author: bootjp

Summary by CodeRabbit

  • 新機能
    • ルート分割移行の新RPC(開始、所有者/交差ルート取得、ジョブ一覧、再試行・中止)に対応。
    • MVCC範囲バージョンのエクスポート/インポートを追加。
    • 読み取りフェンス付きRawGet/RawLatestCommitTS/RawScanAtで、ルート境界付きの読み取りに対応。
  • 改善
    • 分割・移行中ルートのメタデータ(staged visibility / migration job / min write ts)を保存・復元・応答まで一貫反映。
    • ルート境界付き逆方向スキャンの許容範囲を読み取りフェンス有効時に条件付き最適化。
  • テスト
    • ルート境界・フェンス・分割移行メタデータ等の検証を追加/拡充。

@coderabbitai

coderabbitai Bot commented Jul 13, 2026

Copy link
Copy Markdown

Review Change Stack

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

Changes

ルート移行メタデータ

Layer / File(s) Summary
移行APIとルート契約
proto/distribution.proto, proto/internal.proto
分割移行、分割ジョブ、MVCC範囲転送RPCと移行状態フィールドを追加します。
カタログcodecと保存処理
distribution/catalog.go, distribution/catalog_test.go
RouteDescriptorのv1/v2 codec、移行フィールドの検証・比較・clone、MinWriteTSExclusiveの単調保存を追加します。
エンジンとDistributionへの伝播
distribution/engine.go, distribution/engine_test.go, adapter/distribution_server.go, adapter/distribution_server_test.go
移行フィールドをEngine、分割後ルート、Distributionのprotobuf応答へ伝播します。

読み取りフェンス付きルーティング

Layer / File(s) Summary
読み取りフェンスRPC契約
proto/service.proto
Raw読み取りリクエストにread route versionとルート境界情報を追加します。
gRPC Raw読み取り分岐
adapter/grpc.go, adapter/grpc_test.go
read fence対応ストアを優先し、route version・境界の決定とgrouped reverseの検証を行います。
LeaderRoutedStoreのフェンス読み取り
kv/leader_routed_store.go, kv/leader_routed_store_test.go
ローカル読み取りとRaw RPCフォールバックをread fence対応APIへ拡張します。
ShardStoreの境界付きスキャン
kv/shard_store.go, kv/shard_store_test.go, kv/shard_store_txn_lock_test.go
境界付き順方向・逆方向スキャン、ルートフィルタ、ロック走査、read route version伝播を追加します。

Redisキー正規化

Layer / File(s) Summary
Redis wide-columnキーの正規化
kv/shard_key.go, kv/shard_key_test.go
Hash、Set、ZSetの内部キーを共通のユーザーキーへ正規化します。

Estimated code review effort: 5 (Critical) | ~120 minutes

Sequence Diagram(s)

sequenceDiagram
  participant Client
  participant GRPCServer
  participant LeaderRoutedStore
  participant ShardStore
  Client->>GRPCServer: RawScanAt(read route version, route bounds)
  GRPCServer->>LeaderRoutedStore: ScanAtWithReadFence
  LeaderRoutedStore->>ShardStore: 境界付きローカルスキャンまたはRaw RPC
  ShardStore-->>LeaderRoutedStore: フェンス済みKV結果
  LeaderRoutedStore-->>GRPCServer: ScanAt結果
  GRPCServer-->>Client: RawScanAt応答
Loading

Possibly related PRs

  • bootjp/elastickv#1065: RawScanAt のKeysOnly経路と rawScanKeysAt への委譲が関連します。
  • bootjp/elastickv#1117: RouteDescriptor v2とカタログ移行フィールドの変更が、カタログdeltaの公開・適用処理と関連します。
🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 1.28% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed タイトルは移行用のワイヤ契約追加という主要変更を簡潔に表しており、変更内容と一致しています。
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

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 (72fcc6b):

  • distribution/catalog.go
  • distribution/catalog_test.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.

@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 V2 codec version for route descriptors in the distribution catalog to support new migration-related fields, including staged visibility, migration job IDs, and exclusive write timestamps. It also updates protobuf definitions and generated gRPC code to add several new RPC methods (such as split migration and range version export/import) and includes read route versions for migration read fences. The review feedback suggests defining an explicit catalogRouteCodecVersionV2 constant instead of using the dynamic catalogRouteCodecVersion directly in encoding and decoding paths, which prevents future codec version bumps from breaking V2-specific logic.

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/catalog.go Outdated
Comment thread distribution/catalog.go Outdated
Comment thread distribution/catalog.go Outdated
@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 (7dd2e6d):

  • distribution/catalog.go
  • distribution/catalog_test.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: 7dd2e6d48a

ℹ️ 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 distribution/catalog.go
Comment thread proto/service.proto Outdated
Comment thread distribution/catalog.go
@bootjp

bootjp commented Jul 13, 2026

Copy link
Copy Markdown
Owner Author

@codex review

Addressed current-head blockers in ef2ba76:

  • preserved MinWriteTSExclusive and migration fields when splitting/catalog snapshotting routes
  • carried migration fields into distribution.Route snapshots and stats/intersection paths
  • forwarded read_route_version and scan route bounds through raw read proxy hops

Validation:

  • go test ./adapter -run 'TestDistributionServerSplitRange_Success|TestDistributionServerListRoutes_ReadsDurableCatalog' -count=1
  • go test ./distribution -count=1
  • go test ./kv -count=1
  • go test ./adapter ./distribution ./kv -run '^$' -count=1
  • golangci-lint --config=.golangci.yaml run ./adapter ./distribution ./kv --timeout=5m
  • git diff --check HEAD~1..HEAD

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

  • distribution/catalog.go
  • distribution/catalog_test.go
  • distribution/engine.go
  • distribution/engine_test.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 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: ef2ba76416

ℹ️ 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/shard_store.go
Comment thread distribution/catalog.go Outdated
Comment thread adapter/grpc.go Outdated
var err error
if groupID := req.GetGroupId(); groupID != 0 {
if fenceGetter, ok := r.store.(rawReadFenceGetter); ok {
v, err = fenceGetter.GetAtWithReadFence(ctx, req.Key, readTS, req.GetGroupId(), req.GetReadRouteVersion())

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 Stamp raw reads before using the fence helper

External RawKV callers leave read_route_version unset, but this branch passes that zero straight into the fenced store path instead of stamping the catalog version observed while routing the request. When this server is a follower and proxies the read during a split migration, the internal RawGet still carries version 0, so the source-side cutover fence either treats a fresh routed read as a broken legacy hop once zero-version rejection is active or cannot distinguish it from a stale coordinator request; stamp the current route/catalog version before invoking the fence helper.

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 (2388b3e):

  • distribution/catalog.go
  • distribution/catalog_test.go
  • distribution/engine.go
  • distribution/engine_test.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

Addressed the current-head blockers in 2388b3e:

  • routed fenced ShardStore scans using supplied route_start/route_end while keeping the raw scan bounds for storage reads
  • kept CatalogStore MinWriteTSExclusive monotone by merging existing and desired descriptors with max(existing, desired)
  • stamped zero read_route_version at the RawKV gRPC entrypoint before invoking read-fence helper paths, while preserving caller-supplied stamps

Validation:

  • go test ./kv ./distribution ./adapter -run 'TestShardStoreScanAtWithReadFence_RoutesUsingSuppliedBounds|TestCatalogStoreSaveKeepsMinWriteTSExclusiveMonotone|TestGRPCServer_RawReadFenceHelpersStampCurrentRouteVersion|TestGRPCServer_RawReadFenceHelpersKeepCallerRouteVersion' -count=1
  • git diff --check
  • golangci-lint run ./... --timeout=5m --allow-serial-runners
  • commit hook: golangci-lint --config=.golangci.yaml run --fix (0 issues)
  • go test ./... was run: the initial parallel run failed with no space left on device; the retry with TMPDIR=.tmp GOTMPDIR=.tmp GOCACHE=.gocache go test -p=1 ./... passed root/distribution/kv/store and remaining packages, but adapter timed out at 600s

@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: 2388b3e665

ℹ️ 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/shard_store.go Outdated
Comment thread adapter/grpc.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 (781dc36):

  • distribution/catalog.go
  • distribution/catalog_test.go
  • distribution/engine.go
  • distribution/engine_test.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

Addressed the current-head fenced raw scan findings in 781dc36:

  • preserved InvalidArgument for RawScanAt requests that combine group_id and reverse before the read-fence helper path can handle them
  • deduplicated same-group ShardStore read-fence scans only when supplied route_start/route_end causes raw storage bounds to be reused across adjacent descriptors

Validation:

  • go test ./adapter ./kv -run TestGRPCServer_RawScanAt_GroupedReverseStaysInvalidArgumentWithReadFenceStore|TestShardStoreScanAtWithReadFence_DeduplicatesSameGroupSuppliedBounds|TestShardStoreScanAtWithReadFence_RoutesUsingSuppliedBounds|TestGRPCServer_RawReadFenceHelpersStampCurrentRouteVersion|TestGRPCServer_RawReadFenceHelpersKeepCallerRouteVersion -count=1
  • golangci-lint --config=.golangci.yaml run ./adapter ./kv --timeout=5m
  • git diff --check HEAD~1..HEAD
  • commit hook: golangci-lint --config=.golangci.yaml run --fix (0 issues)

@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: 781dc362ec

ℹ️ 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/shard_store.go
Comment thread kv/shard_store.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 (1afde8f):

  • distribution/catalog.go
  • distribution/catalog_test.go
  • distribution/engine.go
  • distribution/engine_test.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

Fixed the two RawScanAt fence findings:

  • Added explicit route-bound presence on RawScanAt and threaded it through ShardStore/LeaderRoutedStore proxy requests so the logical ["", +infinity) range survives proto3 empty bytes.
  • Added route-key-filtered pagination for supplied-bound scans so same-group sibling route rows are skipped without leaking rows or short-filling pages.

Caller audit:

  • rg "ScanAtWithReadFence\(" only finds the adapter RawScanAt path, ShardStore/LeaderRoutedStore proxy paths, and tests; no broader call sites required API changes.

Validation:

  • go test ./kv
  • go test ./adapter -run "TestGRPCServer_RawScanAt_PreservesFullRangeRouteBoundsPresence|TestGRPCServer_RawReadFenceHelpersKeepCallerRouteVersion|TestGRPCServer_RawScanAt_GroupedReverseStaysInvalidArgumentWithReadFenceStore" -count=1
  • golangci-lint run ./adapter ./kv --timeout=5m
  • git diff --check
  • buf generate

@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: 1afde8f1ba

ℹ️ 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/leader_routed_store.go Outdated
Comment on lines +222 to +226
if reverse {
kvs, err := s.local.ReverseScanAt(ctx, start, end, limit, max(ts, fenceTS))
return kvs, errors.WithStack(err)
}
kvs, err := s.local.ScanAt(ctx, start, end, limit, max(ts, fenceTS))

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 Honor route bounds on local leader scans

When this store is the verified local leader and a RawScanAt/ScanAtWithReadFence call supplies routeStart/routeEnd, these branches read the local MVCC store directly and never apply the route-key filter/pagination that the ShardStore path uses. In a leader-routed deployment receiving a supplied-bound scan over an internal raw prefix, rows from same-group sibling route intervals can be returned or consume the page limit, while the non-leader proxy path preserves the bounds.

Useful? React with 👍 / 👎.

Comment thread kv/shard_store.go Outdated
scanEnd := end
for len(out) < limit {
batchLimit := routeFilteredScanBatchLimit(limit - len(out))
kvs, err := s.scanRouteAtDirectionWithReadFenceOnce(ctx, route, scanStart, scanEnd, batchLimit, ts, reverse, explicitGroup, readRouteVersion, routeStart, routeEnd)

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 Filter route keys before resolving scan locks

For supplied-bound scans on a local ShardStore leader, this call resolves MVCC/txn locks for the raw batch before appendRouteFilteredKVs drops rows whose routeKey is outside routeStart/routeEnd. If a same-group sibling route has a pending lock under the scanned raw prefix, the bounded scan can return ErrTxnLocked or hit the lock budget even though that sibling row should be skipped by the route filter.

Useful? React with 👍 / 👎.

@coderabbitai

coderabbitai Bot commented Jul 18, 2026

Copy link
Copy Markdown
✅ Action performed

Review finished.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@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: 65e2973b7e

ℹ️ 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/shard_store.go
Comment thread kv/shard_store.go Outdated
Comment thread kv/shard_store.go
Comment thread kv/shard_store.go

@coderabbitai coderabbitai 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.

Actionable comments posted: 3

🧹 Nitpick comments (1)
kv/shard_key.go (1)

98-114: 🚀 Performance & Scalability | 🔵 Trivial | ⚡ Quick win

スライスの再割り当てを防ぐため、プレフィックスをパッケージレベル変数として定義する

現在の実装では、スキャンのルーティング処理が呼び出されるたびに、[][]byteや内部の[]byteスライスが新しく割り当てられています。これをパッケージレベルの変数として切り出すことで、スキャン実行時の不要なアロケーションを削減し、パフォーマンスを改善できます。

♻️ 提案するリファクタリング
+var wideColumnScanPrefixes = [][]byte{
+	[]byte(store.HashMetaDeltaPrefix),
+	[]byte(store.HashMetaPrefix),
+	[]byte(store.HashFieldPrefix),
+	[]byte(store.SetMetaDeltaPrefix),
+	[]byte(store.SetMetaPrefix),
+	[]byte(store.SetMemberPrefix),
+	[]byte(store.ZSetMetaDeltaPrefix),
+	[]byte(store.ZSetMetaPrefix),
+	[]byte(store.ZSetMemberPrefix),
+	[]byte(store.ZSetScorePrefix),
+}
+
 func redisWideColumnScanRouteKey(key []byte) []byte {
-	for _, prefix := range [][]byte{
-		[]byte(store.HashMetaDeltaPrefix),
-		[]byte(store.HashMetaPrefix),
-		[]byte(store.HashFieldPrefix),
-		[]byte(store.SetMetaDeltaPrefix),
-		[]byte(store.SetMetaPrefix),
-		[]byte(store.SetMemberPrefix),
-		[]byte(store.ZSetMetaDeltaPrefix),
-		[]byte(store.ZSetMetaPrefix),
-		[]byte(store.ZSetMemberPrefix),
-		[]byte(store.ZSetScorePrefix),
-	} {
+	for _, prefix := range wideColumnScanPrefixes {
 		if user := wideColumnScanUserKey(key, prefix); user != nil {
 			return user
 		}
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@kv/shard_key.go` around lines 98 - 114, Update redisWideColumnScanRouteKey to
reuse a package-level prefix collection instead of constructing the [][]byte and
[]byte values on every call. Define the prefixes once using the existing store
prefix constants, then iterate over that shared variable while preserving the
current wideColumnScanUserKey matching order and return behavior.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@kv/shard_key.go`:
- Around line 126-130: Remove the //nolint directive in the key-decoding logic
and refactor the slice handling around keyLen: advance rest past
wideColumnEncodedKeyLengthSize first, validate that the remaining length can
contain keyLen, then slice using the simplified offsets without uint32 casts or
added variables.

In `@kv/shard_store_txn_lock_test.go`:
- Line 360: テストで生成した MVCCStore リソースを確実に解放する。kv/shard_store_txn_lock_test.go
の該当テストでは st に対する t.Cleanup を追加し、同テスト内の st1 と shardStore
も同様にクローズする。kv/leader_routed_store_test.go では store.NewMVCCStore() の結果を変数へ抽出し、既存の
t.Cleanup 内で s.Close() とともにクローズする。
- Around line 373-374: Update the routeStart argument in the BoundsMatchingLocks
test call to scanTxnLockPagesAtWithRouteFilter so the generated
!redis|meta|z0000 keys fall within the route bounds, while keeping the routeEnd
and other arguments unchanged. Ensure the test exercises the intended
matching-locks path where the collected locks exceed lockPageLimit.

---

Nitpick comments:
In `@kv/shard_key.go`:
- Around line 98-114: Update redisWideColumnScanRouteKey to reuse a
package-level prefix collection instead of constructing the [][]byte and []byte
values on every call. Define the prefixes once using the existing store prefix
constants, then iterate over that shared variable while preserving the current
wideColumnScanUserKey matching order and return behavior.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: d6d8646e-c6fb-4289-9e71-38467e08c07f

📥 Commits

Reviewing files that changed from the base of the PR and between e6776d3 and 65e2973.

📒 Files selected for processing (9)
  • Makefile
  • adapter/grpc.go
  • adapter/grpc_test.go
  • kv/leader_routed_store.go
  • kv/leader_routed_store_test.go
  • kv/shard_key.go
  • kv/shard_store.go
  • kv/shard_store_test.go
  • kv/shard_store_txn_lock_test.go
🚧 Files skipped from review as they are similar to previous changes (6)
  • Makefile
  • kv/shard_store_test.go
  • kv/leader_routed_store.go
  • adapter/grpc.go
  • kv/shard_store.go
  • adapter/grpc_test.go

Comment thread kv/shard_key.go Outdated
Comment thread kv/shard_store_txn_lock_test.go
Comment thread kv/shard_store_txn_lock_test.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 (bd17534):

  • distribution/catalog.go
  • distribution/catalog_test.go
  • distribution/engine.go
  • distribution/engine_test.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 18, 2026

Copy link
Copy Markdown
Owner Author

@codex review\n\nAddressed the current-head read-routing findings in bd17534:\n- atomically paired route selection with its catalog version for scans and point reads\n- preserved selected groups for unclamped fan-out scans\n- restored deterministic ordering after route-filtered lock resolution\n- tightened wide-column key decoding and test cleanup/coverage\n\nCaller audit:\n- GetAt/GetAtWithReadFence and LatestCommitTS/LatestCommitTSWithReadFence select and forward the same route snapshot version\n- forward, reverse, and keys-only scan fan-out paths preserve explicit groups only where the outer loop owns fan-out\n- explicit-group receiver paths retain the supplied read fence\n\nValidation:\n- go test ./distribution ./kv -count=1\n- go test ./... -run '^$' -count=1\n- golangci-lint run ./distribution/... ./kv/... --timeout=5m\n- git diff --check

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

ℹ️ 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/shard_store.go Outdated
Comment thread adapter/grpc.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 (2f73906):

  • distribution/catalog.go
  • distribution/catalog_test.go
  • distribution/engine.go
  • distribution/engine_test.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 18, 2026

Copy link
Copy Markdown
Owner Author

@codex review

Latest HEAD 2f73906 addresses both current-head findings: unsupported value read-fence requests now fail closed, and broad Redis wide-column prefix scans fan out over the decoded logical route interval while exact collection scans remain single-route.

Validation: targeted adapter/kv tests passed; go test ./kv -count=1 passed; go test ./... -run ^$ -count=1 passed; golangci-lint run ./... --timeout=5m passed. The full adapter integration suite timed out at its existing 10-minute limit under concurrent local test load; the affected adapter tests passed separately.

@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: 2f739063fa

ℹ️ 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 adapter/grpc.go
Comment thread adapter/grpc.go
Comment thread kv/shard_key.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 (6bebfda):

  • distribution/catalog.go
  • distribution/catalog_test.go
  • distribution/engine.go
  • distribution/engine_test.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 19, 2026

Copy link
Copy Markdown
Owner Author

Review fixes are available at 6bebfda.\n\n- RawGet and RawLatestCommitTS now fail closed when a requested route fence cannot be enforced.\n- Bare Redis wide-column namespace scans and physical cursor scans fan out across all logical routes; exact collection scans remain single-route.\n- The current main conflict is resolved.\n- Catalog V2 decoding rejects trailing bytes after the fixed-size tail.\n\nEvidence:\n- go test ./distribution ./kv .\n- focused adapter read-fence tests\n- golangci-lint run ./adapter ./distribution ./kv --timeout=5m --allow-parallel-runners: 0 issues\n- make gen: no working-tree diff\n- every commit in origin/main..6bebfda has author and committer bootjp contact@bootjp.me and a valid signature\n\n@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: 6bebfda6bc

ℹ️ 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 adapter/distribution_server.go Outdated
Comment on lines 303 to 306
encoded, err := distribution.EncodeRouteDescriptorForCatalogWrite(route, allowRouteDescriptorV2Writes)
if err != nil {
return nil, errors.WithStack(err)
}

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 Preserve the v3 SplitAtHLC patch offset

When the route being split carries any migration extension field such as MinWriteTSExclusive, this encoder emits the v3 route layout, where SplitAtHLC is no longer the final 8 bytes of the descriptor. The following splitAtHLCPatchOffset call still assumes the last word is SplitAtHLC, so the coordinator stamps the split commit timestamp over MinWriteTSExclusive and leaves SplitAtHLC at zero. Splitting a write-fenced/migrating route will therefore corrupt the catalog fence metadata; compute the patch offset from the encoded version/layout rather than assuming the final word.

Useful? React with 👍 / 👎.

Comment thread kv/leader_routed_store.go
Comment on lines +111 to +113
if ok {
val, err := s.local.GetAt(ctx, key, max(ts, fenceTS))
return val, errors.WithStack(err)

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 unenforceable LeaderRoutedStore read fences

When a RawKV server is backed by LeaderRoutedStore and a caller supplies a non-zero ReadRouteVersion, GRPCServer dispatches here because this type now satisfies the read-fence getter interface. The local-leader branch ignores that requested catalog fence and returns local data after only a leadership fence; the same pattern exists in the latest-commit and scan read-fence helpers. During migration this can silently satisfy a fenced read without proving the node has the requested route catalog version, so this wrapper should fail closed for non-zero readRouteVersion unless it can actually enforce it.

Useful? React with 👍 / 👎.

Comment thread kv/shard_store.go

func (s *ShardStore) routesForFilesystemChunkScan(start []byte, end []byte) ([]distribution.Route, bool) {
func (s *ShardStore) routesForFilesystemChunkScanWithVersion(start []byte, end []byte) ([]distribution.Route, uint64, bool) {
allRoutes, version := s.engine.GetIntersectingRoutesWithVersion(nil, 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 Avoid cloning all routes before chunk overlap checks

For scans that are not filesystem chunk scans, this eagerly clones the entire route table before the function checks whether the requested range even overlaps the filesystem chunk keyspace, and the returned version is discarded on the !ok path. With many split routes, ordinary Redis/Dynamo/raw scans pay an extra O(number of routes) allocation and scan before doing their actual routing lookup; defer the all-routes snapshot until after ChunkScanRouteBounds or filesystemChunkScanOverlap proves it is needed.

Useful? React with 👍 / 👎.

Comment thread kv/shard_key.go
Comment on lines +75 to +76
if user := redisWideColumnRouteKey(key); user != nil {
return user

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 Preserve existing Redis wide-column placement on upgrade

When upgrading a sharded cluster that already has Redis hash/set/zset rows written before this change, those rows were placed by the raw storage key while this new normalization sends exact reads and later writes to the route owning the logical user key. If the catalog has a boundary between the raw internal prefixes and a user key, for example !hs|... in group 1 but user key z in group 2, exact HGET/HSCAN/SISMEMBER/ZRANGE-style paths remain single-route and will only contact group 2, leaving the existing rows stranded on group 1. Add a compatibility read/migration path or gate the routing change until old wide-column data has been moved.

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 (94bf4cd):

  • distribution/catalog.go
  • distribution/catalog_test.go
  • distribution/engine.go
  • distribution/engine_test.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 19, 2026

Copy link
Copy Markdown
Owner Author

Fixed the current-head race CI failure in 94bf4cd. The V3 route codec appends SplitAtHLC before staged/job/write-fence fields, but the previous patch offset used the final 8 bytes and overwrote MinWriteTSExclusive. The codec encoder now returns the exact SplitAtHLC offset while constructing V2/V3 records; the existing write fence remains monotone.

Evidence:

  • go test ./distribution -count=1
  • go test -race ./adapter -run '^TestDistributionServerSplitRange_(Success|ReturnsExactCommittedSplitVersion|UsesCoordinatorForCatalogWrites)$' -count=1\n- golangci-lint run ./distribution ./adapter --timeout=5m --allow-parallel-runners (0 issues)\n- caller audit: CommitTSValueOffset producer/forwarding/coordinator paths checked\n- signed bootjp/contact commit verified\n\n@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: 94bf4cd42c

ℹ️ 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/shard_store.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 (707cc61):

  • distribution/catalog.go
  • distribution/catalog_test.go
  • distribution/engine.go
  • distribution/engine_test.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 19, 2026

Copy link
Copy Markdown
Owner Author

Current HEAD: 707cc6178ba120165985b19ec18eb9aece0f9335

Resolved the current P1 list auxiliary scan routing finding and the current-main conflict:

  • List delta and claim scan prefixes/full keys/cursors now decode their logical user key before route lookup.
  • Normal list item scan routing remains on the same helper path.
  • Malformed encoded prefixes return no logical key and fall back without misrouting.
  • Added two-group fenced scan coverage for both delta and claim namespaces.
  • Caller audit: routesForScanWithVersion is shared by forward, reverse, and fenced scans; explicit route bounds remain authoritative.
  • go test ./kv ./store -count=1
  • targeted auxiliary/list scan regression tests
  • golangci-lint run --config=.golangci.yaml --timeout=5m --allow-parallel-runners ./kv ./store -> 0 issues
  • make tla-check
  • git diff --check

@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: 707cc6178b

ℹ️ 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/shard_store.go
Comment on lines +558 to +559
if userKey == nil {
return nil, 0, false

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 Fan out bare list auxiliary scans

When the sharded Redis delta compactor runs its background list pass, scanDeltaRaw starts at the bare store.ListMetaDeltaPrefix, not a per-user scan prefix. For that valid all-list-delta prefix listScanUserKey returns nil and this branch opts out of encoded routing, so routesForScanWithVersion falls back to the raw !lst|meta|d| interval instead of fanning out to all route groups like the hash/set/zset bare-family path. In a split catalog, deltas for users outside that raw interval are not scanned/compacted by the background pass, leaving hot lists dependent on urgent repair.

Useful? React with 👍 / 👎.

Comment thread kv/shard_store.go
}

func routeKeyInScanBounds(key []byte, routeStart []byte, routeEnd []byte) bool {
key = routeKey(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 Decode all Redis storage keys before route filtering

Route-bound scans use this predicate for migration/fenced export filtering, but routeKey() still lacks concrete decoders for Redis stream meta/entry keys and list delta/claim keys (list deltas are swallowed by the broad ListMetaPrefix case as d|...). When a moving route contains one of those user keys, the KV is compared using its raw/internal prefix rather than the logical Redis key and is filtered out of the route-bounded page. That drops stream rows or list auxiliary rows from staged reads/export for the range; add those prefix decoders before relying on routeKey() here.

Useful? React with 👍 / 👎.

Comment thread distribution/engine.go
Comment on lines +32 to +33
// MinWriteTSExclusive rejects writes at or below the migration cutover floor.
MinWriteTSExclusive uint64

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 Enforce the route write timestamp floor

When a catalog snapshot contains a route with MinWriteTSExclusive (for example on the target after cutover), the field is carried into the in-memory route but the write paths still only resolve a group and then call ApplyMutations* without checking the caller-supplied commitTS against the floor. A raw/one-phase/prepare write at commitTS <= MinWriteTSExclusive can therefore create a live version that sorts below the migrated versions and is hidden by reads, reopening the cutover data-loss case this descriptor field is meant to prevent.

Useful? React with 👍 / 👎.

Comment thread adapter/grpc.go
Comment on lines +303 to +304
if req.GetGroupId() != 0 && req.GetReverse() && !req.GetRouteBoundsPresent() {
return nil, errors.WithStack(status.Error(codes.InvalidArgument, "raw scan with explicit group does not support reverse scans"))

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 Allow proxied non-clamped reverse scans

When a follower handles an unbounded/non-clamped ReverseScanAt (for example start/end nil), ShardStore proxies each backing group with group_id set and no route bounds; before this change the explicit-group reverse path handled that. Since the read-fence branch now rejects group_id + reverse unless route bounds are present, a remote leader backed by ShardStore returns InvalidArgument and the scan fails instead of returning data. Route-bound grouped reverse remains covered, but ordinary non-clamped reverse still needs the explicit-group path.

Useful? React with 👍 / 👎.

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