Skip to content

Complete standalone hotspot split automation#1104

Open
bootjp wants to merge 13 commits into
mainfrom
design/hotspot-split-m3-auto-scheduler
Open

Complete standalone hotspot split automation#1104
bootjp wants to merge 13 commits into
mainfrom
design/hotspot-split-m3-auto-scheduler

Conversation

@bootjp

@bootjp bootjp commented Jul 18, 2026

Copy link
Copy Markdown
Owner

Summary

  • complete standalone same-group hotspot split automation on top of detector PR Add autosplit detector core #1097
  • align committed KeyViz windows with per-label Top-K evidence and apply deterministic p50, Top-K, compound, cooldown, hysteresis, route-cap, and history-gap rules
  • gate scheduling by catalog-key and shard-group leadership, chain committed catalog versions, and reconcile sampler route membership on every node
  • add validated startup controls, authenticated Admin.SetAutoSplitEnabled runtime control, bounded metrics, and production/demo route-aware sampling
  • prove split, disable/re-enable, real leadership transfer, stale-history rejection, and confidence re-earn in a three-node etcd-Raft test
  • rename the M3 design to implemented with requirement evidence; leave cross-group target selection explicitly deferred to M3-PR4 after M2

Review roots addressed

  • r3607985785
  • r3608020346
  • r3608020348
  • r3608020351
  • r3608101599
  • r3608101602
  • r3608101604

Tests

  • make gen
  • golangci-lint run ./... --timeout=5m
  • go test -race -count=1 -timeout=20m ./kv/... ./distribution/...
  • go test -count=1 -timeout=10m ./distribution/autosplit ./keyviz ./kv
  • go test -count=1 -timeout=5m -run relevant Admin and DistributionServer SplitRange tests ./adapter
  • go test -count=1 -timeout=5m -run TestAutoSplitE2EThreeNodeSplitKillSwitchAndLeadershipReset .
  • GitHub Actions: build, proto, lint, TLA check, test, and test ubuntu-latest all pass on the current head

Summary by CodeRabbit

  • 新機能

    • ホットスポットを検知し、同一グループ内の範囲を自動分割する機能を追加しました。
    • 自動分割の有効・無効を運用中に切り替えられるようになりました。
    • 自動分割のスケジュール、リーダーシップ、クールダウンを考慮した安全な実行に対応しました。
    • 自動分割の候補、失敗、スキップ状況を監視できるメトリクスを追加しました。
    • ホットキーの収集と分割処理の連携を改善しました。
  • バグ修正

    • 古いスナップショットを適用した際の不要なエラーを解消しました。
    • カタログ更新通知の重複を防止しました。
  • ドキュメント

    • 自動ホットスポット分割の実装状況と運用範囲を更新しました。

bootjp added 4 commits July 14, 2026 04:16
…' into design/hotspot-split-m3-auto-scheduler
…r' into design/hotspot-split-m3-auto-scheduler

# Conflicts:
#	proto/distribution.pb.go
…' into design/hotspot-split-m3-auto-scheduler
@coderabbitai

coderabbitai Bot commented Jul 18, 2026

Copy link
Copy Markdown

Review Change Stack

📝 Walkthrough

Walkthrough

自動分割の検出器・スケジューラ・ランタイム制御を追加し、KeyViz のホットキー観測、カタログ監視、分配サーバー、管理 gRPC と接続しました。Top-K 隔離、証拠フェンス、Prometheus 指標、E2E テスト、設計文書も更新されています。

Changes

Autosplit 検出とスケジューリング

