Fixes the three defects PLAN.md section 6 lists. The previous-note glob is
constrained to the date pattern, so a .sync-conflict- sibling can no longer
be selected as the file to carry forward, which is the likeliest origin of
how those conflicts spread. The retitle is line 1 only, so a body line like
"meeting moved to 2026-09-08" is no longer silently advanced a day. The dead
`&& cd -` is gone.
Pull before the edit, push after. Error handling is shaped by the CrowdSec
rules in section 5 rather than by generic retry logic: a 401 stops dead with
a message, a 404 means the timer has not run yet so it creates once and
never polls, and anything else degrades to editing the local copy.
The offline fallback shells out to the same prune.py the server rollover
uses, installed to ~/.local/lib/todo, so the two cannot drift.
Since SFTPGo ignores If-Match, the precondition is enforced client side by
comparing the ETag captured at pull against a HEAD before the PUT. A remote
that moved mid-edit produces a .sync-conflict- sibling and a non-zero exit
rather than an overwrite. Real merging is phase 5; this just makes phase 2
incapable of losing an edit.
The credential comes from rbw and reaches curl over stdin, never argv, where
any other user's ps could read it.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01PU5ZFfQFtDTFqqhvMTWdGH