Skip to content

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

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

mzxchandra wants to merge 82 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 one-Project-to-many-workspaces model through workspace.project_id. Deploy feat(projects): move Project membership to the workspace column #8830 and verify that incompatible application tasks and background workers have drained before this release; the deployment preflight remains mandatory.
  • Register 0031_project_membership in the existing TypeScript migration runner. Discover all environments, including populated columns; preserve legitimate Project identity, prefer columns over stale connector assignments, and reconcile unambiguous Project scope and archive state. Never unarchive environments or workflows.
  • Commit at most 50 singletons or one complete fork family per assignment transaction. Bound Project-wide repairs, retry transient contention after releasing locks, make progress on unrelated families, and resume committed work after failure.
  • Stop ambiguous grouping, ownership, empty Projects and provider cleanup for explicit remediation. Reviewed private manifests can retain a legitimate shared Project or repair a known detached family through the shared split policy. Stale evidence fails closed; deterministic repair destinations support lost-report replay. The database cleanup journal prevents unfinished external work from being forgotten.
  • Validate before final enforcement. SQL migration 0406 is a placeholder because SQL migrations precede registered scripts. Shared maintenance SQL validates membership, installs final lifecycle guards and retires project_workspace under brief non-waiting table locks. Ordinary workflow writes get no Project trigger. Fresh schema push uses the same enforcement and preserves recovery state.
  • Keep the rollout free of temporary synchronization triggers. feat(projects): move Project membership to the workspace column #8830 is the oldest supported application rollback after connector retirement. Project tests use the standard repository integration matrix, with no additional Project-specific PostgreSQL 16 CI.

Exceptional recovery runs from the exact release checkout on an authorized operator host with current release/drain evidence and the direct primary connection. After reviewing and completing any required preparation, the normal migration entrypoint can consume PROJECT_BACKFILL_REVIEW_PATH, validate/enforce, and write its normal completion receipt. The ordinary deployment retry then needs no private manifest. Direct invocation does not execute the GitHub Actions AWS preflight, so release coordination and fresh drain verification are still required. Never manually insert a completion receipt.

Type of Change

  • Feature / database migration

Testing

  • Latest head d0a9792707 integrates expansion b7ff6b1a02, preserving changelog 0404 and expansion 0405; enforcement is now 0406 plus registered 0031. Fresh real migration, no schema drift, migration safety and 24 focused checks passed. Changelog fixture failure was reproduced before its atomic Project-aware seed/cleanup fix; the optional Redis suite collects and skips all 9 cases when Redis is unset. Hosted validation for this head is pending.
  • On the earlier integrated revision ecfdf8b8e8: 81 PostgreSQL 17 checks passed across Project contract, expansion and schema-push suites; 46 real database/application checks passed across repair, foundation, organization detachment and connector lifecycle locking.
  • Before the latest review and fixture corrections, full repository tests passed: 413 root script tests and all 20 workspace tasks, including 36,896 application tests with 25 existing skips. All 26 workspace type-checks, lint, 58 audits, generated-artifact checks, migration safety, docs manifest, block registry and Drizzle schema consistency passed. Two unchanged documentation-generator cases timed out during the first concurrent run; the complete quieter rerun passed without changing assertions or timeouts.
  • Failure-first and guard-removal checks cover stale fully assigned metadata, personal-owner conflicts, outside-family evidence changes, shared-family replay, journal search paths, socket database identity, last-environment archive, provider/subscriber failures, reviewed detach and fixture cleanup ownership. The actual migration entrypoint rejects ambiguous/stale reviews, completes reviewed recovery, writes its receipt and succeeds on retry without a manifest.
  • Nine earlier real HTTP checks passed for authentication, workspace/Project creation, atomic first-environment creation, fork inheritance, subtree disconnect and cleanup. Eight additional mixed-version HTTP checks now reproduce old archival around new column-only forks, run the actual registered migration, and successfully retry fork/disconnect. Original Project identity and workspace/workflow archive state are preserved. That proof pinned the compatible app to 0dfc7abc1f and the unchanged runner to bdf50b29c7.
  • Review fixes preserve mixed legacy membership during reviewed detach, reject mismatched resume-code fingerprints before mutation, and isolate local subscriber failures. Their targeted checks passed: 9 real CLI/database repair cases and 57 database contract checks, with guard-removal regressions.
  • The four fixture failures from the preceding CI run are corrected. All 33 affected application integration checks passed through each of migration and schema-push provisioning. The mobile fixture now creates and deletes its Project atomically; interrupted-run cleanup was verified. The full local browser matrix was not completed and is not reported as passed.
  • Draft PR CI on 1e4499eebe passed all applicable jobs, including all eight database shards, the full mobile E2E matrix, desktop live tests, lint, unit tests and build. The separate desktop smoke workflow hit an Electron shutdown timeout, passed its internal retry, and is being rerun; overall validation is not yet clean. Local validation does not replace deployment drainage 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; separate desktop rerun and latest review correction pending)
  • 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 10, 2026 1:36am 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
