Review of the seeding path found five ways a seeded database could describe something the copy cannot back up: - Nothing stopped `dev:seed` from running against a live server. SQLite locking lets the seed take the write lock between the server's own writes and commit cleanly; what it cannot do is tell that server its projections and event log were replaced underneath it. Refuse instead, via a pid probe over both state directories. - A thread copied mid-turn kept `state = 'running'`. The session override did not cover it — the turn is read independently, and an unsettled one leaves the thread spinning and its timeline unfoldable forever. Settle those to "interrupted", matching what the server does when a session leaves "running". Streaming messages are finished for the same reason. - Attachment metadata was copied without the files behind it, so a seeded thread rendered an image whose request 404s. Report the referenced ids and copy the matching files alongside the rows. - Orphaned `provider_session_runtime` rows survived the seed naming threads it had just deleted, which the session reaper then tried to stop against a provider instance the worktree may not define. - `--threads` had no upper bound, so a large enough value died with "too many SQL variables" after the target was already emptied. Also corrects the projector-cursor comment: `orchestration_events.sequence` is AUTOINCREMENT, so emptying the log does not reset its high-water mark and sequence does not restart at 1. Zero remains the right cursor, for the reason now stated. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Theo Browne committed on 7/27/2026, 3:38:48 AMparent1800708
9 files changedLine totals unavailable