Skip to content

feat(projects): enforce Project membership and retire the connector - #8590

Draft
mzxchandra wants to merge 74 commits into
feat/project-workspace-column-expandfrom
codex/project-entity-enforcement
Draft

mzxchandra wants to merge 74 commits into
feat/project-workspace-column-expandfrom
codex/project-entity-enforcement

Conversation

@mzxchandra

@mzxchandra mzxchandra commented Oct 2, 2026 •

Copy link
Copy Markdown
Contributor

Summary

  • Complete the workspace.project_id rollout after feat(projects): move Project membership to the workspace column #8830 has been deployed and older application and background-worker versions have drained. This PR is stacked on feat(projects): move Project membership to the workspace column #8830; the deployment preflight remains mandatory.
  • Register 0031_project_membership in the existing TypeScript migration runner. It preserves legacy Project identities, gives populated columns precedence over stale connector rows, and backfills missing assignments in transactions of at most 50 singletons or one complete fork family. Bounded contention retries release locks, allow unrelated families to progress and resume from committed assignments.
  • Run final enforcement only after assignment and validation. SQL migration 0405 is a placeholder because SQL migrations precede registered scripts. Shared maintenance SQL validates the foreign key, requires membership, installs lifecycle guards and retires project_workspace atomically under non-waiting table locks. It adds no Project trigger to ordinary workflow writes.
  • Keep ambiguous ownership and archive/provider cleanup as explicit remediation prerequisites. A persistent database journal records unfinished external cleanup and blocks completion until cleanup succeeds; schema push preserves that recovery state. Fresh schema push shares the final enforcement implementation.
  • Use the standard PostgreSQL 17 integration matrix for Project migration coverage; remove the extra Project-specific PostgreSQL 16 workflow step.
  • Keep rollback limited to feat(projects): move Project membership to the workspace column #8830-compatible application code while retaining the contracted schema. No merge or deployment is part of this PR validation.

Type of Change

  • Feature / database migration

Testing

  • All 177 PostgreSQL 17 database integration checks passed, including 53 Project contract, seven expansion and 16 schema-push checks. All 60 targeted contract/expansion checks passed on PostgreSQL 16.
  • All 31 real database/application checks passed, including four archive/provider-repair cases.
  • The actual full migration runner and replay passed against a running feat(projects): move Project membership to the workspace column #8830 app, Docker PostgreSQL and Redis. Twenty checks across 36 HTTP requests verified legacy assignments, forks, singleton batches and continued application behavior after connector retirement. Fresh full migration and schema push also passed.
  • Regression controls reproduced stale assignment without the connector-row lock, rejected the prior runner's legacy-assignment behavior and detected connector writes when the old synchronization SQL was restored. Recovery coverage includes partial commits, contention, retries, missing completion receipts and persistent cleanup state.
  • Full local repository tests passed: 413 root script tests and all 20 package tasks, including 36,885 application tests. All 26 workspace type-checks, lint, 58 audits, generated-artifact checks, SQL/maintenance safety, schema-drift checks and workflow lint passed.
  • Hosted validation is running on the pushed revision; fresh reviews are pending. Local tests do not replace deployment drain verification or production-scale observation.

Checklist

  • Code follows project style guidelines
  • Self-reviewed my changes
  • Tests added/updated and passing (new tests pass the test-audit authoring gate)
  • No new warnings introduced
  • I confirm that I have read and agree to the terms outlined in the Contributor License Agreement (CLA)

@vercel

vercel Bot commented Oct 2, 2026 •

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated
docs Ready Ready Preview Oct 9, 2026 9:39pm UTC

Request Review

@mzxchandra mzxchandra changed the title feat(projects): enforce membership after the staged backfill feat(projects): backfill and enforce membership in SQL Oct 3, 2026
@cubic-dev-ai

cubic-dev-ai Bot commented Oct 9, 2026