@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 161 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 packages/db/testing/workspace-fixtures.ts Outdated
Comment thread packages/db/maintenance/project-repairs.ts Outdated
Comment thread apps/sim/lib/workspaces/lifecycle.ts
Comment thread packages/db/maintenance/project-backfill.ts Outdated
Comment thread apps/sim/lib/projects/backfill-repair.ts Outdated
Comment thread .github/workflows/migrate.yml

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

2 issues found across 161 files

Confidence score: 4/5

  • The barrier in backfill-repair.integration.ts blocks all eight workers ahead of tail, so the test cannot verify that tail receives a notification. Block only one slow request.
  • In lifecycle.ts, a local pub/sub subscriber error can make strict archive repair treat provider cleanup as unfinished even after it succeeds. 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="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

Comment thread packages/db/maintenance/project-membership.sql
Comment thread packages/db/scripts/push.integration.ts
Comment thread apps/sim/lib/workspaces/lifecycle.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.

All reported issues were addressed across 162 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/lib/projects/backfill-repair.ts Outdated
Comment thread apps/sim/scripts/backfill-projects.ts Outdated
Comment thread apps/sim/lib/workflows/lifecycle.ts
Lock and verify effective legacy memberships before materializing reviewed
assignments and applying the shared detach policy. Reject resume reports
whose code hash differs before changing their checkpoint. Isolate local
pubsub subscriber failures so healthy archive subscribers still receive
notifications.

Extend existing CLI and real-database integration coverage for mixed
memberships, concurrent and stale connector changes, unchanged mismatched
reports, replay, and local subscriber delivery.
@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 10, 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 165 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/lib/projects/__integration__/backfill-repair.integration.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 10, 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.

1 issue found across 166 files

Confidence score: 3/5

  • In reconcile-project-membership.ts, enforcement SQL can resolve to a shadow schema even though preflight checks public.*, so it may apply changes to the wrong schema. Qualify the enforcement references or constrain search_path.
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:27">
P1: The preflight checks `public.*`, but the enforcement SQL resolves unqualified table and function names through the database URL's `search_path`; a shadow schema can therefore receive the triggers or have its `project_workspace` dropped. Set this connection's search path to `public` before calling the helper, or qualify the helper's objects.</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

logger.info('Nullable Project membership column prepared')
if (!process.argv.includes('--prepare') && state.workspace && state.project) {
// Drizzle cannot express lifecycle triggers; fresh push uses the same enforcement as migrations.
await enforceProjectMembership(sql)

@cubic-dev-ai cubic-dev-ai Bot Oct 10, 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.

P1: The preflight checks public.*, but the enforcement SQL resolves unqualified table and function names through the database URL's search_path; a shadow schema can therefore receive the triggers or have its project_workspace dropped. Set this connection's search path to public before calling the helper, or qualify the helper's objects.

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/reconcile-project-membership.ts, line 27:

<comment>The preflight checks `public.*`, but the enforcement SQL resolves unqualified table and function names through the database URL's `search_path`; a shadow schema can therefore receive the triggers or have its `project_workspace` dropped. Set this connection's search path to `public` before calling the helper, or qualify the helper's objects.</comment>

<file context>
@@ -17,34 +17,15 @@ try {
-    logger.info('Nullable Project membership column prepared')
+  if (!process.argv.includes('--prepare') && state.workspace && state.project) {
+    // Drizzle cannot express lifecycle triggers; fresh push uses the same enforcement as migrations.
+    await enforceProjectMembership(sql)
+    logger.info('Project membership validation and lifecycle enforcement completed')
   }
</file context>
Suggested change
await enforceProjectMembership(sql)
await sql.unsafe('SET search_path = public')
await enforceProjectMembership(sql)
Fix with cubic

This branch was successfully deployed

1 active deployment
Preview — d0a97927 Deployed Oct 10, 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