Problem
Turn dispatch routes a parked session's next turn to the latest deployment only in production:
// packages/eve/src/execution/workflow-runtime.ts
function shouldRouteToLatestDeployment(): boolean {
return process.env.VERCEL_ENV === "production";
}
On preview, every turn of an existing session executes on the deployment that created the session — forever. Deployment updates (new skills, changed sandbox definitions, new tools) never apply to live sessions, and the rotation semantics documented in docs/sandbox.mdx ("the next turn starts from the rebuilt template and onSession runs again") cannot fire mid-session on preview targets.
Evidence
Surfaced by the agent-tools-sandbox sandbox/redeploy e2e eval: after a skill-adding redeploy verifiably served by the target alias (confirmed via /eve/v1/info and by inspecting the deployed bundle — the skill and rotated workspace content hash were present in both __server.func and the workflow flow.func), the parked session's turn still found the old sandbox file present and reported the new skill unavailable. The turn executed under the old deployment's manifest.
Why the gate is stricter than the platform
@workflow/world-vercel's resolveLatestDeploymentId() calls GET /v1/workflow/resolve-latest-deployment/{deploymentId}, which resolves the most recent deployment sharing the same environment — the production target, or the same git branch for preview deployments. Branch-carrying previews can resolve latest; only branch-less CLI deploys fail (HTTP 400 "Source deployment has no git branch"). The env-based gate generalizes that failure to all previews.
The routing machinery is otherwise fully built: STABLE_WORKFLOW_NAMES keeps workflowEntry/turnWorkflow ids version-unstamped for cross-deployment routing, and durable-session-migrations/turn-workflow.ts exists to migrate versioned turn inputs when a newer deployment executes a turn dispatched by an older driver.
Note: VERCEL_ENV is a reserved Vercel system variable, so there is no deployment-config workaround — the gate can only be fixed in code.
Proposed fix
Replace the env gate with attempt-plus-fallback in startWorkflowPreferLatest:
- Always attempt
start(…, { deploymentId: "latest" }) on worlds that implement resolveLatestDeploymentId().
- Fall back to pinned dispatch when resolution fails with the no-git-branch 400 (alongside the existing
LATEST_DEPLOYMENT_UNSUPPORTED_MESSAGE fallback), ideally caching the outcome so the extra API round-trip isn't paid on every turn.
Result: production unchanged; git-linked previews get branch-scoped adoption (each preview branch tracks its own latest); branch-less CLI deploys keep today's pinning instead of erroring.
Acceptance
- Flip the tripwire in
e2e/fixtures/agent-tools-sandbox/evals/sandbox/redeploy.eval.ts (t3 gate present → absent, and assert the added skill loads in the pre-existing session). The eval's deploys need a run-scoped git branch ref so resolve-latest has something to scope to — this also needs empirical confirmation that the API honors CLI-provided git metadata.
- Update
docs/sandbox.mdx and docs/concepts/execution-model-and-durability.md to state the adoption semantics per target (production/branch-carrying previews vs branch-less CLI deploys).
- Unit-test the new error classification in
workflow-runtime.
Hazard to keep in mind
Branch-scoped latest on a shared project routes turns to whichever app deployed most recently on that branch. Fine for the one-app-per-project model; the e2e matrix (many fixtures, one project, one checkout branch) must keep ordinary fixture deploys branch-less and give only the redeploy eval a run-scoped ref.
Problem
Turn dispatch routes a parked session's next turn to the latest deployment only in production:
On preview, every turn of an existing session executes on the deployment that created the session — forever. Deployment updates (new skills, changed sandbox definitions, new tools) never apply to live sessions, and the rotation semantics documented in
docs/sandbox.mdx("the next turn starts from the rebuilt template andonSessionruns again") cannot fire mid-session on preview targets.Evidence
Surfaced by the
agent-tools-sandboxsandbox/redeploye2e eval: after a skill-adding redeploy verifiably served by the target alias (confirmed via/eve/v1/infoand by inspecting the deployed bundle — the skill and rotated workspace content hash were present in both__server.funcand the workflowflow.func), the parked session's turn still found the old sandbox filepresentand reported the new skill unavailable. The turn executed under the old deployment's manifest.Why the gate is stricter than the platform
@workflow/world-vercel'sresolveLatestDeploymentId()callsGET /v1/workflow/resolve-latest-deployment/{deploymentId}, which resolves the most recent deployment sharing the same environment — the production target, or the same git branch for preview deployments. Branch-carrying previews can resolve latest; only branch-less CLI deploys fail (HTTP 400 "Source deployment has no git branch"). The env-based gate generalizes that failure to all previews.The routing machinery is otherwise fully built:
STABLE_WORKFLOW_NAMESkeepsworkflowEntry/turnWorkflowids version-unstamped for cross-deployment routing, anddurable-session-migrations/turn-workflow.tsexists to migrate versioned turn inputs when a newer deployment executes a turn dispatched by an older driver.Note:
VERCEL_ENVis a reserved Vercel system variable, so there is no deployment-config workaround — the gate can only be fixed in code.Proposed fix
Replace the env gate with attempt-plus-fallback in
startWorkflowPreferLatest:start(…, { deploymentId: "latest" })on worlds that implementresolveLatestDeploymentId().LATEST_DEPLOYMENT_UNSUPPORTED_MESSAGEfallback), ideally caching the outcome so the extra API round-trip isn't paid on every turn.Result: production unchanged; git-linked previews get branch-scoped adoption (each preview branch tracks its own latest); branch-less CLI deploys keep today's pinning instead of erroring.
Acceptance
e2e/fixtures/agent-tools-sandbox/evals/sandbox/redeploy.eval.ts(t3 gatepresent→absent, and assert the added skill loads in the pre-existing session). The eval's deploys need a run-scoped git branch ref so resolve-latest has something to scope to — this also needs empirical confirmation that the API honors CLI-provided git metadata.docs/sandbox.mdxanddocs/concepts/execution-model-and-durability.mdto state the adoption semantics per target (production/branch-carrying previews vs branch-less CLI deploys).workflow-runtime.Hazard to keep in mind
Branch-scoped latest on a shared project routes turns to whichever app deployed most recently on that branch. Fine for the one-app-per-project model; the e2e matrix (many fixtures, one project, one checkout branch) must keep ordinary fixture deploys branch-less and give only the redeploy eval a run-scoped ref.