Uh oh!
There was an error while loading. Please reload this page.
feat(workspaces): fork + push/pull - #5210
Conversation
The latest updates on your projects. Learn more about Vercel for GitHub. |
PR SummaryHigh Risk Overview The outbox processor cron now also reaps stale fork background-work rows stuck in Manage Forks and Sync workspace modals in the sidebar expose fork creation (optional resource copy), mapping wizard with dependent-field reconfiguration, overwrite confirmation, rollback, and an Activity tab backed by Workflow copy/sync logic gains shared subblock remapping (variables, conditions, cross-workflow references with optional A small editor fix wraps tool-input params in Reviewed by Cursor Bugbot for commit d5b4bd5. Configure here. |
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
Greptile SummaryThis PR introduces workspace forking — the ability to create a child workspace from a parent and bi-directionally sync (push/pull) deployed workflows and mapped resources between them. It is a large, well-structured addition spanning new DB tables, advisory-locked promote/rollback transactions, a credential-access propagation layer, and a full set of UI components.
Confidence Score: 5/5Safe to merge — the promote and rollback paths are carefully locked and the only new finding is a performance gap in the mapping GET endpoint. The core transaction paths (promote, rollback, fork creation) are well-guarded with advisory locks, deterministic lock ordering, locked re-confirmation of undo points, and durable outbox side-effects. The sole new finding is that getForkMappingView reads deployed workflow states one at a time in a sequential loop with no workflow count cap, while the sibling diff and promote paths already use bounded-concurrency batching and throw at 1000 workflows. This is a latency concern on the GET /mapping endpoint for large workspaces, not a correctness issue. apps/sim/lib/workspaces/fork/mapping/mapping-service.ts — the getForkMappingView sequential-read loop (lines 94–107) should adopt the same bounded-concurrency and count-cap pattern used by loadSourceDeployedStates. Important Files Changed
Sequence Diagram%%{init: {'theme': 'neutral'}}%%
sequenceDiagram
participant Client
participant ForkRoute as POST /fork
participant PromoteRoute as POST /fork/promote
participant RollbackRoute as POST /fork/rollback
participant Auth as assertCanPromote/Fork
participant DB as PostgreSQL (advisory locks)
participant Outbox as Deployment Outbox
Client->>ForkRoute: fork workspace
ForkRoute->>Auth: assertCanFork (admin + plan gate)
Auth-->>ForkRoute: source + policy
ForkRoute->>DB: tx(lock) — copy workflows, seed mappings
DB-->>ForkRoute: new workspace id
ForkRoute->>Outbox: schedule background content copy
ForkRoute-->>Client: 201 workspaceId
Client->>PromoteRoute: push/pull with dependentValues
PromoteRoute->>Auth: assertCanPromote (admin on both)
Auth->>DB: resolveForkEdge (2 queries)
PromoteRoute->>DB: loadSourceDeployedStates (pre-tx)
PromoteRoute->>DB: tx(acquireTargetLock + acquireEdgeLock)
DB->>DB: computePromotePlan
DB->>DB: copyWorkflowStateIntoTarget (each item)
DB->>DB: reconcileBlockPairs + upsertIdentityMappings
DB->>DB: propagateCredentialAccess
DB->>DB: upsertPromoteRun (snapshot for rollback)
DB-->>PromoteRoute: promoteRunId + counts
PromoteRoute->>Outbox: process undeploy events (post-commit)
PromoteRoute->>DB: performFullDeploy (per target, unlocked)
PromoteRoute-->>Client: updated/created/archived/redeployed
Client->>RollbackRoute: rollback (otherWorkspaceId)
RollbackRoute->>Auth: assertCanRollback (admin on target)
RollbackRoute->>DB: getLatestPromoteRunForTarget (pre-tx)
RollbackRoute->>DB: tx(acquireTargetLock + acquireEdgeLock)
DB->>DB: re-confirm run is still newest
DB->>DB: un-archive + reactivate / undeploy + archive
DB->>DB: deleteAllPromoteRunsForTarget
DB-->>RollbackRoute: outbox event ids
RollbackRoute->>Outbox: process side-effects (post-commit)
RollbackRoute-->>Client: restored/archived/unarchived/skipped
%%{init: {'theme': 'base', 'themeVariables': {"darkMode": true, "background": "#0d1117", "primaryColor": "#21262d", "primaryTextColor": "#e6edf3", "primaryBorderColor": "#8b949e", "lineColor": "#8b949e", "textColor": "#e6edf3", "edgeLabelBackground": "#161b22", "actorBkg": "#21262d", "actorBorder": "#8b949e", "actorTextColor": "#e6edf3", "actorLineColor": "#8b949e", "signalColor": "#8b949e", "signalTextColor": "#e6edf3", "noteBkgColor": "#373320", "noteBorderColor": "#d4a72c", "noteTextColor": "#f0e6c0", "labelBoxBkgColor": "#21262d", "labelBoxBorderColor": "#8b949e", "labelTextColor": "#e6edf3", "loopTextColor": "#e6edf3", "activationBkgColor": "#30363d", "activationBorderColor": "#8b949e"}}}%%
sequenceDiagram
participant Client
participant ForkRoute as POST /fork
participant PromoteRoute as POST /fork/promote
participant RollbackRoute as POST /fork/rollback
participant Auth as assertCanPromote/Fork
participant DB as PostgreSQL (advisory locks)
participant Outbox as Deployment Outbox
Client->>ForkRoute: fork workspace
ForkRoute->>Auth: assertCanFork (admin + plan gate)
Auth-->>ForkRoute: source + policy
ForkRoute->>DB: tx(lock) — copy workflows, seed mappings
DB-->>ForkRoute: new workspace id
ForkRoute->>Outbox: schedule background content copy
ForkRoute-->>Client: 201 workspaceId
Client->>PromoteRoute: push/pull with dependentValues
PromoteRoute->>Auth: assertCanPromote (admin on both)
Auth->>DB: resolveForkEdge (2 queries)
PromoteRoute->>DB: loadSourceDeployedStates (pre-tx)
PromoteRoute->>DB: tx(acquireTargetLock + acquireEdgeLock)
DB->>DB: computePromotePlan
DB->>DB: copyWorkflowStateIntoTarget (each item)
DB->>DB: reconcileBlockPairs + upsertIdentityMappings
DB->>DB: propagateCredentialAccess
DB->>DB: upsertPromoteRun (snapshot for rollback)
DB-->>PromoteRoute: promoteRunId + counts
PromoteRoute->>Outbox: process undeploy events (post-commit)
PromoteRoute->>DB: performFullDeploy (per target, unlocked)
PromoteRoute-->>Client: updated/created/archived/redeployed
Client->>RollbackRoute: rollback (otherWorkspaceId)
RollbackRoute->>Auth: assertCanRollback (admin on target)
RollbackRoute->>DB: getLatestPromoteRunForTarget (pre-tx)
RollbackRoute->>DB: tx(acquireTargetLock + acquireEdgeLock)
DB->>DB: re-confirm run is still newest
DB->>DB: un-archive + reactivate / undeploy + archive
DB->>DB: deleteAllPromoteRunsForTarget
DB-->>RollbackRoute: outbox event ids
RollbackRoute->>Outbox: process side-effects (post-commit)
RollbackRoute-->>Client: restored/archived/unarchived/skipped
Reviews (6): Last reviewed commit: "fix required + dependsOn combo" | Re-trigger Greptile |
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
icecrasher321
commented
Jun 25, 2026
icecrasher321
commented
Jun 25, 2026
bugbot run |
Uh oh!
There was an error while loading. Please reload this page.
icecrasher321
commented
Jun 25, 2026
bugbot run |
icecrasher321
commented
Jun 27, 2026
bugbot run |
Uh oh!
There was an error while loading. Please reload this page.
icecrasher321
commented
Jun 28, 2026
bugbot run |
Uh oh!
There was an error while loading. Please reload this page.
…guard first-sync fallback, perf + cleanup)
icecrasher321
commented
Jun 28, 2026
bugbot run |
Uh oh!
There was an error while loading. Please reload this page.
icecrasher321
commented
Jun 28, 2026
bugbot run |
icecrasher321
commented
Jun 28, 2026
bugbot run |
Uh oh!
There was an error while loading. Please reload this page.
icecrasher321
commented
Jun 28, 2026
bugbot run |
Uh oh!
There was an error while loading. Please reload this page.
icecrasher321
commented
Jun 28, 2026
bugbot run |
There was a problem hiding this comment.
✅ Bugbot reviewed your changes and found no new issues!
Comment @cursor review or bugbot run to trigger another review on this PR
Reviewed by Cursor Bugbot for commit d5b4bd5. Configure here.
icecrasher321
commented
Jun 28, 2026
Uh oh!
There was an error while loading. Please reload this page.
Summary
Be able to Fork Workspaces. And push/pull changes into or from parent workspaces. Allows one click promotion between environments and supports mapping credentials, secrets, and resources.
Type of Change
Testing
Tested manually
Checklist