Repository navigation
fix(db): drop stale automations v2_project_id FK blocking automation creation - #5878
Conversation
…creation Projects are local-first since #5731 (host.db is authoritative; cloud v2_projects sync retired), so most projects have no cloud row. The automation router already treats the project pin as metadata, but the insert still hit the automations_v2_project_id_v2_projects_id_fk constraint and failed for every local-first project. Drop the FK, mirroring the workspace-pin FK drop in #5741. Claude-Session: https://claude.ai/code/session_0152X97bwXahNYQtSZLDS5zK
📝 WalkthroughWalkthroughMigration 0062 removes the foreign key from ChangesAutomation project foreign key removal
Estimated code review effort: 2 (Simple) | ~10 minutes Suggested reviewers: 🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
Warning There were issues while running some tools. Please review the errors and either fix the tool's configuration or disable the tool if it's a critical failure. 🔧 Checkov (3.3.8)packages/db/drizzle/meta/0062_snapshot.jsonTraceback (most recent call last): packages/db/drizzle/meta/_journal.jsonTraceback (most recent call last): Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Actionable comments posted: 1
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@packages/db/src/schema/schema.ts`:
- Line 776: Before the v2Project delete flow removes a row from v2Projects,
delete all dependent automations whose v2ProjectId matches the project being
deleted, using the existing dbWs operation and automation schema symbols. Keep
the cleanup in the application layer and execute it before
dbWs.delete(v2Projects), preserving the non-null relationship.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro
Run ID: 5b1559b3-be32-499f-a36a-3e5cb052361a
📒 Files selected for processing (4)
packages/db/drizzle/0062_drop_automations_v2_project_fk.sqlpackages/db/drizzle/meta/0062_snapshot.jsonpackages/db/drizzle/meta/_journal.jsonpackages/db/src/schema/schema.ts
| v2ProjectId: uuid("v2_project_id") | ||
| .notNull() | ||
| .references(() => v2Projects.id, { onDelete: "cascade" }), | ||
| v2ProjectId: uuid("v2_project_id").notNull(), |
There was a problem hiding this comment.
🗄️ Data Integrity & Integration | 🟡 Minor | ⚡ Quick win
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
# Find reads/writes of automations.v2ProjectId and any assumptions of a joinable v2_projects row
rg -nP --type=ts -C3 '\bv2ProjectId\b' -g '!**/*.test.*'
# Look for cleanup/cascade logic tied to v2 project deletion
rg -nP --type=ts -C3 'delete\w*\(.*v2[Pp]roject'Repository: superset-sh/superset
Length of output: 158
🏁 Script executed:
#!/bin/bash
set -u
echo "== files matching schema.ts =="
fd -a 'schema\.ts$' . | sed 's#^\./##' | head -100
echo "== referenced file exists and size =="
wc -l packages/db/src/schema/schema.ts 2>/dev/null || true
echo "== schema.ts v2ProjectId/v2_projects context =="
rg -n 'v2ProjectId|v2_project_id|automations|v2Projects' packages/db/src/schema/schema.ts 2>/dev/null -C 4 || true
echo "== repo-wide v2ProjectId/v2_project_id/v2Projects/v2 projects =="
rg -n '\bv2ProjectId\b|\bv2_project_id\b|\bv2Projects\b|\bv2 projects\b|\bv2_projects\b' packages -g '!**/*.test.*' 2>/dev/null -C 3 || true
echo "== delete-related v2_project/v2 project/v2Project strings =="
rg -n 'delete[^(]*\([^)]*v2Project|delete[^(]*\([^)]*v2(project|Project)|\bv2Projects[ .(][^=]*delete|\.delete\(' packages -g '!**/*.test.*' 2>/dev/null -C 3 || trueRepository: superset-sh/superset
Length of output: 50377
🏁 Script executed:
#!/bin/bash
set -u
echo "== exact schema.ts lines around automations/v2_project_id =="
sed -n '730,810p' packages/db/src/schema/schema.ts
echo "== schema.ts FK construction near automations/v2Projects =="
rg -n 'automationsTable|automations|v2ProjectId|v2_projects|references\(' packages/db/src/schema/schema.ts -C 5
echo "== focused repo-wide usages excluding tests/snapshots =="
rg -n --type=ts '\bv2ProjectId\b|\bv2_project_id\b|\bv2Projects\b|\bv2_projects\b' . \
-g '!**/drizzle/meta/**' \
-g '!**/*.test.*' \
-g '!**/dist/**' \
-g '!**/build/**' \
-C 3 || true
echo "== focused delete/cleanup/deleteBy usages excluding tests/snapshots/built artifacts =="
rg -n --type=ts --type=tsx 'delete\(|deleteBy\(|\.delete\(|\.deleteBy\(' packages \
-g '!**/*.test.*' \
-g '!**/drizzle/meta/**' \
-C 2 || true
echo "== focused v2 project deletion mentions excluding tests/snapshots =="
rg -n --type=ts --type=tsx 'v2Project|v2_projects|v2 projects|workspace.*project|project.*workspace' packages \
-g '!**/*.test.*' \
-g '!**/drizzle/meta/**' \
-C 2 || trueRepository: superset-sh/superset
Length of output: 50377
🏁 Script executed:
#!/bin/bash
set -u
python3 - <<'PY'
import json
from pathlib import Path
for p in sorted(Path('packages/db/drizzle/meta').glob('*.json')):
data = json.loads(p.read_text())
automations = data.get('tables', {}).get('public.automations')
v2fk = (automations and automations.get('foreignKeys') or {}).get('automations_v2_project_id_v2_projects_id_fk')
if v2fk:
print(f'{p.name}: automations_v2_project_id_v2_projects_id FK columns={v2fk.get("columnsFrom")} tableTo={v2fk.get("tableTo")} onDelete={v2fk.get("onDelete")}')
PY
echo "== v2-project delete code =="
sed -n '500,535p' packages/trpc/src/router/v2-project/v2-project.ts
echo "== focused delete/where project FK cleanup excluding large dirs/tests =="
rg -n --type=ts --type=tsx '\bwhere\(\s*dt\w*\.projectId\s*,\s*eq\([^)]*v2Projects\.id[\s\S]{0,120}\)|delete\([^)]*projectId|delete\([^)]*project_id' packages \
-g '!**/*.test.*' \
-g '!**/drizzle/meta/**' \
-C 3 || trueRepository: superset-sh/superset
Length of output: 4821
🏁 Script executed:
#!/bin/bash
set -u
echo "== focused delete/where project FK cleanup excluding tests/snapshots =="
rg -n --ext ts --ext tsx '\bwhere\(&<\w*\.projectId,\s*eq\([^)]*v2Projects\.id[\s\S]{0,140}\)|delete\([^)]*projectId|delete\([^)]*project_id' packages \
-g '!**/*.test.*' \
-g '!**/drizzle/meta/**' \
-C 3 || true
echo "== focused delete/where v2WorkspaceId cleanup excluding tests/snapshots =="
rg -n --ext ts --ext tsx '\bwhere\(&<\w*\.v2WorkspaceId,\s*eq\([^)]*v2Workspaces\.id[\s\S]{0,140}\)|delete\([^)]*v2Workspace|delete\([^)]*workspaces\.id|v2_workspace_id' packages \
-g '!**/*.test.*' \
-g '!**/drizzle/meta/**' \
-C 3 || true
echo "== current automations FK presence in latest snapshot =="
python3 - <<'PY'
import json
from pathlib import Path
p = max(Path('packages/db/drizzle/meta').glob('*.json'))
data = json.loads(p.read_text())
tables = data.get('tables', {})
fk = (tables.get('public.automations') or {}).get('foreignKeys', {})
print('current_snapshot', p.name)
print('FK exists:', bool(fk.get('automations_v2_project_id_v2_projects_id_fk')))
print('FK details:', fk.get('automations_v2_project_id_v2_projects_id_fk'))
PYRepository: superset-sh/superset
Length of output: 567
🏁 Script executed:
#!/bin/bash
set -u
echo "== current FK presence in numbered latest snapshot =="
python3 - <<'PY'
import json
from pathlib import Path
snapshot = sorted(Path('packages/db/drizzle/meta').glob('[0-9][0-9][0-9][0-9]_snapshot.json'))[-1]
data = json.loads(snapshot.read_text())
auto_fks = (data.get('tables', {}).get('public.automations') or {}).get('foreignKeys', {})
print(snapshot.name, auto_fks)
print('FK exists:', bool(auto_fks.get('automations_v2_project_id_v2_projects_id_fk')))
print('FK details:', auto_fks.get('automations_v2_project_id_v2_projects_id_fk'))
PY
echo "== v2-project delete/delete-related cleanup code =="
sed -n '500,535p' packages/trpc/src/router/v2-project/v2-project.ts
echo "== focused v2-project/v2-workspace delete patterns excluding tests/snapshots (lowercase flag compatibility) =="
rg -n -t ts -t tsx 'delete\(.*(v2Projects|v2Projects|v2Workspaces|v2Workspaces)|\.delete\(|where\(&<.*(v2WorkspaceId|projectId|projectId|v2_projects|v2_workspaces)' packages \
-g '!**/*.test.*' \
-g '!**/drizzle/meta/**' \
-C 4 || trueRepository: superset-sh/superset
Length of output: 2117
🏁 Script executed:
#!/bin/bash
set -u
echo "== focused v2-project/v2-workspace delete patterns excluding tests/snapshots =="
rg -n --type-add 'tsx:[Pp]ackage\.lock\.json' --type-add 'tsx:*.tsx' --type-add 'tsx:*.ts' -t tsx -t ts 'delete\([^)]*v2Projects|delete\([^)]*v2Workspaces|\.delete\(|where\(&<.*(v2WorkspaceId|projectId|v2_projects|v2_workspaces|v2WorkspaceId)' packages \
-g '!**/*.test.*' \
-g '!**/drizzle/meta/**' \
-C 4 || true
echo "== all references to automation dispatch/project cleanup around v2ProjectId =="
sed -n '90,120p' packages/trpc/src/router/automation/dispatch.ts
sed -n '1,140p' packages/trpc/src/router/v2-project/v2-project.tsRepository: superset-sh/superset
Length of output: 50377
Add automation cleanup when deleting a v2_projects row.
automations.v2ProjectId is still non-null, but the FK is gone, and v2-project.delete calls dbWs.delete(v2Projects) without deleting dependent automations. Deleting a project will leave automations pointing to a missing project; add an app-layer cleanup step before the project delete.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@packages/db/src/schema/schema.ts` at line 776, Before the v2Project delete
flow removes a row from v2Projects, delete all dependent automations whose
v2ProjectId matches the project being deleted, using the existing dbWs operation
and automation schema symbols. Keep the cleanup in the application layer and
execute it before dbWs.delete(v2Projects), preserving the non-null relationship.
🧹 Preview Cleanup CompleteThe following preview resources have been cleaned up:
Thank you for your contribution! 🎉 |
…host CLI ParadevAI#5885, Cursor session labels ParadevAI#5882, open-in-IDE v2 ParadevAI#5877, collapsed sidebar DnD ParadevAI#5871, automations FK drop ParadevAI#5878) # Conflicts: # apps/desktop/src/main/lib/agent-setup/notify-hook.test.ts
…host CLI ParadevAI#5885, Cursor session labels ParadevAI#5882, open-in-IDE v2 ParadevAI#5877, collapsed sidebar DnD ParadevAI#5871, automations FK drop ParadevAI#5878) # Conflicts: # apps/desktop/src/main/lib/agent-setup/notify-hook.test.ts
Problem
Creating an automation fails with a raw
Failed query: insert into "automations" ...error in the create dialog (reported via Discord).Since #5731, projects are local-first — host.db is authoritative and cloud
v2_projectssync is retired, so most projects have no cloud row. That PR relaxedverifyProjectInOrgto treat a missing cloud row as fine, butautomations.v2_project_idstill carried a hard FK tov2_projects. Validation passes, then the insert dies onautomations_v2_project_id_v2_projects_id_fk— so automation creation is broken for every local-first project.Fix
Drop the FK (column stays
NOT NULL). This mirrors #5741, which dropped the analogous workspace-pin FK for the same reason: the cloud table is a best-effort mirror, the host is authoritative, and the pin is metadata — a dangling pin surfaces as a readable host-side error at dispatch.Verification
On a fresh Neon branch from production (
br-snowy-band-afgc8x2r):0062_drop_automations_v2_project_fk.sqlviadrizzle-kit migrate, confirmed the FK gone.automationsinsert pinned to a project id with nov2_projectsrow now succeeds (rolled back after).Lint and typecheck clean.
https://claude.ai/code/session_0152X97bwXahNYQtSZLDS5zK
Summary by cubic
Drop the stale
automations.v2_project_id→v2_projectsFK to unblock automation creation in local-first projects. The column remains NOT NULL; the project pin is validated on the host.packages/db/drizzle/0062_drop_automations_v2_project_fk.sqlto dropautomations_v2_project_id_v2_projects_id_fk.packages/db/src/schema/schema.tsto remove.references(() => v2Projects.id)fromv2ProjectId.v2_projectsrow exists.Written for commit 54ac9ab. Summary will update on new commits.
Summary by CodeRabbit
Bug Fixes
Chores