Adds crates/didbot-serve/tests/deploy_restart.rs. It runs the real didbot-pds, stops it with SIGTERM, and starts the next process on the same port and --data, the way a deploy does. The first test writes every 20 ms across the deploy and asserts the longest unanswered span is under OUTAGE_BUDGET (2 s; about 0.1 s here). Every acknowledged write must be listed afterwards. As soon as the new process listens, three returning clients come back at their full per-address share: 8 held subscribeRepos streams, 8 getRepo reads and 8 getBlob reads. None may be refused. The second test signs in with jacquard's loopback client. After the deploy, the pre-deploy access token still writes (after the use_dpop_nonce retry), and the pre-deploy refresh token still refreshes. Both run in the normal suite in about 1.7 s.
The third test is ignored by default, and scripts/rollback-check.sh <rev> runs it. The script builds <rev>'s didbot-pds without debug info in a scratch worktree. This commit then writes a data directory with records, a blob, an agent token and an app login that has refreshed. <rev>'s binary must start on that directory, serve all of it, and take writes. Then this commit must read back what <rev> wrote. It passes against 7901efecd, the commit before the record-size-limit and parked-key-token changes. docs/operations.md ("Rolling back") points to the script. support/process.rs gains start_on and start_exe_on.
Checked by breaking the code and running each test against it. With a stop that waits out its 10 s drain, the client went unanswered for 10.1 s and the test failed. With the stream limit off by one, the 8th stream got a 429. When the boot skipped restoring pds.grants, the old access token got invalid_token. When this commit wrote a pds.grants field under a new name, 7901efecd refused the directory with missing field `currentAccess` , and the rollback test failed.
🤖 Generated with Claude Code