Skip to content
This repository was archived by the owner on Aug 6, 2026. It is now read-only.

fix(browser-tabs): self-heal schema drift on every boot - #3420

Closed
adamleithp wants to merge 1 commit into
mainfrom
fix/browser-tabs-schema-self-heal
Closed

fix(browser-tabs): self-heal schema drift on every boot#3420
adamleithp wants to merge 1 commit into
mainfrom
fix/browser-tabs-schema-self-heal

Conversation

@adamleithp

Copy link
Copy Markdown
Contributor

Problem

Dev sqlite DBs are shared across branches. A build from the panes branch rebuilds browser_tabs without its target columns (dashboard_id/task_id/channel_id/channel_section/app_view/scroll_state), so back on main every browser-tabs query throws at boot and the tab strip renders a dead "+" that does nothing when clicked.

The existing 0020 repair migration can't help here: it is one-shot. Once the ledger records it as applied, drift that happens afterward (exactly this case) never gets healed.

Changes

  • runMigrations now runs ensureBrowserTabsSchema after every migration pass, an always-on boot invariant rather than a one-shot migration.
  • The expected shape is derived from the migration folder's latest drizzle meta snapshot (the machine-generated source drizzle-kit already maintains), not hardcoded DDL. This means the heal tracks future migrations automatically and can never resurrect columns a later migration deliberately drops.
  • Per table: missing table is created (with indexes) from the snapshot; missing nullable columns are added via ALTER TABLE ADD COLUMN; a variant missing a structural NOT NULL column is rebuilt (tabs are recoverable UI state) instead of stamping rows with fabricated defaults that would create dangling FK references; a non-table squatting on the name (e.g. a VIEW) is skipped.
  • Scope is deliberately limited to the browser-tab tables: they hold recoverable UI state, so the worst outcome of a heal is an empty strip. Data-bearing tables are excluded so their drift stays loud.
  • Everything is best-effort: a statement (or the whole pass) that cannot apply degrades to the pre-heal status quo, never a failed boot.

How did you test this?

  • New unit tests: heals a panes rebuild that postdates the 0020 repair (the reported incident's exact ledger + table shape), rebuilds a variant missing a structural NOT NULL column, and does not inject browser tables into a custom-folder database.
  • All 12 migrate.test.ts tests pass; full workspace-server suite passes except a pre-existing environment-dependent archive.integration.test.ts case (bare git tag fails under tag.gpgsign=true in the local gitconfig, unrelated to this change).
  • Manually confirmed the incident DB shape (dev profile migrated by a panes build) heals: the six missing columns are restored additively and the panes branch's extra columns/tables are left untouched.

Automatic notifications

  • Publish to changelog?
  • Alert Sales and Marketing teams?

🤖 Generated with Claude Code

The 0020 repair migration is one-shot: once the ledger records it,
a later table rebuild by another branch's build (the panes branch
drops the target columns from browser_tabs) leaves every
browser-tabs query throwing and the tab strip dead, a lone + that
does nothing.

Run an always-on heal after every migration pass instead, derived
from the migration folder's latest drizzle meta snapshot so it can
never drift from the real schema or resurrect columns a future
migration deliberately drops. Missing nullable columns are added
in place; a variant missing a structural NOT NULL column is
rebuilt rather than stamped with fabricated defaults. Best-effort
throughout: the heal can never turn a working boot into a failed
one.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@trunk-io

trunk-io Bot commented Jul 14, 2026

Copy link
Copy Markdown

Merging to main in this repository is managed by Trunk.

  • To merge this pull request, check the box to the left or comment /trunk merge below.

After your PR is submitted to the merge queue, this comment will be automatically updated with its status. If the PR fails, failure details will also be posted here

@github-actions

Copy link
Copy Markdown

React Doctor found no issues in the changed files. 🎉

Reviewed by React Doctor for commit af3833f.

@greptile-apps

greptile-apps Bot commented Jul 14, 2026

Copy link
Copy Markdown
Contributor

Reviews (1): Last reviewed commit: "fix(browser-tabs): self-heal schema drif..." | Re-trigger Greptile

});

applyPending();
ensureBrowserTabsSchema(sqlite, migrationsFolder);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Heal Can Skip Production Snapshots

runMigrations now depends on the passed migration folder containing meta/_journal.json, but the production database service path is db-migrations while the checked-in folder used by tests is migrations. If that production path does not include the Drizzle meta snapshots, latestSnapshotTables returns null, this new boot-time heal silently does nothing, and the reported browser-tabs schema drift still reaches the ORM load at startup.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

false positive, no fix: copyDrizzleMigrations (apps/code/vite-main-plugins.mts:483) does cpSync of the entire migrations dir recursively, meta/ included — confirmed present in .vite/build/db-migrations/meta. And readMigrationFiles already requires the same meta/_journal.json, so any folder migrations can run from has the snapshot too

@charlesvien

Copy link
Copy Markdown
Member

@adamleithp adamleithp closed this Jul 18, 2026
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants