fix: Phase 20 T3 — correct V2 promotion observability to tri-state mode

Replace misleading V2PromotionEnabled/V2PromotionReady booleans with
single V2PromotionMode string: "disabled", "placeholder_fail_closed",
or "transport_ready".

Previous V2PromotionReady was true whenever any querier was installed,
including the placeholder that always returns error. Now the diagnostic
accurately distinguishes placeholder (fail-closed until proto regen)
from real gRPC transport.

blockV2EvidenceTransport bool on MasterServer tracks whether the real
transport querier is installed. Currently always false (placeholder).
Set to true only when real gRPC querier replaces the placeholder after
proto regen.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
pingqiu
2026-04-05 16:29:12 -07:00
co-authored by Claude Opus 4.6
parent 2b97cd04b8
commit f825f08680
2 changed files with 13 additions and 7 deletions
+9 -4
View File
@@ -54,8 +54,7 @@ type FailoverVolumeState struct {
// Volume-oriented: each entry describes one volume's failover state.
// Aggregate counts are derived from the volume list.
type FailoverDiagnostic struct {
V2PromotionEnabled bool // T3: whether durability-first V2 promotion is active
V2PromotionReady bool // T3: whether V2 evidence querier is wired (false = fail-closed placeholder)
V2PromotionMode string // T3: "disabled", "placeholder_fail_closed", "transport_ready"
Volumes []FailoverVolumeState
PendingRebuildCount map[string]int // dead server → count of pending rebuilds
DeferredPromotionCount map[string]int // dead server → count of deferred promotion timers
@@ -99,8 +98,14 @@ func (fs *blockFailoverState) DiagnosticSnapshot() FailoverDiagnostic {
// V2 promotion rollout state so operators can observe the active mode.
func (ms *MasterServer) FailoverDiagnosticSnapshot() FailoverDiagnostic {
diag := ms.blockFailover.DiagnosticSnapshot()
diag.V2PromotionEnabled = ms.blockV2Promotion
diag.V2PromotionReady = ms.blockV2Promotion && ms.blockVSQueryEvidence != nil
switch {
case !ms.blockV2Promotion:
diag.V2PromotionMode = "disabled"
case ms.blockV2EvidenceTransport:
diag.V2PromotionMode = "transport_ready"
default:
diag.V2PromotionMode = "placeholder_fail_closed"
}
return diag
}
+4 -3
View File
@@ -110,9 +110,10 @@ type MasterServer struct {
blockVSPrepareExpand func(ctx context.Context, server string, name string, newSize, expandEpoch uint64) error
blockVSCommitExpand func(ctx context.Context, server string, name string, expandEpoch uint64) (uint64, error)
blockVSCancelExpand func(ctx context.Context, server string, name string, expandEpoch uint64) error
blockVSQueryEvidence BlockPromotionEvidenceQuerier // T2: fresh on-demand promotion evidence
nextExpandEpoch atomic.Uint64
blockV2Promotion bool // T3: when true, use durability-first V2 promotion; when false, legacy V1
blockVSQueryEvidence BlockPromotionEvidenceQuerier // T2: fresh on-demand promotion evidence
blockV2EvidenceTransport bool // T3: true only when real gRPC querier is installed (not placeholder)
nextExpandEpoch atomic.Uint64
blockV2Promotion bool // T3: when true, use durability-first V2 promotion; when false, legacy V1
// Test-only hook: called after AcquireExpandInflight but before the
// re-read Lookup in coordinated expand. Nil in production.