Copy link
Copy Markdown
Contributor

@cubic-dev-ai review this PR

@mzxchandra I have started the AI code review. It will take a few minutes to complete.

@cubic-dev-ai cubic-dev-ai 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.

All reported issues were addressed across 150 files

You've manually re-run cubic several times on this PR. Each manual re-review checks the full PR again and counts toward your usage quota. To preserve your usage limits, we recommend letting cubic automatically review new commits.

Turn on auto-fix | Re-trigger cubic

Comment thread apps/sim/scripts/backfill-projects.ts Outdated
@mzxchandra

Copy link
Copy Markdown
Contributor Author

@greptile

@mzxchandra

Copy link
Copy Markdown
Contributor Author

@cubic-dev-ai review this PR

@cubic-dev-ai

cubic-dev-ai Bot commented Oct 9, 2026

Copy link
Copy Markdown
Contributor

@cubic-dev-ai review this PR

@mzxchandra I have started the AI code review. It will take a few minutes to complete.

@cubic-dev-ai cubic-dev-ai 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.

All reported issues were addressed across 150 files

You've manually re-run cubic several times on this PR. Each manual re-review checks the full PR again and counts toward your usage quota. To preserve your usage limits, we recommend letting cubic automatically review new commits.

Turn on auto-fix | Re-trigger cubic

Comment thread apps/sim/scripts/backfill-projects.ts
@mzxchandra

Copy link
Copy Markdown
Contributor Author

@greptile

@mzxchandra

Copy link
Copy Markdown
Contributor Author

@cubic-dev-ai review this PR

@cubic-dev-ai

cubic-dev-ai Bot commented Oct 9, 2026

Copy link
Copy Markdown
Contributor

@cubic-dev-ai review this PR

@mzxchandra I have started the AI code review. It will take a few minutes to complete.

@cubic-dev-ai cubic-dev-ai 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.

No issues found across 150 files

Confidence score: 5/5

  • Automated review surfaced no issues in the provided summaries.
  • No files require special attention.

You've manually re-run cubic several times on this PR. Each manual re-review checks the full PR again and counts toward your usage quota. To preserve your usage limits, we recommend letting cubic automatically review new commits.

Turn on auto-fix | Re-trigger cubic

@mzxchandra

Copy link
Copy Markdown
Contributor Author

@greptile

@mzxchandra

Copy link
Copy Markdown
Contributor Author

@cubic-dev-ai review this PR

@cubic-dev-ai

cubic-dev-ai Bot commented Oct 9, 2026

Copy link
Copy Markdown
Contributor

@cubic-dev-ai review this PR

@mzxchandra I have started the AI code review. It will take a few minutes to complete.

@mzxchandra

Copy link
Copy Markdown
Contributor Author

@greptile

@mzxchandra

Copy link
Copy Markdown
Contributor Author

@cubic-dev-ai review this PR

@cubic-dev-ai

cubic-dev-ai Bot commented Oct 9, 2026

Copy link
Copy Markdown
Contributor

@cubic-dev-ai review this PR

@mzxchandra I have started the AI code review. It will take a few minutes to complete.

@cubic-dev-ai cubic-dev-ai 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.

6 issues found across 161 files

Confidence score: 3/5

  • .github/workflows/migrate.yml can start the migration before workers have drained; a mutable acknowledgement digest can let the migration remove project_id while workers still use it. Verify the worker drain directly or use a trustworthy acknowledgement.
  • project-repairs.ts can miss pending repair journals when search_path is non-public, allowing cleanup to proceed as if no repairs were pending. Schema-qualify the journal lookup.
  • project-backfill.ts treats PostgreSQL URLs with different socket host values as the same database, which can conflate backfills for separate databases. Include routing parameters in the connection identity.
  • workspace-fixtures.ts can delete a Project that the fixture did not create. Track fixture-created Project IDs and limit cleanup to those.
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/testing/workspace-fixtures.ts">

