feat(sync): add per-field merge strategies for conflict resolution
Implements configurable per-field merge strategies (hq-ew1mbr.11):
- Add FieldStrategy type with strategies: newest, max, union, manual
- Add conflict.fields config section for per-field overrides
- compaction_level defaults to "max" (highest value wins)
- estimated_minutes defaults to "manual" (flags for user resolution)
- labels defaults to "union" (set merge)
Manual conflicts are displayed during sync with resolution options:
bd sync --ours / --theirs, or bd resolve <id> <field> <value>
Config example:
conflict:
strategy: newest
fields:
compaction_level: max
estimated_minutes: manual
labels: union
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
committed by
Steve Yegge
parent
e0dc3a37c3
commit
9a9704b451
@@ -478,3 +478,57 @@ func TestSovereigntyString(t *testing.T) {
|
||||
t.Errorf("SovereigntyNone.String() = %q, want %q", got, "")
|
||||
}
|
||||
}
|
||||
|
||||
func TestFieldStrategyString(t *testing.T) {
|
||||
tests := []struct {
|
||||
strategy FieldStrategy
|
||||
expected string
|
||||
}{
|
||||
{FieldStrategyNewest, "newest"},
|
||||
{FieldStrategyMax, "max"},
|
||||
{FieldStrategyUnion, "union"},
|
||||
{FieldStrategyManual, "manual"},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
if got := tt.strategy.String(); got != tt.expected {
|
||||
t.Errorf("%v.String() = %q, want %q", tt.strategy, got, tt.expected)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestValidFieldStrategies(t *testing.T) {
|
||||
strategies := ValidFieldStrategies()
|
||||
if len(strategies) != 4 {
|
||||
t.Errorf("ValidFieldStrategies() returned %d strategies, want 4", len(strategies))
|
||||
}
|
||||
expected := []string{"newest", "max", "union", "manual"}
|
||||
for i, s := range strategies {
|
||||
if s != expected[i] {
|
||||
t.Errorf("ValidFieldStrategies()[%d] = %q, want %q", i, s, expected[i])
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestIsValidFieldStrategy(t *testing.T) {
|
||||
tests := []struct {
|
||||
strategy string
|
||||
valid bool
|
||||
}{
|
||||
{"newest", true},
|
||||
{"max", true},
|
||||
{"union", true},
|
||||
{"manual", true},
|
||||
{"NEWEST", true}, // case insensitive
|
||||
{" max ", true}, // whitespace trimmed
|
||||
{"invalid", false},
|
||||
{"lww", false},
|
||||
{"", false},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
if got := IsValidFieldStrategy(tt.strategy); got != tt.valid {
|
||||
t.Errorf("IsValidFieldStrategy(%q) = %v, want %v", tt.strategy, got, tt.valid)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user