Skip to content

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

Merged
mzxchandra merged 137 commits into
stagingfrom
codex/project-entity-enforcement
Oct 13, 2026
Merged

mzxchandra merged 137 commits into
stagingfrom
codex/project-entity-enforcement

Conversation

@mzxchandra

@mzxchandra mzxchandra commented Oct 2, 2026 •

Copy link
Copy Markdown
Contributor

Summary

Complete the migration to workspace.project_id after #8830 is deployed and incompatible membership activity has drained. Release-2 migrations run before application promotion, while release 1 serves traffic.

  • The existing registered 0032_project_membership runner switches the checked singleton to column authority under the workspace barrier, then performs bounded, resumable assignment and reconciliation. SQL 0411 remains a placeholder because SQL migrations precede script migrations.
  • Preserve existing Project identity, archive state and ownership; stop for ambiguous grouping or incomplete provider cleanup. Retain reviewed operator repair and resume paths.
  • Validate membership, enforce workspace.project_id NOT NULL and its restrictive FK, then atomically remove both project_workspace and project_membership_rollout. The authority-aware feat(projects): move Project membership to the workspace column #8830 runtime remains the supported rollback version after contraction.

Permanent enforcement

Replace all custom Project integrity triggers, trigger-specific advisory locks, deferred row-version dispatch, and UPDATE project SET updated_at = updated_at with native constraints:

  • A generated organization scope key on Project/workspace encodes NULL as personal and IDs as organization:<id>. The expression always yields a value, cannot be overridden by writers, and supports a composite organization-consistency FK without the nullable-FK loophole.
  • A composite workspace self-FK requires each connected fork to share its parent's Project. The existing parent-ID FK still clears only the parent pointer on deletion; Project membership never cascades automatically.
  • Both composite FKs are deferred so atomic organization transfers and subtree moves can complete before validation. Their supporting unique indexes are built concurrently and attached as named unique constraints. Fresh schema push uses the same finalizer to restore deferred timing, which Drizzle does not model.

Project non-emptiness and archive lifecycle remain application-owned. Keep existing application Project/lineage/edge/workspace locks and transactional workflow admission. Backfill still validates legacy lifecycle state once; it does not install permanent lifecycle triggers. Keep project.updated_at as ordinary metadata, and exclude the new internal scope key from Project presentation.

Deployment sequence

  1. Deploy feat(projects): move Project membership to the workspace column #8830 first. It adds nullable membership and the authority marker without bulk backfill. Connector-phase transactions read/write only the connector; column-phase transactions use workspace membership with connector fallback only for unassigned rows. Authority is read transactionally under the workspace barrier, never cached across transactions.
  2. Verify the complete compatible release is serving and incompatible in-flight membership operations and independently scheduled workers have drained. All-at-once app traffic cutover prevents fresh requests reaching retired servers; it does not prove independent workers have drained. The deployment gate verifies the acknowledged release and app task retirement; operators must separately verify relevant workers.
  3. Run this release's migrations while feat(projects): move Project membership to the workspace column #8830 still serves, before promoting this release. Switch authority under the bounded workspace barrier, then run resumable backfill/reconciliation. Review ambiguous grouping and finish required external cleanup before contraction.
  4. Validate native constraints and require membership, then drop both connector and marker in one transaction. Verify assignments and lifecycle state, the completion receipt, and reads/writes through the still-supported feat(projects): move Project membership to the workspace column #8830 runtime. A missing marker with an incomplete schema fails closed.
  5. Promote this release after successful migration. If application rollback is needed after authority switches, use feat(projects): move Project membership to the workspace column #8830 and retain the database changes. Never roll back to pre-feat(projects): move Project membership to the workspace column #8830 code or restore connector authority.

Migration trade-off and rollback

On PostgreSQL 16/17, adding stored generated columns rewrites the Project/workspace tables. This phase refuses busy tables and bounds each statement to five seconds; a timeout rolls it back before connector removal. This is a bounded blocking operation, not a zero-interruption column addition. Assess table size/capacity before deployment; do not silently extend its lock budget. Interrupted concurrent unique-index builds are repaired on replay.

