refactor(config): improve sync config with warnings toggle and dedup

Code review improvements to internal/config/sync.go:

1. Warning suppression toggle
   - Add ConfigWarnings bool to enable/disable warnings
   - Add ConfigWarningWriter io.Writer for testable output

2. Consolidate sync mode constants
   - cmd/bd/sync_mode.go now imports from internal/config
   - Single source of truth for mode values
   - Uses shared IsValidSyncMode() for validation

3. Fix empty sovereignty semantics
   - Empty now returns SovereigntyNone (no restriction)
   - Only non-empty invalid values fall back to T1 with warning

4. Export validation helpers
   - IsValidSyncMode(), IsValidConflictStrategy(), IsValidSovereignty()
   - ValidSyncModes(), ValidConflictStrategies(), ValidSovereigntyTiers()
   - String() methods on all typed values

5. Logger interface
   - ConfigWarningWriter allows custom logging destinations
   - Tests can capture warnings without os.Stderr manipulation

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
collins
2026-01-19 11:49:33 -08:00
committed by Steve Yegge
parent 80cd1f35c0
commit 521239cfdc
4 changed files with 308 additions and 72 deletions

View File

@@ -2,6 +2,7 @@ package config
import (
"fmt"
"io"
"os"
"strings"
)
@@ -9,6 +10,21 @@ import (
// Sync mode configuration values (from hq-ew1mbr.3)
// These control how Dolt syncs with JSONL/remotes.
// ConfigWarnings controls whether warnings are logged for invalid config values.
// Set to false to suppress warnings (useful for tests or scripts).
var ConfigWarnings = true
// ConfigWarningWriter is the destination for config warnings.
// Defaults to os.Stderr. Can be replaced for testing or custom logging.
var ConfigWarningWriter io.Writer = os.Stderr
// logConfigWarning logs a warning message if ConfigWarnings is enabled.
func logConfigWarning(format string, args ...interface{}) {
if ConfigWarnings && ConfigWarningWriter != nil {
fmt.Fprintf(ConfigWarningWriter, format, args...)
}
}
// SyncMode represents the sync mode configuration
type SyncMode string
@@ -31,6 +47,21 @@ var validSyncModes = map[SyncMode]bool{
SyncModeBeltAndSuspenders: true,
}
// ValidSyncModes returns the list of valid sync mode values.
func ValidSyncModes() []string {
return []string{
string(SyncModeGitPortable),
string(SyncModeRealtime),
string(SyncModeDoltNative),
string(SyncModeBeltAndSuspenders),
}
}
// IsValidSyncMode returns true if the given string is a valid sync mode.
func IsValidSyncMode(mode string) bool {
return validSyncModes[SyncMode(strings.ToLower(strings.TrimSpace(mode)))]
}
// ConflictStrategy represents the conflict resolution strategy
type ConflictStrategy string
@@ -53,10 +84,27 @@ var validConflictStrategies = map[ConflictStrategy]bool{
ConflictStrategyManual: true,
}
// ValidConflictStrategies returns the list of valid conflict strategy values.
func ValidConflictStrategies() []string {
return []string{
string(ConflictStrategyNewest),
string(ConflictStrategyOurs),
string(ConflictStrategyTheirs),
string(ConflictStrategyManual),
}
}
// IsValidConflictStrategy returns true if the given string is a valid conflict strategy.
func IsValidConflictStrategy(strategy string) bool {
return validConflictStrategies[ConflictStrategy(strings.ToLower(strings.TrimSpace(strategy)))]
}
// Sovereignty represents the federation sovereignty tier
type Sovereignty string
const (
// SovereigntyNone means no sovereignty restriction (empty value)
SovereigntyNone Sovereignty = ""
// SovereigntyT1 is the most open tier (public repos)
SovereigntyT1 Sovereignty = "T1"
// SovereigntyT2 is organization-level
@@ -67,7 +115,7 @@ const (
SovereigntyT4 Sovereignty = "T4"
)
// validSovereigntyTiers is the set of allowed sovereignty values
// validSovereigntyTiers is the set of allowed sovereignty values (excluding empty)
var validSovereigntyTiers = map[Sovereignty]bool{
SovereigntyT1: true,
SovereigntyT2: true,
@@ -75,9 +123,28 @@ var validSovereigntyTiers = map[Sovereignty]bool{
SovereigntyT4: true,
}
// ValidSovereigntyTiers returns the list of valid sovereignty tier values.
func ValidSovereigntyTiers() []string {
return []string{
string(SovereigntyT1),
string(SovereigntyT2),
string(SovereigntyT3),
string(SovereigntyT4),
}
}
// IsValidSovereignty returns true if the given string is a valid sovereignty tier.
// Empty string is valid (means no restriction).
func IsValidSovereignty(sovereignty string) bool {
if sovereignty == "" {
return true
}
return validSovereigntyTiers[Sovereignty(strings.ToUpper(strings.TrimSpace(sovereignty)))]
}
// GetSyncMode retrieves the sync mode configuration.
// Returns the configured mode, or SyncModeGitPortable (default) if not set or invalid.
// Logs a warning to stderr if an invalid value is configured.
// Logs a warning if an invalid value is configured (unless ConfigWarnings is false).
//
// Config key: sync.mode
// Valid values: git-portable, realtime, dolt-native, belt-and-suspenders
@@ -89,7 +156,8 @@ func GetSyncMode() SyncMode {
mode := SyncMode(strings.ToLower(strings.TrimSpace(value)))
if !validSyncModes[mode] {
fmt.Fprintf(os.Stderr, "Warning: invalid sync.mode %q in config (valid: git-portable, realtime, dolt-native, belt-and-suspenders), using default 'git-portable'\n", value)
logConfigWarning("Warning: invalid sync.mode %q in config (valid: %s), using default 'git-portable'\n",
value, strings.Join(ValidSyncModes(), ", "))
return SyncModeGitPortable
}
@@ -98,7 +166,7 @@ func GetSyncMode() SyncMode {
// GetConflictStrategy retrieves the conflict resolution strategy configuration.
// Returns the configured strategy, or ConflictStrategyNewest (default) if not set or invalid.
// Logs a warning to stderr if an invalid value is configured.
// Logs a warning if an invalid value is configured (unless ConfigWarnings is false).
//
// Config key: conflict.strategy
// Valid values: newest, ours, theirs, manual
@@ -110,7 +178,8 @@ func GetConflictStrategy() ConflictStrategy {
strategy := ConflictStrategy(strings.ToLower(strings.TrimSpace(value)))
if !validConflictStrategies[strategy] {
fmt.Fprintf(os.Stderr, "Warning: invalid conflict.strategy %q in config (valid: newest, ours, theirs, manual), using default 'newest'\n", value)
logConfigWarning("Warning: invalid conflict.strategy %q in config (valid: %s), using default 'newest'\n",
value, strings.Join(ValidConflictStrategies(), ", "))
return ConflictStrategyNewest
}
@@ -118,23 +187,39 @@ func GetConflictStrategy() ConflictStrategy {
}
// GetSovereignty retrieves the federation sovereignty tier configuration.
// Returns the configured tier, or SovereigntyT1 (default) if not set or invalid.
// Logs a warning to stderr if an invalid value is configured.
// Returns the configured tier, or SovereigntyNone (empty, no restriction) if not set.
// Returns SovereigntyT1 and logs a warning if an invalid non-empty value is configured.
//
// Config key: federation.sovereignty
// Valid values: T1, T2, T3, T4
// Valid values: T1, T2, T3, T4 (empty means no restriction)
func GetSovereignty() Sovereignty {
value := GetString("federation.sovereignty")
if value == "" {
return SovereigntyT1 // Default
return SovereigntyNone // No restriction
}
// Normalize to uppercase for comparison (T1, T2, etc.)
tier := Sovereignty(strings.ToUpper(strings.TrimSpace(value)))
if !validSovereigntyTiers[tier] {
fmt.Fprintf(os.Stderr, "Warning: invalid federation.sovereignty %q in config (valid: T1, T2, T3, T4), using default 'T1'\n", value)
logConfigWarning("Warning: invalid federation.sovereignty %q in config (valid: %s, or empty for no restriction), using 'T1'\n",
value, strings.Join(ValidSovereigntyTiers(), ", "))
return SovereigntyT1
}
return tier
}
// String returns the string representation of the SyncMode.
func (m SyncMode) String() string {
return string(m)
}
// String returns the string representation of the ConflictStrategy.
func (s ConflictStrategy) String() string {
return string(s)
}
// String returns the string representation of the Sovereignty.
func (s Sovereignty) String() string {
return string(s)
}