Skip to content

fix(db): drop stale automations v2_project_id FK blocking automation creation - #5878

Merged
saddlepaddle merged 1 commit into
mainfrom
fix-discord-automation-er
Jul 22, 2026
Merged

saddlepaddle merged 1 commit into
mainfrom
fix-discord-automation-er

Conversation

@saddlepaddle

@saddlepaddle saddlepaddle commented Jul 22, 2026 •

Copy link
Copy Markdown
Collaborator

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_projects sync is retired, so most projects have no cloud row. That PR relaxed verifyProjectInOrg to treat a missing cloud row as fine, but automations.v2_project_id still carried a hard FK to v2_projects. Validation passes, then the insert dies on automations_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):

  • Confirmed the FK present, applied 0062_drop_automations_v2_project_fk.sql via drizzle-kit migrate, confirmed the FK gone.
  • Reproduced the failing case: an automations insert pinned to a project id with no v2_projects row 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_projects FK to unblock automation creation in local-first projects. The column remains NOT NULL; the project pin is validated on the host.

  • Bug Fixes
    • Added migration packages/db/drizzle/0062_drop_automations_v2_project_fk.sql to drop automations_v2_project_id_v2_projects_id_fk.
    • Updated packages/db/src/schema/schema.ts to remove .references(() => v2Projects.id) from v2ProjectId.
    • Automations can now be created even when no cloud v2_projects row exists.

Written for commit 54ac9ab. Summary will update on new commits.

Review in cubic

Summary by CodeRabbit

  • Bug Fixes

    • Updated automation project relationships to prevent automatic deletion when a referenced project is removed.
    • Preserved the requirement that every automation has an associated project identifier.
  • Chores

    • Updated database migration metadata and schema history to reflect the relationship change.

…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
@coderabbitai

coderabbitai Bot commented Jul 22, 2026 •

Copy link
Copy Markdown
Contributor

Review Change Stack

📝 Walkthrough

Walkthrough

Migration 0062 removes the foreign key from automations.v2_project_id to v2_projects.id, updates the exported Drizzle schema, and records the complete schema snapshot and migration journal entry.

Changes

Automation project foreign key removal

Layer / File(s) Summary
Remove automation project reference constraint
packages/db/src/schema/schema.ts, packages/db/drizzle/0062_drop_automations_v2_project_fk.sql
The required v2ProjectId UUID no longer references v2Projects.id, and migration 0062 drops the existing foreign key constraint.
Record migration snapshot and journal
packages/db/drizzle/meta/0062_snapshot.json, packages/db/drizzle/meta/_journal.json
The complete PostgreSQL schema snapshot and journal entry are added for migration 0062.

Estimated code review effort: 2 (Simple) | ~10 minutes

Suggested reviewers: kitenite

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Title check ✅ Passed The title is concise, conventional, and accurately summarizes the main change: dropping the stale automations FK.
Description check ✅ Passed The description covers the problem, fix, and verification, and includes the key test outcome and lint/typecheck status.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix-discord-automation-er

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.json

Traceback (most recent call last):
File "/usr/local/bin/checkov", line 2, in
from checkov.main import Checkov
ModuleNotFoundError: No module named 'checkov'

packages/db/drizzle/meta/_journal.json

Traceback (most recent call last):
File "/usr/local/bin/checkov", line 2, in
from checkov.main import Checkov
ModuleNotFoundError: No module named 'checkov'


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.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@coderabbitai coderabbitai Bot left a comment

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.

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

📥 Commits

Reviewing files that changed from the base of the PR and between 976241c and 54ac9ab.

📒 Files selected for processing (4)
  • packages/db/drizzle/0062_drop_automations_v2_project_fk.sql
  • packages/db/drizzle/meta/0062_snapshot.json
  • packages/db/drizzle/meta/_journal.json
  • packages/db/src/schema/schema.ts

v2ProjectId: uuid("v2_project_id")
.notNull()
.references(() => v2Projects.id, { onDelete: "cascade" }),
v2ProjectId: uuid("v2_project_id").notNull(),

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.

🗄️ 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 || true

Repository: 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 || true

Repository: 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 || true

Repository: 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\(&amp;&lt;\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\(&amp;&lt;\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'))
PY

Repository: 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\(&amp;&lt;.*(v2WorkspaceId|projectId|projectId|v2_projects|v2_workspaces)' packages \
  -g '!**/*.test.*' \
  -g '!**/drizzle/meta/**' \
  -C 4 || true

Repository: 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\(&amp;&lt;.*(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.ts

Repository: 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.

@github-actions

github-actions Bot commented Jul 22, 2026 •

Copy link
Copy Markdown
Contributor

🧹 Preview Cleanup Complete

The following preview resources have been cleaned up:

  • ✅ Neon database branch

Thank you for your contribution! 🎉

@saddlepaddle
saddlepaddle merged commit 46313e6 into main Jul 22, 2026
18 checks passed
Laurence-NZ added a commit to Laurence-NZ/superset-pwsh that referenced this pull request Jul 23, 2026
…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
Laurence-NZ added a commit to Laurence-NZ/superset-pwsh that referenced this pull request Jul 23, 2026
…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

This branch was previously deployed

1 inactive deployment
preview — 54ac9ab0 Deployed Jul 22, 2026 by saddlepaddle via Deploy Admin #6783
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant