# Harden dev:seed against state it cannot settle · pingdotgg/t3code

[View on GitCafe](https://git.cafe/pingdotgg/t3code/commit/373e7919d14b0bad48e1c4e830270f0181e3e99a)

Repository: [pingdotgg/t3code](https://git.cafe/pingdotgg/t3code)

Visibility: public

Requested revision: 373e7919d14b0bad48e1c4e830270f0181e3e99a

Requested commit: 373e7919d14b0bad48e1c4e830270f0181e3e99a

Commit: 373e7919d14b0bad48e1c4e830270f0181e3e99a

Tree: 180d9d9fc1f8f9d17d47f944141ff25cbad74f58

Author: Theo Browne

Committer: Theo Browne

## Message

```
Harden dev:seed against state it cannot settle

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>

```

## Parents

- [180070865e5137d4021939778f8d33fc5c892b75](https://git.cafe/pingdotgg/t3code/commit/180070865e5137d4021939778f8d33fc5c892b75?format=markdown)

[Source at this commit](https://git.cafe/pingdotgg/t3code/tree/373e7919d14b0bad48e1c4e830270f0181e3e99a?format=markdown)
