From 189891e5923e4cabb3f0ac9bed2678db67a2db95 Mon Sep 17 00:00:00 2001 From: MinglesAI Date: Tue, 31 Mar 2026 10:38:41 +0000 Subject: [PATCH] chore: circuit breaker follow-up cleanup (#30) - Remove dead CircuitBreakerStatePrefix (prefix 53) from keys.go; the implementation already uses string-based CircuitBreakerStateKey with KeyPrefix() consistently. Reserved comment added so prefix 53 is not reused accidentally. - Add nil guard in buildSelectionWeightsMap() for eg.GroupData == nil; defensive change to prevent a nil-dereference panic in the unlikely case EpochGroup is constructed without NewEpochGroup(). - Document zero-value governance param caveat in getCBParams(): setting any CB param to 0 via governance silently falls back to compile-time defaults. Prefer large values (e.g. CbMissThresholdPct=100) to disable threshold enforcement rather than zero. Addresses reviewer follow-up from issue #30. --- inference-chain/x/inference/epochgroup/random.go | 5 +++++ inference-chain/x/inference/keeper/circuit_breaker.go | 9 +++++++++ inference-chain/x/inference/types/keys.go | 8 +++++--- 3 files changed, 19 insertions(+), 3 deletions(-) diff --git a/inference-chain/x/inference/epochgroup/random.go b/inference-chain/x/inference/epochgroup/random.go index 4cbb0d667..f6fe93c2c 100644 --- a/inference-chain/x/inference/epochgroup/random.go +++ b/inference-chain/x/inference/epochgroup/random.go @@ -75,7 +75,12 @@ func (eg *EpochGroup) GetRandomMember( // PoC voting weights (ValidationWeights[].Weight) and the cosmos-sdk group member // weights (used for block production) are NOT modified; this map is used solely by // the executor-selection lottery. +// +// Returns an empty map if GroupData or ValidationWeights is nil. func (eg *EpochGroup) buildSelectionWeightsMap() map[string]int64 { + if eg.GroupData == nil { + return make(map[string]int64) + } weights := make(map[string]int64, len(eg.GroupData.ValidationWeights)) for _, vw := range eg.GroupData.ValidationWeights { if vw == nil { diff --git a/inference-chain/x/inference/keeper/circuit_breaker.go b/inference-chain/x/inference/keeper/circuit_breaker.go index 03ab13bde..0cf39234c 100644 --- a/inference-chain/x/inference/keeper/circuit_breaker.go +++ b/inference-chain/x/inference/keeper/circuit_breaker.go @@ -48,6 +48,15 @@ type cbParams struct { // getCBParams reads CB parameters from ValidationParams and falls back to Go // compile-time defaults for any field that is zero (unset). +// +// NOTE: Zero-value governance override caveat — because zero is used as a sentinel +// for "unset" (triggering the default fallback), it is not possible to set any of +// these parameters to 0 via a governance proposal. For example, setting +// CbMissThresholdPct=0 to disable threshold-based exclusion will be silently +// ignored and the default (DefaultCBMissThresholdPct=25) will be used instead. +// This is intentional: a threshold of 0 would immediately exclude every node. +// If disabling the circuit breaker is needed, prefer very large values +// (e.g. CbMissThresholdPct=100 or CbMinSamples=MaxUint64) rather than zero. func (k Keeper) getCBParams(ctx context.Context) cbParams { p := cbParams{ MissThresholdPct: DefaultCBMissThresholdPct, diff --git a/inference-chain/x/inference/types/keys.go b/inference-chain/x/inference/types/keys.go index d16ed118b..715312bca 100644 --- a/inference-chain/x/inference/types/keys.go +++ b/inference-chain/x/inference/types/keys.go @@ -75,9 +75,11 @@ var ( SubnetEscrowCounterPrefix = collections.NewPrefix(49) SubnetEscrowEpochCountPrefix = collections.NewPrefix(50) SubnetHostEpochStatsPrefix = collections.NewPrefix(51) - SubnetEscrowsByEpochPrefix = collections.NewPrefix(52) - CircuitBreakerStatePrefix = collections.NewPrefix(53) - ParamsKey = []byte("p_inference") + SubnetEscrowsByEpochPrefix = collections.NewPrefix(52) + // Note: prefix 53 is reserved for circuit breaker state; the implementation uses + // the string-based CircuitBreakerStateKey with KeyPrefix() for consistency with + // other string-keyed stores in this module. Do not reuse prefix 53. + ParamsKey = []byte("p_inference") ) func KeyPrefix(p string) []byte {