8eb316751d
Two concurrency fixes from the 2026-07-06 review (findings M1, M2): sync push (M1): the load→merge→store cycle ran as three separate DB operations. Two devices pushing concurrently both read the same stored payload, merged independently, and the second store overwrote the first merge — the server visibly regressed until the losing device pushed again. The whole cycle (including the leaderboard update) now runs in one transaction; SQLite serialises the writers. The leaderboard helper's stale docstring (claiming a single conditional UPDATE that was actually two statements) is corrected — the transaction now provides the atomicity it described. refresh rotation (M2): SELECT-then-DELETE let two concurrent refreshes with the same token both pass the liveness check and both mint fresh token pairs. The SELECT is gone; rotation now gates on the DELETE's rows_affected — whoever removes the jti row wins, everyone else gets 401. Sequential reuse was already covered by consumed_refresh_token_is_rejected, which still passes unchanged. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>