Repository navigation
fix(db): bootstrap Projects for development push databases that predate them - #9611
Conversation
…te them A push-managed database with workspaces but no Project schema could never pass the schema-push guard: push cannot backfill workspace.project_id, and the guard refuses every unenforced Project state. Under SIM_DEV_DB_PUSH=1 the pre-push reconciler now replays migrations 0394 and 0406 (the foundation commits atomically with the rollout marker) and runs the registered 0032_project_membership script migration on its single session, recording it as the migration runner does. An interrupted bootstrap resumes; every other unenforced state still refuses with the same message. The pinned drizzle-kit patch also adds unique constraints before foreign keys, so a composite foreign key on a new unique constraint of an existing table no longer fails, and in the noninteractive push policy it answers the unique-constraint truncate prompt with its non-destructive choice.
|
The latest updates on your projects. Learn more about Vercel for GitHub. |
[Medium impact] The PR appears safe to merge; no new actionable issues were found. SummaryEnables development schema pushes for databases that predate Projects.
|
There was a problem hiding this comment.
1 issue found across 5 files
Confidence score: 3/5
- In
packages/db/scripts/reconcile-project-membership.ts, classifying the database as fresh while the Project-specific columns remain can let bootstrap reach a Drizzle foreign-key push that fails on orphaned values. Account for those columns before treating the database as fresh.
Prompt for AI agents (unresolved issues)
Check if these issues are valid — if so, understand the root cause of each and fix them. When an issue isn't valid or won't be fixed in this PR, reply in its thread with the reason and then resolve the thread. If appropriate, use sub-agents to investigate and fix each issue separately.
<file name="packages/db/scripts/reconcile-project-membership.ts">
<violation number="1" location="packages/db/scripts/reconcile-project-membership.ts:49">
P2: This classifies a database as `fresh` even when Project-specific `folder.project_id` or `workspace_files.project_id` columns remain. Orphaned values can make Drizzle’s later foreign-key push fail after bootstrap has committed the Project migration. Include these columns in the schema-state check and refuse this shape.</violation>
</file>
Reply with feedback, questions, or to request a fix.
Turn on auto-fix | Re-trigger cubic
The bootstrap ran 0032_project_membership before Drizzle pushed anything, so a development database from before a column the migration reads (such as the fork parent) failed after committing the expansion, on every retry. --prepare now only replays the expansion. push.ts then runs one Drizzle push with workspace.project_id still nullable (SIM_DB_PUSH_PROJECT_BOOTSTRAP=1), runs the migration through reconcile-project-membership.ts --bootstrap, and finishes with the ordinary push. The connector and rollout marker are kept out of Drizzle's diff until the migration retires them. A fresh bootstrap also requires that no public table carries a project_id column.
|
@cubic-dev-ai review this PR |
@waleedlatif1 I have started the AI code review. It will take a few minutes to complete. |
There was a problem hiding this comment.
All reported issues were addressed across 8 files
Reply with feedback, questions, or to request a fix.
Turn on auto-fix | Re-trigger cubic
The replayed migration SQL and the script runner name tables unqualified, so a connection search path that lists another schema first created the Project foundation outside public. The refusal snapshot now also covers folders and Projects.
|
@cubic-dev-ai review this PR |
@waleedlatif1 I have started the AI code review. It will take a few minutes to complete. |
Summary
SIM_DEV_DB_PUSH=1 db:push) refused any database that has workspaces but no Project schema, so a push-managed database from before Projects could never sync: push can't backfillworkspace.project_idand the guard refuses every unenforced Project statereconcile-project-membership.ts --preparenow expands those databases: it replays0394_project_foundation+0406_workspace_project_columnverbatim (minus 0406's leading migrator batchCOMMIT, so the foundation commits atomically with the rollout marker)push.tsthen sees the rollout marker on its fence session and runs one Drizzle push withworkspace.project_idstill nullable (SIM_DB_PUSH_PROJECT_BOOTSTRAP=1, read only byschema.tsfor that column), so an older database gains every column0032reads (e.g. the fork parent).reconcile-project-membership.ts --bootstrapthen runs the registered0032_project_membershipthroughrunScriptMigrationson its single session (recorded exactly asmigrate.tsrecords it), and the ordinary push and reconcilers follow.drizzle.config.tskeeps the connector and rollout marker out of Drizzle's diff until 0032 retires themmigrate.tsand other pushes out; the fence holds no table locks or snapshot, so 0406's concurrent index build and 0032's workspace barrier don't wait on itproject_idcolumn on any public table. Every other state behaves as today: connector with memberships, connector or Projects without the column expansion, a nullable column without Projects, a versioned expansion awaiting 0032, and any push withoutSIM_DEV_DB_PUSH=1still refuse with the same message.migrate.tsis untouched(id, project_id, resource_type)unique always failed on an existing table. Unique constraints now come right after new columns. In the noninteractive push policy, the "truncate before adding a unique constraint?" prompt (which aborts without a TTY) is answered with its non-destructive choice; duplicates still fail the pushType of Change
Testing
packages/db/scripts/project-push-bootstrap.integration.ts: pushes the real schema, strips every Project object to build a pre-Project template, then per test runs the realscripts/push.ts --force(fence included). It covers bootstrap + push + replay, a database missing a column 0032 reads (fork parent dropped), (memberships, fork family, archived Project, validated/deferrable constraints, connector and marker retired,0032recorded), resume after a discovery conflict, atomic rollback when the workspace barrier is busy, a migration holding the lock, no-op withoutSIM_DEV_DB_PUSH, and seven refusal states (incl. orphaned folder Project ownership) that must keep schema, workspaces and connector byte-identicalpush.integration.tscase for a composite FK on a new unique constraint of a populated table; it goes red with either drizzle hunk removedschema.tsand from the last pre-forkingschema.ts, seeded with workspaces, then pushed with the current code: both bootstrap and replay. The pre-forking one first hits an unrelated Drizzle diff error dropping a webhook FK that never existed (also on an empty copy, before this change); the rerun resumes and completesscripts/push.integration.ts,project-contract,project-authority,workspace-project-columnintegration suites (120 tests) pass on PostgreSQL 17;push.test.ts; packages/dbtype-check;lint;check:utils,check:comment-hygiene,check:test-patterns,check:file-namesChecklist
test-auditauthoring gate)