Use the existing all-at-once traffic cutover and verify the concrete old membership operations/workers have drained. No new maintenance mechanism, dual writes, synchronization triggers, extra compatibility release, or Project-specific PostgreSQL16 CI is introduced. Once authority switches, keep column authority on retries/rollback and never deploy pre-#8830 code. Updated #8830 recognizes the completed schema without the marker, so rollback requires no retained rollout table. Fresh schema push creates no marker; migration replay recognizes completed contraction even when recording its receipt previously failed.

Validation

Focused local verification on 6a43776bc2, using isolated Docker PostgreSQL 17 and Redis:

  • Fresh database migration through SQL 0411 and script 0032 passed.
  • 87 database integration tests passed: authority cutover, backfill/contract, operator CLI, lock budgets, search-path isolation, receipt replay, and schema push.
  • 49 application integration tests passed: operator repair, workspace imports, file names, public log paging, chat stream status, and Recently Deleted.
  • Application typecheck and affected-file Biome passed. The three newly merged staging fixtures now use the shared workspace fixture helper for required membership and cleanup.
  • Persisted readback confirmed the connector and marker are absent, the script receipt exists, and no fixture users, workspaces, or Projects remain.
  • The preceding staging merge passed database typecheck, migration safety, schema-generation drift, and snapshot/journal ordering checks.

Full current-head CI runs in GitHub Actions; these local results do not claim hosted CI or production rollout completion. No phone/Android matrix or full repository suite was run locally.

Downstream synchronization

Greptile's open finding on #8781 is a valid downstream dependency: its supplied head 10f89e065f still imports/queries projectWorkspace in project-file-read.integration.ts, project-file-write-transport.integration.ts, and project-file-context.integration.ts. When synchronizing that branch with this stack, replace the connector lookup with workspace.projectId (or the row returned by insertWorkspaceFixture) and remove the retired schema import. Those files are absent from #8590; this PR does not claim the downstream adaptation is complete. Downstream #8609/#8610 also retain their previously recorded synchronization requirement.

@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 13, 2026 1:33am 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 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.

No issues found across 175 files

Confidence score: 5/5

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

Heads up: you’ve reached your flex budget. Increase your flex budget or wait for usage to reset.

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/README.md
Base automatically changed from feat/project-workspace-column-expand to staging October 10, 2026 21:24
@mzxchandra
mzxchandra marked this pull request as ready for review October 13, 2026 01:03

@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 175 files

Confidence score: 5/5

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

Heads up: you’ve reached your flex budget. Increase your flex budget or wait for usage to reset.

Turn on auto-fix | Re-trigger cubic

Comment thread packages/db/maintenance/project-membership.sql
@mzxchandra

Copy link
Copy Markdown
Contributor Author

@greptile Please re-review head 6a43776. The staging fixture type errors are fixed using shared Project-aware insertion and cleanup. Fresh Docker PostgreSQL 17 migration, all 87 focused database tests, all 49 affected application tests, application typecheck, and affected-file lint passed locally before this push.

The open #8781 finding is a valid downstream synchronization requirement, documented in the PR description with its current head and the three affected files. Those files are not in #8590; no downstream completion is claimed and the retired connector is not restored here. Please distinguish current-PR defects from that outstanding stack adaptation.

@mzxchandra

Copy link
Copy Markdown
Contributor Author

@cubic-dev-ai review this PR

@cubic-dev-ai

cubic-dev-ai Bot commented Oct 13, 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 178 files

Confidence score: 5/5

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

Heads up: you’ve reached your flex budget. Increase your flex budget or wait for usage to reset.

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/scripts/reconcile-project-membership.ts Outdated
Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com>
@mzxchandra
mzxchandra merged commit eef9d29 into staging Oct 13, 2026
49 of 51 checks passed
@waleedlatif1
waleedlatif1 deleted the codex/project-entity-enforcement branch October 13, 2026 01:59

This branch was successfully deployed

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