<violation number="1" location="packages/db/testing/workspace-fixtures.ts:100">
P2: This cleanup can delete an existing Project, not just one created for the fixture. Track which Projects the fixture created and restrict deletion to those IDs.</violation>
</file>

<file name="packages/db/maintenance/project-repairs.ts">

<violation number="1" location="packages/db/maintenance/project-repairs.ts:30">
P2: The cleanup gate can miss pending repairs when the connection uses a non-public `search_path`: journal creation may target another schema, while this check only looks for the public table. Schema-qualify journal creation, updates, and reads consistently so migration completion cannot bypass pending cleanup.</violation>
</file>

<file name="apps/sim/lib/workspaces/lifecycle.ts">

<violation number="1" location="apps/sim/lib/workspaces/lifecycle.ts:154">
P2: Strict mode treats every `finishWorkflowArchive` rejection as failed provider cleanup, but that function also publishes MCP events after cleanup. A local subscriber exception can therefore leave the repair journal incomplete after provider cleanup succeeded; isolate notification errors or propagate only provider-cleanup failures.</violation>
</file>

<file name="packages/db/maintenance/project-backfill.ts">

<violation number="1" location="packages/db/maintenance/project-backfill.ts:54">
P2: `postgres:///prod?host=/var/run/postgresql` and `postgres:///prod?host=/tmp/other` hash identically because the socket `host` is in the omitted query string. Include PostgreSQL routing parameters in the identity so a manifest cannot be applied to a different socket-backed database with the same name.</violation>
</file>

<file name="apps/sim/lib/projects/backfill-repair.ts">

<violation number="1" location="apps/sim/lib/projects/backfill-repair.ts:89">
P2: Archive repair can leave an existing Project active after its last environment is archived, so the repair completes but migration validation can never pass. Apply the same last-environment Project archival lifecycle used by `archiveWorkspace` before recording the repair complete.</violation>
</file>

<file name=".github/workflows/migrate.yml">

<violation number="1" location=".github/workflows/migrate.yml:87">
P2: This gate does not enforce the required worker drain: it checks only the app ECS tasks and trusts a mutable digest variable for the worker acknowledgement. A prematurely set variable lets the migration remove `project_workspace` while an old Trigger.dev run still accesses it; require a release-scoped worker-drain receipt or an automated worker check before applying enforcement.</violation>
</file>

You've manually re-run cubic several times on this PR. Each manual re-review checks the full PR again and counts toward your usage quota. To preserve your usage limits, we recommend letting cubic automatically review new commits.

Turn on auto-fix | Re-trigger cubic

