Skip to content

fix(scripts): add recover-dev-db.sql for fork-branch migration mismatch - #15

Closed
Benniphx wants to merge 1 commit into
42tg:mainfrom
Benniphx:fix/recover-dev-db-from-fork-migrations
Closed

Benniphx wants to merge 1 commit into
42tg:mainfrom
Benniphx:fix/recover-dev-db-from-fork-migrations

Conversation

@Benniphx

Copy link
Copy Markdown
Collaborator

Problem

Local dev DBs that were grown on a fork branch can fail to start bun run dev after switching back to main:

SQLiteError: no such column: default_model_selection_json
ProviderSessionDirectoryPersistenceError: Unknown persisted provider 'claudeCode'.

The Effect-SQL migrator tracks migrations by numeric ID only. If a DB has IDs 14–18 recorded from a fork timeline that used different migrations under those IDs, main's 14–18 are silently skipped — leaving the schema half-converted.

Concrete divergence I hit (Tobias' fork → main):

ID Fork (recorded in DB) main (never runs)
14 ProjectionThreadActivityParentAndItemId ProjectionThreadProposedPlanImplementation
15 ProjectionThreadsJiraTicket ProjectionTurnsSourceProposedPlan
16 ReviewComments CanonicalizeModelSelections (the painful one)
17 ReviewRequests ProjectionThreadsArchivedAt
18 ReviewRequestsPrMeta ProjectionThreadsArchivedAtIndex

Plus the claudeCode → claudeAgent provider rename was code-only, so legacy rows still reference claudeCode.

What this PR does

Adds scripts/recover-dev-db.sql — a single-transaction recovery script that:

  1. Renames claudeCode → claudeAgent in provider_session_runtime (provider_name + adapter_key), projection_thread_sessions.provider_name, and orchestration_events.payload_json.
  2. Applies the missing schema deltas for main migrations 14–18:
    • 14 projection_thread_proposed_plans: implemented_at, implementation_thread_id
    • 15 projection_turns: source_proposed_plan_thread_id, source_proposed_plan_id
    • 16 CanonicalizeModelSelections — adds default_model_selection_json (projects), model_selection_json (threads), drops default_model/model, and ports orchestration_events payloads (project.created, project.meta-updated, thread.created, thread.meta-updated, thread.turn-start-requested) to the new modelSelection shape.
    • 17 projection_threads.archived_at
    • 18 idx_projection_threads_project_archived_at
  3. Does not touch effect_sql_migrations — IDs 14–21 are already recorded as applied, so no migration will be re-run.

Recommended path: keep your data (Option B)

This is the path teammates should default to — wiping the DB loses all local sessions.

# 1. Stop the dev server
# 2. Backup
cp ~/.t3/dev/state.sqlite ~/.t3/dev/state.sqlite.bak-$(date +%Y%m%d-%H%M%S)
# 3. Apply
sqlite3 ~/.t3/dev/state.sqlite < scripts/recover-dev-db.sql
# 4. Start
bun run dev

Fallback only: nuke and re-create (Option A)

Use this only if Option B somehow doesn't work for you. You will lose all local dev sessions.

TS=$(date +%Y%m%d-%H%M%S)
mv ~/.t3/dev/state.sqlite     ~/.t3/dev/state.sqlite.bak-$TS
mv ~/.t3/dev/state.sqlite-shm ~/.t3/dev/state.sqlite-shm.bak-$TS 2>/dev/null
mv ~/.t3/dev/state.sqlite-wal ~/.t3/dev/state.sqlite-wal.bak-$TS 2>/dev/null
bun run dev

Verification

After running the script:

sqlite3 ~/.t3/dev/state.sqlite "
  SELECT 'default_model_selection_json:', COUNT(*) FROM pragma_table_info('projection_projects') WHERE name='default_model_selection_json'
  UNION ALL SELECT 'model_selection_json:', COUNT(*) FROM pragma_table_info('projection_threads')  WHERE name='model_selection_json'
  UNION ALL SELECT 'archived_at:',          COUNT(*) FROM pragma_table_info('projection_threads')  WHERE name='archived_at'
  UNION ALL SELECT 'claudeCode rest:',      COUNT(*) FROM provider_session_runtime WHERE provider_name='claudeCode';
"

First three should be 1, last should be 0. Tested locally on a real fork-grown DB (~3.7 MB, ~200 events with claudeCode references) — all checks green, dev server starts cleanly, sessions intact.

Out of scope (but worth a follow-up)

The root cause — migrator keying only on ID — is what makes this class of break possible. A future change could verify recorded migration names match expected ones at startup and warn or fail fast.

Local dev DBs that were built up on a fork branch can have migration
IDs 14-18 recorded that map to different migrations than the ones on
main. The Effect-SQL migrator only tracks numeric IDs, so main's
migrations 14-18 never run on those DBs, producing errors like:

  SQLiteError: no such column: default_model_selection_json
  ProviderSessionDirectoryPersistenceError: Unknown persisted provider
    'claudeCode'.

This script applies the missing schema deltas (migrations 14-18) and
renames the legacy 'claudeCode' provider to 'claudeAgent', without
touching effect_sql_migrations.

Usage:
  cp ~/.t3/dev/state.sqlite ~/.t3/dev/state.sqlite.bak
  sqlite3 ~/.t3/dev/state.sqlite < scripts/recover-dev-db.sql
@github-actions github-actions Bot added size:L vouch:unvouched PR author is not yet trusted in the VOUCHED list. labels Apr 13, 2026
@Benniphx

Copy link
Copy Markdown
Collaborator Author

Closing in favor of a same-repo PR — got WRITE access in the meantime.

@Benniphx Benniphx closed this Apr 13, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size:L vouch:unvouched PR author is not yet trusted in the VOUCHED list.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant