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

@@ -4,26 +4,29 @@ import (
"context"
"fmt"
"github.com/steveyegge/beads/internal/config"
"github.com/steveyegge/beads/internal/storage"
)
// Sync mode constants define how beads synchronizes data with git.
// Sync mode constants - re-exported from internal/config for backward compatibility.
// These are used with storage.Storage (database) while config.SyncMode* are used
// with viper (config.yaml).
const (
// SyncModeGitPortable exports to JSONL on push, imports on pull.
// This is the default mode - works with standard git workflows.
SyncModeGitPortable = "git-portable"
SyncModeGitPortable = string(config.SyncModeGitPortable)
// SyncModeRealtime exports to JSONL on every database mutation.
// Provides immediate persistence but more git noise.
SyncModeRealtime = "realtime"
SyncModeRealtime = string(config.SyncModeRealtime)
// SyncModeDoltNative uses Dolt remotes for sync, skipping JSONL.
// Requires Dolt backend and configured Dolt remote.
SyncModeDoltNative = "dolt-native"
SyncModeDoltNative = string(config.SyncModeDoltNative)
// SyncModeBeltAndSuspenders uses both Dolt remotes AND JSONL.
// Maximum redundancy - Dolt for versioning, JSONL for git portability.
SyncModeBeltAndSuspenders = "belt-and-suspenders"
SyncModeBeltAndSuspenders = string(config.SyncModeBeltAndSuspenders)
// SyncModeConfigKey is the database config key for sync mode.
SyncModeConfigKey = "sync.mode"
@@ -45,32 +48,29 @@ const (
TriggerChange = "change"
)
// GetSyncMode returns the configured sync mode, defaulting to git-portable.
// GetSyncMode returns the configured sync mode from the database, defaulting to git-portable.
// This reads from storage.Storage (database), not config.yaml.
// For config.yaml access, use config.GetSyncMode() instead.
func GetSyncMode(ctx context.Context, s storage.Storage) string {
mode, err := s.GetConfig(ctx, SyncModeConfigKey)
if err != nil || mode == "" {
return SyncModeGitPortable
}
// Validate mode
switch mode {
case SyncModeGitPortable, SyncModeRealtime, SyncModeDoltNative, SyncModeBeltAndSuspenders:
return mode
default:
// Invalid mode, return default
// Validate mode using the shared validation
if !config.IsValidSyncMode(mode) {
return SyncModeGitPortable
}
return mode
}
// SetSyncMode sets the sync mode configuration.
// SetSyncMode sets the sync mode configuration in the database.
func SetSyncMode(ctx context.Context, s storage.Storage, mode string) error {
// Validate mode
switch mode {
case SyncModeGitPortable, SyncModeRealtime, SyncModeDoltNative, SyncModeBeltAndSuspenders:
// Valid
default:
return fmt.Errorf("invalid sync mode: %s (valid: %s, %s, %s, %s)",
mode, SyncModeGitPortable, SyncModeRealtime, SyncModeDoltNative, SyncModeBeltAndSuspenders)
// Validate mode using the shared validation
if !config.IsValidSyncMode(mode) {
return fmt.Errorf("invalid sync mode: %s (valid: %s)",
mode, fmt.Sprintf("%v", config.ValidSyncModes()))
}
return s.SetConfig(ctx, SyncModeConfigKey, mode)