.where(condition)
await tx.delete(workspace).where(condition)
if (rows.length)
await tx.delete(project).where(

@cubic-dev-ai cubic-dev-ai Bot Oct 9, 2026 •

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.

P2: This cleanup can delete an existing Project, not just one created for the fixture. Track which Projects the fixture created and restrict deletion to those IDs.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. 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. At packages/db/testing/workspace-fixtures.ts, line 100:

<comment>This cleanup can delete an existing Project, not just one created for the fixture. Track which Projects the fixture created and restrict deletion to those IDs.</comment>

<file context>
@@ -0,0 +1,112 @@
+      .where(condition)
+    await tx.delete(workspace).where(condition)
+    if (rows.length)
+      await tx.delete(project).where(
+        and(
+          inArray(
</file context>
Fix with cubic

await sql`SELECT to_regclass('public.project_backfill_archive_repairs') IS NOT NULL AS present`
if (!state.present) return 0
const [row] =
await sql`SELECT count(*)::int AS count FROM project_backfill_archive_repairs WHERE completed_at IS NULL`

@cubic-dev-ai cubic-dev-ai Bot Oct 9, 2026 •

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.

P2: The cleanup gate can miss pending repairs when the connection uses a non-public search_path: journal creation may target another schema, while this check only looks for the public table. Schema-qualify journal creation, updates, and reads consistently so migration completion cannot bypass pending cleanup.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. 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. At packages/db/maintenance/project-repairs.ts, line 30:

<comment>The cleanup gate can miss pending repairs when the connection uses a non-public `search_path`: journal creation may target another schema, while this check only looks for the public table. Schema-qualify journal creation, updates, and reads consistently so migration completion cannot bypass pending cleanup.</comment>

<file context>
@@ -0,0 +1,32 @@
+    await sql`SELECT to_regclass('public.project_backfill_archive_repairs') IS NOT NULL AS present`
+  if (!state.present) return 0
+  const [row] =
+    await sql`SELECT count(*)::int AS count FROM project_backfill_archive_repairs WHERE completed_at IS NULL`
+  return row.count
+}
</file context>
Fix with cubic

requestId,
strictExternalCleanup: options.strictExternalCleanup,
}).catch((error: unknown) => {
if (options.strictExternalCleanup) {

@cubic-dev-ai cubic-dev-ai Bot Oct 9, 2026 •

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.

P2: Strict mode treats every finishWorkflowArchive rejection as failed provider cleanup, but that function also publishes MCP events after cleanup. A local subscriber exception can therefore leave the repair journal incomplete after provider cleanup succeeded; isolate notification errors or propagate only provider-cleanup failures.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. 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. At apps/sim/lib/workspaces/lifecycle.ts, line 154:

<comment>Strict mode treats every `finishWorkflowArchive` rejection as failed provider cleanup, but that function also publishes MCP events after cleanup. A local subscriber exception can therefore leave the repair journal incomplete after provider cleanup succeeded; isolate notification errors or propagate only provider-cleanup failures.</comment>

<file context>
@@ -135,30 +135,44 @@ export async function archiveEnvironmentInTransaction(
+        requestId,
+        strictExternalCleanup: options.strictExternalCleanup,
+      }).catch((error: unknown) => {
+        if (options.strictExternalCleanup) {
+          cleanupErrors.push(error)
+          return
</file context>
Fix with cubic

export function projectBackfillDatabaseId(url: string): string {
const target = new URL(url)
return createHash('sha256')
.update(`${target.hostname.toLowerCase()}:${target.port || '5432'}${target.pathname}`)

@cubic-dev-ai cubic-dev-ai Bot Oct 9, 2026 •

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.

P2: postgres:///prod?host=/var/run/postgresql and postgres:///prod?host=/tmp/other hash identically because the socket host is in the omitted query string. Include PostgreSQL routing parameters in the identity so a manifest cannot be applied to a different socket-backed database with the same name.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. 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. At packages/db/maintenance/project-backfill.ts, line 54:

<comment>`postgres:///prod?host=/var/run/postgresql` and `postgres:///prod?host=/tmp/other` hash identically because the socket `host` is in the omitted query string. Include PostgreSQL routing parameters in the identity so a manifest cannot be applied to a different socket-backed database with the same name.</comment>

<file context>
@@ -0,0 +1,444 @@
+export function projectBackfillDatabaseId(url: string): string {
+  const target = new URL(url)
+  return createHash('sha256')
+    .update(`${target.hostname.toLowerCase()}:${target.port || '5432'}${target.pathname}`)
+    .digest('hex')
+}
</file context>
Fix with cubic

throw new ProjectBackfillConflict(
'Finish the pending repair with its original manifest before replacing it'
)
await archiveEnvironmentInTransaction(

@cubic-dev-ai cubic-dev-ai Bot Oct 9, 2026 •

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.

P2: Archive repair can leave an existing Project active after its last environment is archived, so the repair completes but migration validation can never pass. Apply the same last-environment Project archival lifecycle used by archiveWorkspace before recording the repair complete.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. 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. At apps/sim/lib/projects/backfill-repair.ts, line 89:

<comment>Archive repair can leave an existing Project active after its last environment is archived, so the repair completes but migration validation can never pass. Apply the same last-environment Project archival lifecycle used by `archiveWorkspace` before recording the repair complete.</comment>

<file context>
@@ -0,0 +1,117 @@
+      throw new ProjectBackfillConflict(
+        'Finish the pending repair with its original manifest before replacing it'
+      )
+    await archiveEnvironmentInTransaction(
+      tx,
+      repair.workspaceId,
</file context>
Fix with cubic

env:
ENVIRONMENT: ${{ inputs.environment }}
EXPECTED_IMAGE_DIGEST: ${{ inputs.environment == 'production' && vars.PROJECT_COLUMN_ENFORCEMENT_READY_IMAGE_DIGEST_PRODUCTION || inputs.environment == 'staging' && vars.PROJECT_COLUMN_ENFORCEMENT_READY_IMAGE_DIGEST_STAGING || '' }}
run: python3 .github/scripts/check-project-rollout.py --environment "$ENVIRONMENT" --region "$AWS_REGION" --expected-image-digest "$EXPECTED_IMAGE_DIGEST"

@cubic-dev-ai cubic-dev-ai Bot Oct 9, 2026 •

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.

P2: This gate does not enforce the required worker drain: it checks only the app ECS tasks and trusts a mutable digest variable for the worker acknowledgement. A prematurely set variable lets the migration remove project_workspace while an old Trigger.dev run still accesses it; require a release-scoped worker-drain receipt or an automated worker check before applying enforcement.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. 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. At .github/workflows/migrate.yml, line 87:

<comment>This gate does not enforce the required worker drain: it checks only the app ECS tasks and trusts a mutable digest variable for the worker acknowledgement. A prematurely set variable lets the migration remove `project_workspace` while an old Trigger.dev run still accesses it; require a release-scoped worker-drain receipt or an automated worker check before applying enforcement.</comment>

<file context>
@@ -51,6 +60,32 @@ jobs:
+        env:
+          ENVIRONMENT: ${{ inputs.environment }}
+          EXPECTED_IMAGE_DIGEST: ${{ inputs.environment == 'production' && vars.PROJECT_COLUMN_ENFORCEMENT_READY_IMAGE_DIGEST_PRODUCTION || inputs.environment == 'staging' && vars.PROJECT_COLUMN_ENFORCEMENT_READY_IMAGE_DIGEST_STAGING || '' }}
+        run: python3 .github/scripts/check-project-rollout.py --environment "$ENVIRONMENT" --region "$AWS_REGION" --expected-image-digest "$EXPECTED_IMAGE_DIGEST"
+
       # The expression maps the explicit environment input to exactly one repo
</file context>
Fix with cubic

@cubic-dev-ai cubic-dev-ai 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.

4 issues found across 161 files

Confidence score: 1/5

  • In project-membership.sql, the deferred Project trigger rejects normal project creation because the Project is inserted before its first workspace. Adjust the check so it does not abort the transaction before the workspace exists.
  • In backfill-repair.integration.ts, the barrier blocks the first eight workflows, leaving tail queued and unnotified. Block only one slow request so another worker can reach tail.
  • In push.integration.ts, the fixture cannot satisfy later reconcilers, and the assertion still passes when the push exits nonzero. Provide the required tables and assert a successful exit.
  • In lifecycle.ts, a pub/sub subscriber throwing after provider cleanup makes strict archive repair rethrow a notification error as if provider cleanup failed. Keep notification failures separate from provider cleanup status.
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="apps/sim/lib/projects/__integration__/backfill-repair.integration.ts">

<violation number="1" location="apps/sim/lib/projects/__integration__/backfill-repair.integration.ts:38">
P2: This barrier prevents `tail` from being notified: the first eight sorted workflows (`flow` and `slow-1` through `slow-7`) all block, leaving `tail` queued. Block only one slow request so another worker can reach `tail` before the test releases the barrier.</violation>
</file>

<file name="packages/db/maintenance/project-membership.sql">

<violation number="1" location="packages/db/maintenance/project-membership.sql:242">
P0: This deferred Project trigger rejects the normal create flow: the application inserts the Project before its first workspace, so the Project event runs with zero environments and aborts the transaction. Defer the nonempty check until the workspace membership event/final state is available, while retaining a guard for genuinely empty Projects.</violation>
</file>

<file name="packages/db/scripts/push.integration.ts">

<violation number="1" location="packages/db/scripts/push.integration.ts:229">
P2: This fixture cannot complete the push wrapper because its later reconcilers require tables the schema does not create. The assertion only checks spawn errors, so it passes on a nonzero exit; provide the required fixtures or isolate Project reconciliation, then assert `status` is zero.</violation>
</file>

<file name="apps/sim/lib/workspaces/lifecycle.ts">

<violation number="1" location="apps/sim/lib/workspaces/lifecycle.ts:154">
P2: Strict archive repair currently treats MCP notification failures as unfinished provider cleanup. If a local pub/sub subscriber throws after provider cleanup succeeds, this branch rethrows the notification error, leaves the repair journal incomplete, and blocks migration completion; isolate best-effort MCP notification errors from the strict provider-cleanup result.</violation>
</file>

You've manually re-run cubic several times on this PR. Each manual re-review checks the full PR again and counts toward your usage quota. To preserve your usage limits, we recommend letting cubic automatically review new commits.

Turn on auto-fix | Re-trigger cubic

CREATE TRIGGER project_contract_lock BEFORE INSERT OR UPDATE OR DELETE ON project
FOR EACH ROW EXECUTE FUNCTION project_contract_before_write();
DROP TRIGGER IF EXISTS project_contract_check ON project;
CREATE CONSTRAINT TRIGGER project_contract_check AFTER INSERT OR UPDATE OR DELETE ON project

@cubic-dev-ai cubic-dev-ai Bot Oct 9, 2026 •

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.

P0: This deferred Project trigger rejects the normal create flow: the application inserts the Project before its first workspace, so the Project event runs with zero environments and aborts the transaction. Defer the nonempty check until the workspace membership event/final state is available, while retaining a guard for genuinely empty Projects.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. 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. At packages/db/maintenance/project-membership.sql, line 242:

<comment>This deferred Project trigger rejects the normal create flow: the application inserts the Project before its first workspace, so the Project event runs with zero environments and aborts the transaction. Defer the nonempty check until the workspace membership event/final state is available, while retaining a guard for genuinely empty Projects.</comment>

<file context>
@@ -0,0 +1,268 @@
+CREATE TRIGGER project_contract_lock BEFORE INSERT OR UPDATE OR DELETE ON project
+FOR EACH ROW EXECUTE FUNCTION project_contract_before_write();
+DROP TRIGGER IF EXISTS project_contract_check ON project;
+CREATE CONSTRAINT TRIGGER project_contract_check AFTER INSERT OR UPDATE OR DELETE ON project
+DEFERRABLE INITIALLY DEFERRED FOR EACH ROW EXECUTE FUNCTION project_contract_after_write();
+--> statement-breakpoint
</file context>
Fix with cubic

for await (const chunk of request) chunks.push(Buffer.from(chunk))
const { workflowId } = JSON.parse(Buffer.concat(chunks).toString()) as { workflowId: string }
if (workflowId === 'tail') tailNotified = true
if (workflowId.startsWith('slow-')) await releaseNotifications.promise

@cubic-dev-ai cubic-dev-ai Bot Oct 9, 2026 •

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.

P2: This barrier prevents tail from being notified: the first eight sorted workflows (flow and slow-1 through slow-7) all block, leaving tail queued. Block only one slow request so another worker can reach tail before the test releases the barrier.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. 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. At apps/sim/lib/projects/__integration__/backfill-repair.integration.ts, line 38:

<comment>This barrier prevents `tail` from being notified: the first eight sorted workflows (`flow` and `slow-1` through `slow-7`) all block, leaving `tail` queued. Block only one slow request so another worker can reach `tail` before the test releases the barrier.</comment>

<file context>
@@ -0,0 +1,281 @@
+  for await (const chunk of request) chunks.push(Buffer.from(chunk))
+  const { workflowId } = JSON.parse(Buffer.concat(chunks).toString()) as { workflowId: string }
+  if (workflowId === 'tail') tailNotified = true
+  if (workflowId.startsWith('slow-')) await releaseNotifications.promise
+  response.writeHead(200, { 'content-type': 'application/json' }).end('{}')
+})
</file context>
Suggested change
if (workflowId.startsWith('slow-')) await releaseNotifications.promise
if (workflowId === 'slow-7') await releaseNotifications.promise
Fix with cubic

projectId: text('project_id').notNull().references(() => projects.id, { onDelete: 'restrict' }),
organizationId: text('organization_id'), archivedAt: timestamp('archived_at'), forkedFromWorkspaceId: text('forked_from_workspace_id'),
})
export const workflows = pgTable('workflow', {

@cubic-dev-ai cubic-dev-ai Bot Oct 9, 2026 •

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.

P2: This fixture cannot complete the push wrapper because its later reconcilers require tables the schema does not create. The assertion only checks spawn errors, so it passes on a nonzero exit; provide the required fixtures or isolate Project reconciliation, then assert status is zero.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. 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. At packages/db/scripts/push.integration.ts, line 229:

<comment>This fixture cannot complete the push wrapper because its later reconcilers require tables the schema does not create. The assertion only checks spawn errors, so it passes on a nonzero exit; provide the required fixtures or isolate Project reconciliation, then assert `status` is zero.</comment>

<file context>
@@ -185,108 +187,71 @@ export const knowledgeBases = pgTable('knowledge_base', {
+  projectId: text('project_id').notNull().references(() => projects.id, { onDelete: 'restrict' }),
+  organizationId: text('organization_id'), archivedAt: timestamp('archived_at'), forkedFromWorkspaceId: text('forked_from_workspace_id'),
+})
+export const workflows = pgTable('workflow', {
+  id: text('id').primaryKey(), workspaceId: text('workspace_id'), archivedAt: timestamp('archived_at'),
 })`)
</file context>
Fix with cubic

requestId,
strictExternalCleanup: options.strictExternalCleanup,
}).catch((error: unknown) => {
if (options.strictExternalCleanup) {

@cubic-dev-ai cubic-dev-ai Bot Oct 9, 2026 •

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.

P2: Strict archive repair currently treats MCP notification failures as unfinished provider cleanup. If a local pub/sub subscriber throws after provider cleanup succeeds, this branch rethrows the notification error, leaves the repair journal incomplete, and blocks migration completion; isolate best-effort MCP notification errors from the strict provider-cleanup result.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. 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. At apps/sim/lib/workspaces/lifecycle.ts, line 154:

<comment>Strict archive repair currently treats MCP notification failures as unfinished provider cleanup. If a local pub/sub subscriber throws after provider cleanup succeeds, this branch rethrows the notification error, leaves the repair journal incomplete, and blocks migration completion; isolate best-effort MCP notification errors from the strict provider-cleanup result.</comment>

<file context>
@@ -135,30 +135,44 @@ export async function archiveEnvironmentInTransaction(
+        requestId,
+        strictExternalCleanup: options.strictExternalCleanup,
+      }).catch((error: unknown) => {
+        if (options.strictExternalCleanup) {
+          cleanupErrors.push(error)
+          return
</file context>
Fix with cubic

This branch was successfully deployed

1 active deployment
Preview — e92ba0bd Deployed Oct 9, 2026 by vercel[bot]
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