995576358f
The CRDT lamport seq is per-author and per-field, not globally monotonic. Replaying by `seq ASC` causes field-update ops (which have low per-field seq counters like 1, 2, 3) to be applied BEFORE the list-insert ops they reference (which have higher per-list seq counters like N for the Nth item ever inserted). The field updates fail with ErrPathMismatch because the target item doesn't exist yet, the field counter is never advanced, and subsequent writes silently lose state. Concretely on 2026-04-09 we observed: post-restart writes were being persisted at seq=1,2,3,4,5,6,7 even though pre-restart seq had reached 492. On the next replay, those low-seq field updates would be applied before their seq=485+ creation ops, silently dropping the updates. This was the load-bearing "why does state keep flapping" bug today. Fix: replay by `rowid ASC` (SQLite insertion order) instead. Rowid preserves the causal order ops were originally applied in, so field updates always come after the item insert they reference. Adds a regression test that constructs the exact scenario: inserts a story (op gets seq=6), updates its stage (op gets seq=1 because field counter starts at 0), persists both ops in causal order, then replays both seq ASC (reproduces the bug — stage update is lost) and rowid ASC (the fix — stage update is preserved). Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>