Sanitized server-only runtime evidence — issue 25289 Visual matrix: empty, confirmed by lead proof-audit. Proof: prior red test + actual runtime transcript. No server or browser was started during evidence assembly. No source was changed. Base/main: [0a3b561bc0](https://git.cafe/pingdotgg/t3code/commit/0a3b561bc0901d8fa47e430fc9d8593918cde978) Fix head: [d511961ca4](https://git.cafe/pingdotgg/t3code/commit/d511961ca4d815066b2a979270a77a1698d72181) BEFORE — supplied lead capture (not rerun during assembly) Issue 25289: preview migration collision Environment: fs-11, Linux x86_64, Node 26.12.1; isolated checkout /home/ubuntu/wt/issue-25289 Before: main [0a3b561bc0](https://git.cafe/pingdotgg/t3code/commit/0a3b561bc0901d8fa47e430fc9d8593918cde978) Read-only source history (SELECT migration_id,name FROM effect_sql_migrations WHERE migration_id>=65): 65 CodexUsageNativeTurnIndex 66 RepairClientSettlementTimestamps 67 WebhookDedupe 68 PeerLinks 69 PeerLinkFence 70 WaitingLinkRequestIndex Attempt 1: vp run migrate-dev-db Source opened read-only; snapshot copied under worktree .t3/userdata. Result: MigrateDevDbPhaseError during migrate, caused by: MigrationError: This database's migration history would skip required schema migrations: 68_ShellStopRequestIndex (recorded: PeerLinks), 69_ThreadMessageSearch (recorded: PeerLinkFence). The migrator skips every id up to the highest recorded id (70), regardless of name. Attempt 2: SQLite backup API copied source opened with mode=ro into worktree .t3/userdata/statev2.sqlite; vp run dev --no-seed [dev-runner] mode=dev source=worktree serverPort=15602 webPort=7562 baseDir=/home/ubuntu/wt/issue-25289/.t3 Vite ready. Server startup failed: [03:48:17.187] ERROR (#2): MigrationError: This database's migration history would skip required schema migrations: 68_ShellStopRequestIndex (recorded: PeerLinks), 69_ThreadMessageSearch (recorded: PeerLinkFence). The migrator skips every id up to the highest recorded id (70), regardless of name. at assertV2MigrationsCanRun at runMigrations at server.runServerCommand Failed running 'src/bin.ts'. Waiting for file changes before restarting... Stopped the spawned dev runner with Ctrl-C. No server reached ready state. Red test (commit [e06dfa6a90](https://git.cafe/pingdotgg/t3code/commit/e06dfa6a9015490699c01143c02ccf1c40e769af)): vp test run src/persistence/Migrations.test.ts (from apps/server) 1 failed, 7 passed. Failure: same MigrationError at Migrations.ts:189. Test: upgrades a 0.1.2-preview.3511 database with peer links recorded at 68-70 AFTER — actual captured migration command: vp run migrate-dev-db $ node apps/server/scripts/migrate-dev-db.ts ⊘ cache disabled Copying visible threads from /home/ubuntu/.t3/userdata/statev2.sqlite (read-only)... Running migrations on the snapshot... [03:54:09.435] INFO (#1): Migrations ran successfully { migrations: [ '68_ShellStopRequestIndex', '69_ThreadMessageSearch' ] } [03:54:09.436] WARN (#1): Database migration history diverges from this build; recorded migration ids are skipped, not reconciled by name. { divergent: [ '70:PeerLinks (unknown to this build)', '71:PeerLinkFence (unknown to this build)', '72:WaitingLinkRequestIndex (unknown to this build)' ] } Pruning to 5 projects, 10 stopped threads each... Compacting into /home/ubuntu/wt/issue-25289/.t3/userdata/statev2.sqlite... Dev database ready: /home/ubuntu/wt/issue-25289/.t3/userdata/statev2.sqlite (91.8 MB) 11533 orchestration events kept Migrations applied: 68_ShellStopRequestIndex, 69_ThreadMessageSearch Aggregate pruning result from lead capture: 37 stopped threads retained; database 91.8 MB. Project labels omitted. AFTER — actual captured startup command: vp run dev --no-seed [03:54:27.137] INFO (#1): [dev-runner] mode=dev source=worktree /home/ubuntu/wt/issue-25289 serverPort=15602 webPort=7562 baseDir=/home/ubuntu/wt/issue-25289/.t3 [03:54:34.719] WARN (#48): Database migration history diverges from this build; recorded migration ids are skipped, not reconciled by name. divergent: [ '70:PeerLinks (unknown to this build)', '71:PeerLinkFence (unknown to this build)', '72:WaitingLinkRequestIndex (unknown to this build)' ] [03:54:36.125] INFO (#6516): Listening [startup address omitted] [03:54:36.547] INFO (#6513): V2 orchestration recovery completed { terminalizedRuns: 0, stoppedSessions: 0, closedRequests: 0, retiredEffects: 0, requeuedEffects: 0 } Lead stopped the spawned dev runner via its captured session with Ctrl-C. FRICTION: GET /api/health returned 404; this route does not exist. No health-200 claim is made. Readiness evidence is Listening at 03:54:36.125 and completed recovery at 03:54:36.547 with all five recovery counts zero. CURRENT ISOLATED DATABASE — read-only verification during assembly Python sqlite3.connect('file:/home/ubuntu/wt/issue-25289/.t3/userdata/statev2.sqlite?mode=ro', uri=True) Only migration history and sqlite_master schema were queried; no thread/project contents were read for this evidence. SQL: SELECT migration_id,name FROM effect_sql_migrations WHERE migration_id BETWEEN 68 AND 72 ORDER BY migration_id; 68 ShellStopRequestIndex 69 ThreadMessageSearch 70 PeerLinks 71 PeerLinkFence 72 WaitingLinkRequestIndex SQL: SELECT type,name,sql FROM sqlite_master WHERE name IN ('orchestration_v2_projection_turn_items_stop_request_idx','orchestration_v2_projection_turn_items_waiting_link_idx','orchestration_v2_message_search') OR (type='trigger' AND name LIKE 'orchestration_v2_message_search_%') ORDER BY type,name; index: orchestration_v2_projection_turn_items_stop_request_idx CREATE INDEX orchestration_v2_projection_turn_items_stop_request_idx ON orchestration_v2_projection_turn_items(thread_id, run_id) WHERE type = 'run_interrupt_request' index: orchestration_v2_projection_turn_items_waiting_link_idx CREATE INDEX orchestration_v2_projection_turn_items_waiting_link_idx ON orchestration_v2_projection_turn_items(thread_id, updated_at DESC, turn_item_id DESC) WHERE type = 'link_request' AND status = 'waiting' table: orchestration_v2_message_search CREATE VIRTUAL TABLE orchestration_v2_message_search USING fts5( text, content = '', contentless_delete = 1, tokenize = 'trigram remove_diacritics 1' ) trigger: orchestration_v2_message_search_delete CREATE TRIGGER orchestration_v2_message_search_delete AFTER DELETE ON orchestration_v2_projection_messages WHEN old.streaming = 0 BEGIN DELETE FROM orchestration_v2_message_search WHERE rowid = old.rowid; END trigger: orchestration_v2_message_search_insert CREATE TRIGGER orchestration_v2_message_search_insert AFTER INSERT ON orchestration_v2_projection_messages WHEN new.streaming = 0 AND ( new.role = 'assistant' OR ( new.role = 'user' AND COALESCE(json_extract(new.payload_json, '$.createdBy'), 'user') = 'user' ) ) AND NOT EXISTS ( SELECT 1 FROM orchestration_v2_projection_threads AS subagent_threads WHERE subagent_threads.thread_id = new.thread_id AND json_extract(subagent_threads.payload_json, '$.lineage.relationshipToParent') = 'subagent' ) BEGIN INSERT INTO orchestration_v2_message_search (rowid, text) SELECT new.rowid, replace(replace(json_extract(new.payload_json, '$.text'), '’', ''''), '‘', '''') WHERE json_extract(new.payload_json, '$.text') IS NOT NULL; END trigger: orchestration_v2_message_search_update CREATE TRIGGER orchestration_v2_message_search_update AFTER UPDATE OF payload_json, streaming, role ON orchestration_v2_projection_messages WHEN (old.streaming = 0 OR new.streaming = 0) AND ( old.streaming IS NOT new.streaming OR old.role IS NOT new.role OR json_extract(old.payload_json, '$.text') IS NOT json_extract(new.payload_json, '$.text') OR json_extract(old.payload_json, '$.createdBy') IS NOT json_extract(new.payload_json, '$.createdBy') ) BEGIN DELETE FROM orchestration_v2_message_search WHERE rowid = old.rowid AND old.streaming = 0; INSERT INTO orchestration_v2_message_search (rowid, text) SELECT new.rowid, replace(replace(json_extract(new.payload_json, '$.text'), '’', ''''), '‘', '''') WHERE new.streaming = 0 AND ( new.role = 'assistant' OR ( new.role = 'user' AND COALESCE(json_extract(new.payload_json, '$.createdBy'), 'user') = 'user' ) ) AND NOT EXISTS ( SELECT 1 FROM orchestration_v2_projection_threads AS subagent_threads WHERE subagent_threads.thread_id = new.thread_id AND json_extract(subagent_threads.payload_json, '$.lineage.relationshipToParent') = 'subagent' ) AND json_extract(new.payload_json, '$.text') IS NOT NULL; END LIMITATION: The recorded peer migrations 70 PeerLinks, 71 PeerLinkFence, and 72 WaitingLinkRequestIndex remain unknown to this build. Base/main has no peer migration implementations (git ls-tree checked); this evidence does not claim that main implements or fully validates their behavior. The fix preserves their existing schema/history while applying main migrations 68/69. The startup divergence warning is retained above. Sanitization: startup pairing token/URL, project labels, secrets, thread/project contents, and database data are excluded. Only selected runtime lines, aggregate counts, migration names, and schema are included. Original logs and full database are not uploaded.