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.
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 (SyncRunReporthas 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:
contesteddisposition — preserved once, not every tick; the flip-flop stops at the first conflict.SyncRunReport, the initiators' run rows, scheduler log lines, and a TUI badge — on their machines, not just the hub.squirrel conflictslists 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
/planclassifier returnscontestedfor such paths; wire disposition throughsyncproto(version-gated for older peers).squirrel conflicts+resolvesubcommands (separate files per cobra convention).design/testbed.mdre-run as the acceptance test: one conflict dir, immediate freeze, badges on both edges, resolve unfreezes.See
design/friction-log.mdF27.