Layer / File(s) Summary
検出器の拡張
distribution/autosplit/detector.go, distribution/autosplit/detector_test.go, distribution/autosplit/detector_rapid_test.go
履歴平滑化、Top-K 隔離、複合分割、リーダーシップ境界、拒否理由を追加し、テストを拡張しました。
スケジューラと観測
distribution/autosplit/scheduler.go, distribution/autosplit/metrics.go, distribution/autosplit/runtime_switch.go, distribution/autosplit/*_test.go
カタログ評価、分割実行、複合分割の保留・再試行、クールダウン、キルスイッチ、Prometheus 指標を追加しました。
KeyViz 連携
keyviz/*, kv/coordinator.go, kv/sharded_coordinator.go, kv/raft_engine.go
境界付きホットキー・サンプラーウィンドウを追加し、読み書き観測とリーダーシップ情報を提供します。
実行時配線
main.go, main_autosplit.go, cmd/server/demo.go, main_autosplit_e2e_test.go
CLI 設定、監視、ルート再整合、SplitRange 委譲、管理サービス登録、3 ノード E2E を追加しました。
管理 API とカタログ監視
proto/admin.proto, adapter/admin_grpc.go, distribution/watcher.go, adapter/distribution_server.go
自動分割切替 RPC、スナップショット通知、stale snapshot の抑制を追加しました。
テスト・設計更新
docs/design/*, main_bootstrap_e2e_test.go
設計状況を更新し、E2E テストの待機・終了処理を整理しました。

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

Possibly related PRs

  • bootjp/elastickv#639: KeyViz の MemSampler、リングバッファ、フラッシャー基盤に直接関連します。
  • bootjp/elastickv#1097: autosplit 検出器コアと今回の検出器拡張に直接関連します。
  • bootjp/elastickv#1117: カタログ監視と SyncOnce の変更領域が重なります。

Sequence Diagram(s)

sequenceDiagram
  participant AdminClient
  participant AdminServer
  participant RuntimeSwitch
  participant Scheduler
  AdminClient->>AdminServer: SetAutoSplitEnabled(enabled)
  AdminServer->>RuntimeSwitch: SetEnabled(enabled)
  AdminServer-->>AdminClient: Enabled()
  Scheduler->>RuntimeSwitch: KillSwitch()
  RuntimeSwitch-->>Scheduler: enabled state
Loading
🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 16.47% 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 タイトルはPRの主目的であるスタンドアロンのhotspot split自動化完了を正確に要約しています。
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.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch

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

❤️ Share

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

@bootjp

bootjp commented Jul 18, 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 (48d83f0):

  • distribution/autosplit/scheduler.go
  • distribution/autosplit/scheduler_test.go
  • distribution/catalog.go
  • distribution/catalog_test.go
  • kv/coordinator.go
  • kv/sharded_coordinator.go

What to check, by subsystem:

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

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


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

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

@chatgpt-codex-connector

Copy link
Copy Markdown

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

@github-actions

Copy link
Copy Markdown
Contributor

TLA+ spec divergence review (auto-triggered)

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

Anchored files changed in this PR head (8b22ccf):

  • distribution/autosplit/scheduler.go
  • distribution/autosplit/scheduler_test.go
  • distribution/catalog.go
  • distribution/catalog_test.go
  • kv/coordinator.go
  • kv/sharded_coordinator.go

What to check, by subsystem:

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

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


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

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

@bootjp

bootjp commented Jul 18, 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 implements the standalone automatic hotspot range split scheduler (autosplit) for same-group splits, integrating it with the existing SplitRange and KeyViz sampler. It introduces a durable SplitAtHLC route lineage field to reconstruct cooldowns on leadership changes, updates the route catalog codec to v2 with backward compatibility, and adds a transaction commit timestamp patching mechanism (CommitTSValueOffset). A critical issue was identified in the scheduler's execution loop where sequential split decisions are executed with a stale catalog version, which will cause subsequent splits in the same cycle to fail due to optimistic concurrency control (OCC) mismatches. Updating the catalog version dynamically after each successful split is recommended to resolve this.

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/autosplit/scheduler.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 (a18b63d):

  • distribution/autosplit/scheduler.go
  • distribution/autosplit/scheduler_test.go
  • distribution/catalog.go
  • distribution/catalog_test.go
  • kv/coordinator.go
  • kv/sharded_coordinator.go

What to check, by subsystem:

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

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


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

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

@bootjp

bootjp commented Jul 18, 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.

@bootjp

bootjp commented Jul 18, 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 (00e9a82):

  • distribution/autosplit/scheduler.go
  • distribution/autosplit/scheduler_test.go
  • distribution/catalog.go
  • distribution/catalog_test.go
  • kv/coordinator.go
  • kv/sharded_coordinator.go

What to check, by subsystem:

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

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


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

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

@chatgpt-codex-connector

Copy link
Copy Markdown

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

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

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 00e9a82fb8

ℹ️ 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 cmd/server/demo.go Outdated
Comment thread distribution/autosplit/scheduler.go Outdated
Comment thread main_autosplit.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 (4817c25):

  • distribution/autosplit/scheduler.go
  • distribution/autosplit/scheduler_test.go
  • distribution/catalog.go
  • distribution/catalog_test.go
  • kv/coordinator.go
  • kv/sharded_coordinator.go

What to check, by subsystem:

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

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


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

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

@chatgpt-codex-connector

Copy link
Copy Markdown

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

@bootjp

bootjp commented Jul 18, 2026

Copy link
Copy Markdown
Owner Author

Updated the scheduler follow-up on latest head. Addressed current findings around demo sampling, sampler route descriptor re-registration, and catalog-key leadership gating. Local checks: go test ./distribution/autosplit -count=1; go test . -count=1; go test ./cmd/server -count=1; go test ./kv -count=1; go test ./... -run '^$'; go test ./... -timeout=20m; golangci-lint --config=.golangci.yaml run --fix; git diff --check.\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: 4817c25fdb

ℹ️ 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
Comment thread cmd/server/demo.go Outdated
Comment thread distribution/autosplit/scheduler.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 (9f3f8a9):

  • distribution/autosplit/detector.go
  • distribution/autosplit/detector_rapid_test.go
  • distribution/autosplit/detector_test.go
  • distribution/autosplit/metrics.go
  • distribution/autosplit/metrics_test.go
  • distribution/autosplit/runtime_switch.go
  • distribution/autosplit/runtime_switch_test.go
  • distribution/autosplit/scheduler.go
  • distribution/autosplit/scheduler_test.go
  • distribution/catalog.go
  • distribution/catalog_test.go
  • distribution/watcher.go
  • distribution/watcher_test.go
  • kv/coordinator.go
  • kv/sharded_coordinator.go

What to check, by subsystem:

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

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


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

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

@chatgpt-codex-connector

Copy link
Copy Markdown

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

@bootjp

bootjp commented Jul 18, 2026

Copy link
Copy Markdown
Owner Author

Current-head evidence for 9f3f8a93c5995db8925b398ed9df1b9ef533aa17:

Requirement audit:

  • Exact committed (WindowStart, At] columns now carry aligned per-label Top-K evidence; the ring deep-copies it.
  • Detector covers per-label aggregation, normalized per-column plus smoothed scores, chronological hysteresis/reset, Top-K lower/error/degraded/absolute gates, p50 and compound/edge forms, structural splittability, route-delta cap, cooldown, and bounded state.
  • Scheduler is gated by catalog-key leadership and per-route shard-group leadership terms, fences stale/straddling/history-gap evidence, chains committed catalog versions, retries and revalidates compound finalization, and always uses same-group targets for standalone M3.
  • Catalog watcher reconciliation updates sampler membership on every node; demo traffic resolves the current route dynamically.
  • Startup flags are validated, Admin.SetAutoSplitEnabled atomically controls runtime scheduling, and metric names/reason labels are bounded.
  • main_autosplit_e2e_test.go proves a real three-node etcd-Raft split, runtime disable/re-enable, actual leadership transfer, stale-history rejection, and post-transfer confidence re-earn.
  • The design is renamed to 2026_06_11_implemented_hotspot_split_milestone3_automation.md with an implementation evidence matrix; M3-PR4 remains explicitly deferred post-M2.

Current-head fixes for review roots:

  • r3608020346: production/demo sampler writes use current route resolution.
  • r3608020348: descriptor changes re-register routes.
  • r3608020351: scheduler uses catalog-key leadership.
  • r3608101599: an engine-ahead stale apply no longer turns a committed split into an RPC failure.
  • r3608101602: demo no longer pins the startup route ID.
  • r3608101604: watcher reconciliation runs on followers as well as the catalog leader.
  • r3607985785: multi-split and compound calls chain the returned committed catalog version.

Verification:

  • make gen: pass.
  • golangci-lint run ./... --timeout=5m: 0 issues; signed commit hook lint also 0 issues.
  • go test -race -count=1 ./kv/... ./distribution/...: 646 tests pass.
  • go test -count=1 ./distribution/autosplit ./keyviz ./kv: 640 tests pass.
  • Focused admin and DistributionServer.SplitRange tests: pass.
  • Real three-node auto-split E2E: pass.
  • Full ./... attempt reached 5515 tests; the only failures were temporary disk exhaustion. Isolated adapter then reached 1625 tests with one unrelated Lua election flake, and that exact test passed on immediate isolated rerun.

Commit signature: Good EDDSA signature; author and committer are bootjp <contact@bootjp.me>.

@bootjp

bootjp commented Jul 18, 2026

Copy link
Copy Markdown
Owner Author

@codex review

@bootjp

bootjp commented Jul 18, 2026

Copy link
Copy Markdown
Owner Author

Superseded by the verified current-head evidence comment: #1104 (comment)

@bootjp bootjp changed the title Add autosplit p50 scheduler wiring Complete standalone hotspot split automation Jul 18, 2026
@bootjp

bootjp commented Jul 18, 2026

Copy link
Copy Markdown
Owner Author

@coderabbitai review

@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: 9f3f8a93c5

ℹ️ 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 main_autosplit.go
Comment thread kv/coordinator.go
Comment thread main_autosplit.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 (3bd6a97):

  • distribution/autosplit/detector.go
  • distribution/autosplit/detector_rapid_test.go
  • distribution/autosplit/detector_test.go
  • distribution/autosplit/metrics.go
  • distribution/autosplit/metrics_test.go
  • distribution/autosplit/runtime_switch.go
  • distribution/autosplit/runtime_switch_test.go
  • distribution/autosplit/scheduler.go
  • distribution/autosplit/scheduler_test.go
  • distribution/catalog.go
  • distribution/catalog_test.go
  • distribution/watcher.go
  • distribution/watcher_test.go
  • kv/coordinator.go
  • kv/sharded_coordinator.go

What to check, by subsystem:

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

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


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

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

@chatgpt-codex-connector

Copy link
Copy Markdown

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

…r' into design/hotspot-split-m3-auto-scheduler

# Conflicts:
#	Makefile
#	adapter/admin_grpc.go
#	proto/admin.pb.go
#	proto/service.pb.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 (bf05e1d):

  • distribution/autosplit/detector.go
  • distribution/autosplit/detector_rapid_test.go
  • distribution/autosplit/detector_test.go
  • distribution/autosplit/metrics.go
  • distribution/autosplit/metrics_test.go
  • distribution/autosplit/runtime_switch.go
  • distribution/autosplit/runtime_switch_test.go
  • distribution/autosplit/scheduler.go
  • distribution/autosplit/scheduler_test.go
  • distribution/watcher.go
  • distribution/watcher_test.go
  • kv/coordinator.go
  • kv/sharded_coordinator.go

What to check, by subsystem:

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

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


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

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

@chatgpt-codex-connector

Copy link
Copy Markdown

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

@bootjp

bootjp commented Jul 19, 2026

Copy link
Copy Markdown
Owner Author

@codex review

Current head bf05e1d resolves the three latest review findings and is merged with current main through dependency PR #1097.

Validation:

  • go test ./distribution ./distribution/autosplit ./kv . -count=1 -timeout=10m
  • go test ./adapter -run "TestAdmin|TestGRPCServer_RawScanAt" -count=1 -timeout=10m
  • buf breaking against current main
  • make tla-check
  • golangci-lint run ./... --timeout=5m --allow-parallel-runners
  • git diff --check

The previous full local go test run only failed the pre-existing long-running Redis stream latency test after its HLC physical ceiling expired under local load; current-head GitHub test and Jepsen checks are the authoritative full-suite gates.

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

ℹ️ 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/autosplit/scheduler.go Outdated
Comment thread cmd/server/demo.go Outdated
Comment thread keyviz/sampler.go
Comment thread cmd/server/demo.go Outdated
Base automatically changed from feature/hotspot-split-m3-detector to main July 19, 2026 14:17
@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 (e023ed4):

  • distribution/autosplit/detector.go
  • distribution/autosplit/detector_rapid_test.go
  • distribution/autosplit/detector_test.go
  • distribution/autosplit/metrics.go
  • distribution/autosplit/metrics_test.go
  • distribution/autosplit/runtime_switch.go
  • distribution/autosplit/runtime_switch_test.go
  • distribution/autosplit/scheduler.go
  • distribution/autosplit/scheduler_test.go
  • distribution/watcher.go
  • distribution/watcher_test.go
  • kv/coordinator.go
  • kv/sharded_coordinator.go

What to check, by subsystem:

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

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


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

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

@chatgpt-codex-connector

Copy link
Copy Markdown

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

@bootjp

bootjp commented Jul 19, 2026

Copy link
Copy Markdown
Owner Author

Current HEAD: e023ed4608e6aa7d4a8d1ff81f664cc5c890e9f8

Resolved all four current P2 findings and merged current main:

  • Compound isolation follows the committed normalized first-split boundary while preserving topology validation and pending retries.
  • Demo sampler route lookup uses kv.RouteKey.
  • Enabled Top-K write observation and counter draining are synchronized across the same flush boundary; disabled/read paths retain their prior lock behavior.
  • Demo detector rejects NaN/Inf for all float thresholds and weights.

Caller/semantic audit:

  • Compound validation is used only by the scheduler's compound execution path; normal splits are unchanged.
  • The demo resolver is installed only by setupDemoDistributionRuntime.
  • MemSampler.Observe adds the RW lock only for writes when hot-key tracking is enabled.
  • Validation changes fail startup for non-finite operator input instead of silently activating invalid scheduling.

Validation after merging current main:

  • go test ./distribution/autosplit ./keyviz ./cmd/server -count=1
  • go test -race ./keyviz -run 'TestFlushWindowKeepsHotKeyAndCounterInSameColumn|TestRunFlusherAttachesAlignedHotKeysWindow' -count=10
  • golangci-lint run --config=.golangci.yaml --timeout=5m --allow-parallel-runners ./cmd/server ./distribution/autosplit ./keyviz -> 0 issues
  • make tla-check
  • git diff --check

@codex review

@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 (2)
main_autosplit_e2e_test.go (2)

49-50: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Tickの戻り値を検証せずに破棄している

kill switch を無効化する直前のこの Tick 呼び出しは結果を _ で捨てており、Scheduled/Failed が想定通りゼロであることをアサートしていない。ここで意図しない追加split(または部分失敗)が発生してもテストは検知できない。

提案: 結果を検証する
-	_, err = leaderScheduler.Tick(context.Background(), base.Add(2*time.Minute+time.Second))
-	require.NoError(t, err)
+	settled, err := leaderScheduler.Tick(context.Background(), base.Add(2*time.Minute+time.Second))
+	require.NoError(t, err)
+	require.Zero(t, settled.Scheduled)
+	require.Zero(t, settled.Failed)
🤖 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 `@main_autosplit_e2e_test.go` around lines 49 - 50, Update the Tick call in the
autosplit test to retain its result and assert that both Scheduled and Failed
are zero before disabling the kill switch. Keep the existing error assertion and
use the returned Tick result to detect unintended splits or partial failures.

90-99: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

confidence re-earning後の最終splitでクラスタ全体への伝播確認が欠けている

47行目・66行目の分割成功時は waitForCatalogVersion(t, nodes, ...) で全ノードへの伝播を確認しているが、96-99行目の reearned split では currentCatalogVersion を対象ノードのみでチェックしており、他ノードへの反映は未検証。3ノードE2Eテストの目的(クラスタ全体の一貫性)に対して非対称であり、他の成功パスと揃えるべき。

また、8分/9分の書き込みでは notYet.Detector.Decisions が空になり、10分でようやく成功する(初回splitは2ウィンドウで成立)という挙動の違いは、リーダー移譲後の信頼再構築に必要なウィンドウ数の意図が読み手に伝わりにくい。簡潔なコメントを添えると可読性が上がる。

提案: 最終splitの伝播確認を追加
 	reearned, err := targetScheduler.Tick(context.Background(), base.Add(10*time.Minute))
 	require.NoError(t, err)
 	require.Equal(t, 1, reearned.Scheduled)
-	require.Greater(t, currentCatalogVersion(t, nodes[targetIdx]), secondSplitVersion)
+	finalVersion := currentCatalogVersion(t, nodes[targetIdx])
+	require.Greater(t, finalVersion, secondSplitVersion)
+	waitForCatalogVersion(t, nodes, finalVersion, waitTimeout, waitInterval)
🤖 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 `@main_autosplit_e2e_test.go` around lines 90 - 99, 最終のreearned
splitが対象ノードだけでなくクラスタ全体へ伝播したことを検証する。targetScheduler
の10分時点の成功後、currentCatalogVersion の単一ノード確認を waitForCatalogVersion(t, nodes, ...)
に置き換え、既存の成功パスと揃える。8分・9分では判定に必要なウィンドウが不足していることが10分で成功する意図を示す簡潔なコメントを notYet
の確認付近に追加する。
🤖 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/coordinator.go`:
- Around line 268-271: Synchronize updates to sampler, samplerRouteID, and
samplerRouteResolve with the lock-free reads performed by the observe* methods.
Update WithSamplerRouteResolver and the corresponding coordinator fields so all
three values are replaced atomically under the same synchronization mechanism,
preserving consistent routing during range-split reconfiguration.

In `@kv/sharded_coordinator.go`:
- Around line 1707-1723: NewShardedCoordinatorで受け取ったgroups
mapをそのまま保持せず、初期化時に独立したコピーを作成してc.groupsへ格納してください。GroupLeadershipとLeadershipForKeyはそのコピーを参照し、初期化後の外部map変更によるdata
raceを防いでください。

In `@main_autosplit.go`:
- Around line 109-146: Update setupDistributionWatcherAndAutoSplit so the
disabled --autoSplit path returns a true nil interface for
autosplit.RuntimeSwitch rather than a typed-nil *autosplit.RuntimeSwitch.
Preserve the existing runtime creation and KillSwitch setup when cfg.Enabled is
true, while ensuring callers such as the AutoSplitRuntime assignment can detect
the feature as unavailable.

---

Nitpick comments:
In `@main_autosplit_e2e_test.go`:
- Around line 49-50: Update the Tick call in the autosplit test to retain its
result and assert that both Scheduled and Failed are zero before disabling the
kill switch. Keep the existing error assertion and use the returned Tick result
to detect unintended splits or partial failures.
- Around line 90-99: 最終のreearned
splitが対象ノードだけでなくクラスタ全体へ伝播したことを検証する。targetScheduler
の10分時点の成功後、currentCatalogVersion の単一ノード確認を waitForCatalogVersion(t, nodes, ...)
に置き換え、既存の成功パスと揃える。8分・9分では判定に必要なウィンドウが不足していることが10分で成功する意図を示す簡潔なコメントを notYet
の確認付近に追加する。
🪄 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: 5e29aa3d-154e-4f04-b63f-44891679ed6a

📥 Commits

Reviewing files that changed from the base of the PR and between dafb8d2 and e023ed4.

⛔ Files ignored due to path filters (2)
  • proto/admin.pb.go is excluded by !**/*.pb.go
  • proto/admin_grpc.pb.go is excluded by !**/*.pb.go
📒 Files selected for processing (38)
  • adapter/admin_grpc.go
  • adapter/admin_grpc_autosplit_test.go
  • adapter/distribution_server.go
  • adapter/distribution_server_test.go
  • cmd/server/demo.go
  • cmd/server/demo_test.go
  • distribution/autosplit/detector.go
  • distribution/autosplit/detector_rapid_test.go
  • distribution/autosplit/detector_test.go
  • distribution/autosplit/metrics.go
  • distribution/autosplit/metrics_test.go
  • distribution/autosplit/runtime_switch.go
  • distribution/autosplit/runtime_switch_test.go
  • distribution/autosplit/scheduler.go
  • distribution/autosplit/scheduler_test.go
  • distribution/watcher.go
  • distribution/watcher_test.go
  • docs/design/2026_02_18_partial_hotspot_shard_split.md
  • docs/design/2026_06_11_implemented_hotspot_split_milestone3_automation.md
  • docs/design/2026_06_11_implemented_leader_balance_scheduler.md
  • docs/design/2026_06_12_proposed_scaling_roadmap.md
  • docs/design/2026_06_23_proposed_scaling_roadmap.md
  • keyviz/flusher.go
  • keyviz/flusher_test.go
  • keyviz/hot_keys.go
  • keyviz/hot_keys_test.go
  • keyviz/ring_buffer.go
  • keyviz/sampler.go
  • kv/coordinator.go
  • kv/coordinator_dispatch_test.go
  • kv/raft_engine.go
  • kv/sharded_coordinator.go
  • main.go
  • main_autosplit.go
  • main_autosplit_e2e_test.go
  • main_autosplit_test.go
  • main_bootstrap_e2e_test.go
  • proto/admin.proto

Comment thread kv/coordinator.go
Comment on lines +268 to +271
leaseObserver LeaseReadObserver
sampler keyviz.Sampler
samplerRouteID uint64
samplerRouteResolve func(key []byte) (uint64, bool)

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🩺 Stability & Availability | 🟡 Minor | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# WithSampler / WithSamplerRouteResolver の呼び出し箇所を確認
rg -nP -C4 '\.With(Sampler|SamplerRouteResolver)\s*\(' --type=go

Repository: bootjp/elastickv

Length of output: 154


🏁 Script executed:

#!/bin/bash
set -euo pipefail

printf '\n## files\n'
git ls-files 'kv/*' | sed -n '1,120p'

printf '\n## coordinator outline\n'
ast-grep outline kv/coordinator.go --view expanded || true

printf '\n## sampler-related identifiers\n'
rg -n --context 3 'WithSampler|WithSamplerRouteResolver|samplerRouteID|samplerRouteResolve|sampler\s+keyviz\.Sampler' kv/coordinator.go kv -g '*.go' || true

Repository: bootjp/elastickv

Length of output: 25072


🏁 Script executed:

#!/bin/bash
set -euo pipefail

sed -n '1,360p' kv/coordinator.go | cat -n

Repository: bootjp/elastickv

Length of output: 17276


🏁 Script executed:

#!/bin/bash
set -euo pipefail

python3 - <<'PY'
from pathlib import Path
text = Path('kv/coordinator.go').read_text()
for needle in ['WithSampler', 'WithSamplerRouteResolver', 'samplerRouteID', 'samplerRouteResolve', 'observe']:
    print(f'\n## {needle}')
    for i, line in enumerate(text.splitlines(), 1):
        if needle in line:
            start = max(1, i-4)
            end = min(len(text.splitlines()), i+6)
            for j in range(start, end+1):
                print(f'{j}: {text.splitlines()[j-1]}')
            print('---')
PY

Repository: bootjp/elastickv

Length of output: 27458


sampler 配線の更新経路を同期するか、更新不可と明示してください。
WithSamplerRouteResolver は range split 後の再配線用途があり、observe* 側は sampler / samplerRouteID / samplerRouteResolve を無ロックで読んでいます。リクエスト処理中に差し替える前提ならデータレースになるので、3 フィールドを安全に一括更新できる形にするか、起動前のみ更新可だと明文化してください。

🤖 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/coordinator.go` around lines 268 - 271, Synchronize updates to sampler,
samplerRouteID, and samplerRouteResolve with the lock-free reads performed by
the observe* methods. Update WithSamplerRouteResolver and the corresponding
coordinator fields so all three values are replaced atomically under the same
synchronization mechanism, preserving consistent routing during range-split
reconfiguration.

Comment thread kv/sharded_coordinator.go
Comment on lines +1707 to +1723
// LeadershipForKey reports local leadership and Raft term for key's group.
func (c *ShardedCoordinator) LeadershipForKey(key []byte) (bool, uint64) {
g, ok := c.groupForKey(key)
if !ok {
return false, 0
}
return leadershipForEngine(engineForGroup(g))
}

// GroupLeadership reports local leadership and Raft term for groupID.
func (c *ShardedCoordinator) GroupLeadership(groupID uint64) (bool, uint64) {
g, ok := c.groups[groupID]
if !ok {
return false, 0
}
return leadershipForEngine(engineForGroup(g))
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🩺 Stability & Availability | 🟡 Minor | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# c.groups への書き込み・保護状況を確認
rg -nP -C3 '\bc\.groups\b' kv/sharded_coordinator.go
# groups フィールド定義と保護用ロックの有無
ast-grep run --pattern 'groups map[$_]$_' --lang go kv/sharded_coordinator.go
rg -nP -C2 'groups\s+map\[' kv/sharded_coordinator.go

Repository: bootjp/elastickv

Length of output: 6077


🏁 Script executed:

#!/bin/bash
set -euo pipefail

# コンストラクタ周辺を確認
sed -n '655,705p' kv/sharded_coordinator.go

echo
echo '--- call sites ---'
rg -n "NewShardedCoordinator\(" -S .

echo
echo '--- any assignments to c.groups after construction ---'
rg -n "\bc\.groups\s*=" kv/sharded_coordinator.go

echo
echo '--- any writes via groups map in this file ---'
rg -n "\bc\.groups\[[^]]+\]\s*=" kv/sharded_coordinator.go

Repository: bootjp/elastickv

Length of output: 11603


groups をコピーするか、不変である契約を明記してください。
NewShardedCoordinator は受け取った map をそのまま c.groups に保持しています。GroupLeadership / LeadershipForKey はバックグラウンド goroutine からロックなしで参照されるため、初期化後に外部から map を書き換えられると data race になります。

🤖 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/sharded_coordinator.go` around lines 1707 - 1723,
NewShardedCoordinatorで受け取ったgroups
mapをそのまま保持せず、初期化時に独立したコピーを作成してc.groupsへ格納してください。GroupLeadershipとLeadershipForKeyはそのコピーを参照し、初期化後の外部map変更によるdata
raceを防いでください。

Comment thread main_autosplit.go
Comment on lines +109 to +146
func setupDistributionWatcherAndAutoSplit(
ctx context.Context,
eg *errgroup.Group,
catalog *distribution.CatalogStore,
engine *distribution.Engine,
distServer *adapter.DistributionServer,
coordinate *kv.ShardedCoordinator,
sampler *keyviz.MemSampler,
observer autosplit.Observer,
) (*autosplit.RuntimeSwitch, error) {
cfg, err := configureRuntimeAutoSplit(coordinate)
if err != nil {
return nil, err
}
cfg.Observer = observer
var runtime *autosplit.RuntimeSwitch
if cfg.Enabled {
runtime = autosplit.NewRuntimeSwitch(true)
cfg.KillSwitch = runtime.KillSwitch
}
var reconciler *autosplit.RouteReconciler
if sampler != nil {
reconciler = autosplit.NewRouteReconciler(sampler)
initialSnapshot, snapshotErr := catalog.Snapshot(ctx)
if snapshotErr != nil {
return nil, errors.Wrap(snapshotErr, "load initial catalog for keyviz reconciliation")
}
reconciler.Reconcile(initialSnapshot.Routes)
cfg.Reconciler = reconciler
}
eg.Go(func() error {
return runDistributionCatalogWatcher(ctx, catalog, engine, func(snapshot distribution.CatalogSnapshot) {
reconciler.Reconcile(snapshot.Routes)
})
})
startAutoSplitScheduler(ctx, eg, catalog, distServer, coordinate, sampler, cfg)
return runtime, 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.

🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

--autoSplit 無効時に SetAutoSplitEnabledUnavailable を返さない(typed-nil 問題)

setupDistributionWatcherAndAutoSplit は無効時に nil の *autosplit.RuntimeSwitch を返します。これが main.go:611 で interface 型フィールド adapter.AutoSplitRuntime に代入されると、nil ポインタを包んだ「非 nil な interface」(typed-nil)になります。結果として main.go:2120if autoSplitRuntime != nil が true となり typed-nil な switch が登録され、AdminServer.SetAutoSplitEnabledcodes.Unavailable(未設定)ではなく成功(enabled=false)を返し、有効化操作も no-op になります。--autoSplit はデフォルト無効なので既定経路で発生します。keyviz サンプラが main.go:2113-2116 のコメント通り concrete 型で nil 判定して回避しているのと同じ罠です。

無効時に真の nil interface を返すよう修正するのが簡潔です。

🐛 Proposed fix
 	sampler *keyviz.MemSampler,
 	observer autosplit.Observer,
-) (*autosplit.RuntimeSwitch, error) {
+) (adapter.AutoSplitRuntime, error) {
 	cfg, err := configureRuntimeAutoSplit(coordinate)
 	if err != nil {
 		return nil, err
 	}
@@
 	startAutoSplitScheduler(ctx, eg, catalog, distServer, coordinate, sampler, cfg)
-	return runtime, nil
+	if runtime == nil {
+		return nil, nil
+	}
+	return runtime, nil
 }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
func setupDistributionWatcherAndAutoSplit(
ctx context.Context,
eg *errgroup.Group,
catalog *distribution.CatalogStore,
engine *distribution.Engine,
distServer *adapter.DistributionServer,
coordinate *kv.ShardedCoordinator,
sampler *keyviz.MemSampler,
observer autosplit.Observer,
) (*autosplit.RuntimeSwitch, error) {
cfg, err := configureRuntimeAutoSplit(coordinate)
if err != nil {
return nil, err
}
cfg.Observer = observer
var runtime *autosplit.RuntimeSwitch
if cfg.Enabled {
runtime = autosplit.NewRuntimeSwitch(true)
cfg.KillSwitch = runtime.KillSwitch
}
var reconciler *autosplit.RouteReconciler
if sampler != nil {
reconciler = autosplit.NewRouteReconciler(sampler)
initialSnapshot, snapshotErr := catalog.Snapshot(ctx)
if snapshotErr != nil {
return nil, errors.Wrap(snapshotErr, "load initial catalog for keyviz reconciliation")
}
reconciler.Reconcile(initialSnapshot.Routes)
cfg.Reconciler = reconciler
}
eg.Go(func() error {
return runDistributionCatalogWatcher(ctx, catalog, engine, func(snapshot distribution.CatalogSnapshot) {
reconciler.Reconcile(snapshot.Routes)
})
})
startAutoSplitScheduler(ctx, eg, catalog, distServer, coordinate, sampler, cfg)
return runtime, nil
}
func setupDistributionWatcherAndAutoSplit(
ctx context.Context,
eg *errgroup.Group,
catalog *distribution.CatalogStore,
engine *distribution.Engine,
distServer *adapter.DistributionServer,
coordinate *kv.ShardedCoordinator,
sampler *keyviz.MemSampler,
observer autosplit.Observer,
) (adapter.AutoSplitRuntime, error) {
cfg, err := configureRuntimeAutoSplit(coordinate)
if err != nil {
return nil, err
}
cfg.Observer = observer
var runtime *autosplit.RuntimeSwitch
if cfg.Enabled {
runtime = autosplit.NewRuntimeSwitch(true)
cfg.KillSwitch = runtime.KillSwitch
}
var reconciler *autosplit.RouteReconciler
if sampler != nil {
reconciler = autosplit.NewRouteReconciler(sampler)
initialSnapshot, snapshotErr := catalog.Snapshot(ctx)
if snapshotErr != nil {
return nil, errors.Wrap(snapshotErr, "load initial catalog for keyviz reconciliation")
}
reconciler.Reconcile(initialSnapshot.Routes)
cfg.Reconciler = reconciler
}
eg.Go(func() error {
return runDistributionCatalogWatcher(ctx, catalog, engine, func(snapshot distribution.CatalogSnapshot) {
reconciler.Reconcile(snapshot.Routes)
})
})
startAutoSplitScheduler(ctx, eg, catalog, distServer, coordinate, sampler, cfg)
if runtime == nil {
return nil, nil
}
return runtime, nil
}
🤖 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 `@main_autosplit.go` around lines 109 - 146, Update
setupDistributionWatcherAndAutoSplit so the disabled --autoSplit path returns a
true nil interface for autosplit.RuntimeSwitch rather than a typed-nil
*autosplit.RuntimeSwitch. Preserve the existing runtime creation and KillSwitch
setup when cfg.Enabled is true, while ensuring callers such as the
AutoSplitRuntime assignment can detect the feature as unavailable.

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

ℹ️ 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 main_autosplit.go
cfg,
catalog,
autoSplitDistributionSplitter{server: distServer},
sampler,

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 Count forwarded traffic on the splitting leader

When clients send writes to followers, the sampler update happens on the ingress coordinator before forwarding (for example the sharded path observes during dispatch entry), while the leader-side Internal.Forward commit path does not update this node's sampler. Since this scheduler is only eligible on the catalog/shard leaders but consumes only the local sampler passed here, follower-ingress hotspots never reach the threshold on the node that is allowed to split. Please either observe forwarded commits on the leader or feed the scheduler merged/fan-in sampler data.

Useful? React with 👍 / 👎.

Comment thread kv/coordinator.go
if !ok {
return
}
c.sampler.Observe(routeID, mut.Key, keyviz.OpWrite, len(mut.Value), keyviz.LabelLegacy)

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 Normalize keys before sampling split evidence

In the single-group/demo path, when the resolver maps adapter storage keys such as S3 or filesystem keys through kv.RouteKey, this call still records the raw mut.Key into the sampler. The sampler's sub-bucket rows and Top-K entries are then in a different keyspace from the catalog route bounds that SplitRange normalizes before committing, so auto-split can choose raw-prefix boundaries or repeatedly retry a compound second split that normalizes back to the first boundary instead of isolating the hot route key. Pass the normalized route key to Observe (or have the resolver return it) for these paths.

Useful? React with 👍 / 👎.

s.fenceUnprovenCatalogGap(prep.routes, prep.fences, newestWindowAt(windows))
}
result := Evaluate(s.cfg.Detector, s.state, Input{
Routes: prep.routes,

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 Enforce the route cap against the full catalog

When GroupLeadership is configured, prep.routes has already been filtered to only the shard groups this node leads, but Evaluate uses the length of this slice for MaxRoutes admission. In a multi-group cluster where the catalog already has 1024 live routes but this node leads only a subset, the detector can still admit another split because the cap check sees only the subset; SplitRange has no independent max-route guard, so the global route cap can be exceeded. Pass the full snapshot route count into the admission check while still scoring only locally-led routes.

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