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:
beads/crew/lydia
2026-01-21 19:39:20 -08:00
committed by Steve Yegge
parent e0dc3a37c3
commit 9a9704b451
9 changed files with 698 additions and 91 deletions

View File

@@ -69,7 +69,7 @@ func resolveConflictsInteractively(conflicts []InteractiveConflict) ([]*beads.Is
for j := i; j < len(conflicts); j++ {
c := conflicts[j]
if c.Local != nil && c.Remote != nil {
merged := mergeFieldLevel(c.Base, c.Local, c.Remote)
merged, _ := mergeFieldLevel(c.Base, c.Local, c.Remote)
resolved = append(resolved, merged)
} else if c.Local != nil {
resolved = append(resolved, c.Local)
@@ -293,7 +293,7 @@ func promptConflictResolution(reader *bufio.Reader, conflict InteractiveConflict
case "merged":
// Do field-level merge (same as automatic LWW merge)
merged := mergeFieldLevel(conflict.Base, local, remote)
merged, _ := mergeFieldLevel(conflict.Base, local, remote)
return InteractiveResolution{Choice: "merged", Issue: merged}, nil
case "skip":