Skip to content

peer-sync: conflicts converge via contested-freeze and notify both sides #158

Description

@mbertschler

Problem (friction log F27, S1 — confirmed live)

Divergent edits of the same path on two peers ping-pong forever: each side's scheduled push re-asserts its version in turn, every cadence tick mints another .squirrel-conflicts/run-N/ copy on the receiver (run-393, 396, 398, 405… observed growing every 30s in the walk), the live file flip-flops — and no human is ever told: the initiators' scheduler logs carry no conflict signal (SyncRunReport has no conflict field), the receiver's CONFLICTS column is visible only on the hub, and the losing machine's own surfaces show all-green 0-file syncs while its local file silently diverges. Nothing was lost (both versions preserved every round — the no-loss principle held), but convergence never happens and the conflict store grows unboundedly.

Decision (Martin, 2026-07-24 — option 2a: contested-freeze)

After a conflict, the receiver marks the path contested:

  • Automated re-supersedes of a contested path from any peer are refused with a new contested disposition — preserved once, not every tick; the flip-flop stops at the first conflict.
  • Both initiators receive a conflict signal: conflict counts flow into SyncRunReport, the initiators' run rows, scheduler log lines, and a TUI badge — on their machines, not just the hub.
  • A new question/change command pair: squirrel conflicts lists unresolved contested paths (path, versions, preserved locations, when, who); squirrel conflicts resolve <path> (pick a version or accept the current live one) clears the contested state and lets syncs flow again. Resolution is an explicit human act, per the "irreversible acts remain human" principle.

Plan sketch

  • Contested state on the receiver's file row (schema migration + snapshot regen); /plan classifier returns contested for such paths; wire disposition through syncproto (version-gated for older peers).
  • Initiator-side: surface conflicts/contested counts in report → scheduler log → runs row → TUI.
  • squirrel conflicts + resolve subcommands (separate files per cobra convention).
  • Walk scenario 6 in design/testbed.md re-run as the acceptance test: one conflict dir, immediate freeze, badges on both edges, resolve unfreezes.

See design/friction-log.md F27.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions