Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
60 commits
Select commit Hold shift + click to select a range
b1e6caa
Add test for workflowDeployBody's catalog-offering shape
TheGreatAxios Sep 6, 2026
fae77c0
e2e: deploy workflows by catalog offering ids
TheGreatAxios Sep 6, 2026
b03ce16
Fix formatting
TheGreatAxios Sep 6, 2026
f981798
Add tests for deploying default workflows by catalog offering ids
TheGreatAxios Sep 6, 2026
1ce35c4
Seeding: deploy default workflows by catalog offering ids
TheGreatAxios Sep 6, 2026
2587cd2
longevity-sim: deploy workflows by catalog offering ids
TheGreatAxios Sep 6, 2026
2430449
Fix formatting: prettier
TheGreatAxios Sep 6, 2026
b65781e
Merge remote-tracking branch 'origin/cl-7461-seed-deploy-offering-ids…
TheGreatAxios Sep 6, 2026
602ad68
sandbox-sidecar: add tests for generation-0 ensure/destroy requests
TheGreatAxios Sep 6, 2026
e01feda
sandbox-sidecar: accept the allocation service's initial generation
TheGreatAxios Sep 6, 2026
c6da1fa
sandbox-sidecar: fix formatting in provisioner test
TheGreatAxios Sep 6, 2026
72d5be0
Merge remote-tracking branch 'origin/cl-7107-repin-and-re-vendor-audi…
TheGreatAxios Sep 6, 2026
824c2b6
Add tests for resolved catalog offerings and modelSourceFor's trimmed…
TheGreatAxios Sep 6, 2026
ec87551
Seed deploys against a tenant's resolved catalog offerings, not just …
TheGreatAxios Sep 6, 2026
dd1fe50
Merge remote-tracking branch 'origin/cl-7461-seed-deploy-offering-ids…
TheGreatAxios Sep 6, 2026
bcb8703
Add a regression test pinning the shared-sidecar auth gap (CL-7472)
TheGreatAxios Sep 6, 2026
ccbe497
e2e: stop pre-provisioning a shared sidecar identity (CL-7472)
TheGreatAxios Sep 6, 2026
308ab25
ci: upload hub/sidecar e2e logs as a build artifact (CL-7472)
TheGreatAxios Sep 6, 2026
27b8f84
Merge remote-tracking branch 'origin/cl-7107-repin-and-re-vendor-audi…
TheGreatAxios Sep 6, 2026
b72964e
Add tests for tenant-scoped workbench_launch address resolution (CL-7…
TheGreatAxios Sep 6, 2026
262a381
Chat: workbench_launch address/stableId lookups are tenant-scoped
TheGreatAxios Sep 6, 2026
b75eebc
Chat: run prettier on the tenant-scoping change
TheGreatAxios Sep 6, 2026
040f085
Merge remote-tracking branch 'origin/cl-7107-repin-and-re-vendor-audi…
TheGreatAxios Sep 6, 2026
75300cb
Merge the re-pin branch into cl-7474-cross-tenant-launch
TheGreatAxios Sep 6, 2026
0eef0e0
Chat: tenant-scoped binding reads require the tenant; the one unscope…
TheGreatAxios Sep 6, 2026
b677451
Add tests for the shared retry-until-routable delivery helper
TheGreatAxios Sep 6, 2026
5cb3164
Deliver a webhook trigger's opening mail once its sidecar becomes rou…
TheGreatAxios Sep 6, 2026
a0c8a27
Log a skip, not an error, when root tenant seed has no operator key c…
TheGreatAxios Sep 6, 2026
ff22eef
Merge remote-tracking branch 'origin/cl-7474-cross-tenant-launch' int…
TheGreatAxios Sep 6, 2026
1fd89dd
Run prettier
TheGreatAxios Sep 6, 2026
3f8fdc9
Chat: run prettier on the tenant-scoping test file
TheGreatAxios Sep 6, 2026
3cf5507
Merge remote-tracking branches 'origin/cl-7474-cross-tenant-launch' a…
TheGreatAxios Sep 6, 2026
46a4a93
Add a DB-gated test for recording a run's agent_session (CL-7477)
TheGreatAxios Sep 6, 2026
39ea012
Native launch records the run's agent_session so mail and spans persi…
TheGreatAxios Sep 6, 2026
5f92950
Merge remote-tracking branch 'origin/cl-7107-repin-and-re-vendor-audi…
TheGreatAxios Sep 6, 2026
f31e0e1
Add tests for the run's event collector create/abandon wiring
TheGreatAxios Sep 6, 2026
9260c3a
Native launch creates the run's event collector so turns are recorded…
TheGreatAxios Sep 6, 2026
3706a53
Merge remote-tracking branch 'origin/cl-7107-repin-and-re-vendor-audi…
TheGreatAxios Sep 6, 2026
f6369d9
Add tests for lazy, idempotent run-session ensure (CL-7480)
TheGreatAxios Sep 6, 2026
d6eda39
Hub ensures a run's session and collector on first use (CL-7480)
TheGreatAxios Sep 6, 2026
63b2d2e
Fix prettier formatting in agent-session.ts (CL-7480)
TheGreatAxios Sep 6, 2026
af790b2
Add tests for eager session recording and launch-spec session lookup
TheGreatAxios Sep 6, 2026
ae8d33b
Record a run's session at provision; re-key it when Interchange ancho…
TheGreatAxios Sep 6, 2026
2b5dd7a
Fix CI: prettier formatting, principal enum value, and workflowRunLau…
TheGreatAxios Sep 6, 2026
258cfe4
Merge remote-tracking branch 'origin/cl-7107-repin-and-re-vendor-audi…
TheGreatAxios Sep 6, 2026
8b469ac
Merge the re-pin branch into cl-7481-eager-session
TheGreatAxios Sep 6, 2026
c57dd9d
Fix merge fallout: restore CL-7481 agent-session exports and drop a d…
TheGreatAxios Sep 6, 2026
42f0511
Add tests for wake retry re-resolving the live address (CL-7486)
TheGreatAxios Sep 6, 2026
c5cbceb
Chat: wake retry chases the run a relaunch replaced it with (CL-7486)
TheGreatAxios Sep 6, 2026
485dc99
Merge remote-tracking branch 'origin/cl-7481-eager-session' into cl-7…
TheGreatAxios Sep 6, 2026
ebc173b
Fix webhook-triggers launch test fixture: eventCollectors needs has()
TheGreatAxios Sep 6, 2026
097b172
Add test coverage for routable-wait relaunch chasing in sendRunMailWi…
TheGreatAxios Sep 6, 2026
153b818
Chat: wait for the routing table instead of a fixed backoff before gi…
TheGreatAxios Sep 6, 2026
320deb2
Fix formatting
TheGreatAxios Sep 6, 2026
632b439
Merge the re-pin branch into cl-7488-chat-routable
TheGreatAxios Sep 6, 2026
3cfb6de
Add test coverage for ensureRunSession creating a session for an API-…
TheGreatAxios Sep 6, 2026
6547f36
ensureRunSession: create the session row instead of throwing when it'…
TheGreatAxios Sep 6, 2026
b9785a9
Add tests for waiting on a booting run instead of relaunching it
TheGreatAxios Sep 6, 2026
a1370dc
Chat: a booting run is waited on, not relaunched
TheGreatAxios Sep 6, 2026
6679721
Merge the re-pin branch into cl-7490-wake-booting
TheGreatAxios Sep 6, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 18 additions & 1 deletion packages/chat/src/agent-binding.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -186,12 +186,29 @@ describe("isBeyondWake", () => {
).toBe(false);
});

test("a completed run is beyond waking — wake is a fresh provision", async () => {
test("a completed run that took a turn is beyond waking — wake is a fresh provision", async () => {
expect(
await isBeyondWake(fakeDb([]), {
id: "run_done",
status: "completed",
principalId: "prin_1",
}),
).toBe(true);
});

// CL-7490: a deployment `markTerminal`'d before its first trigger ever
// landed settles "completed" too (see `workflow-run-store.ts`'s
// `markTerminal`), and the store cannot otherwise tell that apart from a
// run still mid-boot. Treating it as beyond waking here is exactly the
// bug that made a booting run's status read as terminal and relaunched
// it out from under its own in-flight sidecar registration.
test("a completed run that never took a turn is not beyond waking — the store cannot tell it apart from still booting", async () => {
expect(
await isBeyondWake(fakeDb([]), {
id: "run_never_triggered",
status: "completed",
principalId: null,
}),
).toBe(false);
});
});
39 changes: 29 additions & 10 deletions packages/chat/src/agent-binding.ts
Original file line number Diff line number Diff line change
Expand Up @@ -314,27 +314,46 @@ export async function readPriorRuns(
}

/**
* The statuses a `workflow_run` can hold that mean "this run will never
* accept mail again". Wake of a reaped or lost instance is a fresh
* `prepareProvisionedDeployment`, not a reuse of this row.
* The statuses a `workflow_run` can hold that are terminal regardless of
* whether the run ever took a turn. `"completed"` is deliberately absent
* here — a deployment `markTerminal`'d before its first trigger settles
* "completed" too (see `workflow-run-store.ts`'s `markTerminal`), and that
* is a run that is still booting, not one that will "never accept mail
* again". `isBeyondWake` below folds `"completed"` back in only once it
* can tell the two apart.
*/
const TERMINAL_RUN_STATUSES: ReadonlySet<string> = new Set([
const UNCONDITIONALLY_TERMINAL_RUN_STATUSES: ReadonlySet<string> = new Set([
"failed",
"cancelled",
"canceled",
"completed",
]);

/**
* Whether this run is dead: terminal in `workflow_run.status`. A run
* this returns true for cannot be woken — it can only be relaunched as
* a fresh provisioned deployment.
* Whether this run is dead: terminal in `workflow_run.status`, in a way
* that actually means "this run will never accept mail again" rather than
* "this deployment never got as far as its first trigger". A run this
* returns true for cannot be woken — it can only be relaunched as a fresh
* provisioned deployment. A run this returns false for — `"deployed"` or
* `"running"`, or `"completed"` with no principal ever anchored to it — is
* still live or still booting: waking it means waiting for it to become
* routable (`deliverWhenRoutable`), never relaunching it (CL-7490).
*
* `principalId` is the signal for "ever took a turn": `anchorWithPrincipal`
* sets it in the same update that flips `"deployed"` -> `"running"` on a
* deployment's first trigger, and a child run is born with one already. A
* `"completed"` run with no `principalId` can only be a deployment torn
* down before that first trigger ever landed — the store cannot tell that
* apart from a mid-boot deployment misreporting itself terminal, so it is
* treated as still booting rather than relaunched out from under a caller
* that is only waiting on it.
*/
export async function isBeyondWake(
_db: DB["db"],
run: { id: string; status: string },
run: { id: string; status: string; principalId?: string | null },
): Promise<boolean> {
return TERMINAL_RUN_STATUSES.has(run.status);
if (UNCONDITIONALLY_TERMINAL_RUN_STATUSES.has(run.status)) return true;
if (run.status !== "completed") return false;
return run.principalId !== null && run.principalId !== undefined;
}

/**
Expand Down
41 changes: 12 additions & 29 deletions packages/chat/src/platform-adapter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -733,35 +733,18 @@ export function createHubChatPlatform(
return;
}

if (live.run.definitionId === null) {
throw new Error(
`Cannot wake "${binding.stableId}": its run ${live.run.id} names no definition`,
);
}
const definitionAssetId = await resolveDefinitionAssetId(
live.run.definitionId,
);
if (definitionAssetId === undefined) {
throw new Error(
`Cannot wake "${binding.stableId}": definition ${live.run.definitionId} has no workflow asset`,
);
}
const prepared = await provisionOnAsset({
tenantId: binding.tenantId,
deploymentDomain: domainOf(binding.roomAddress),
sourceAuthorityPrincipalId:
await sourceAuthorityForAsset(definitionAssetId),
definitionAssetId,
foldedBody: binding.foldedBody,
});
await repointBinding(
deps.db,
binding,
prepared.runId,
prepared.sourcesDigest,
);
lifecycle?.untrack(binding.liveAddress);
lifecycle?.track(prepared.address);
// CL-7490: not terminal, and not (yet) routable. A provisioned
// anchor stays "deployed" until its first trigger — this is
// exactly what a run mid-boot looks like from here, and relaunching
// it out from under its own in-flight sidecar registration is what
// supersedes the allocation and restarts the boot forever (the
// "Deployed agent" line never appears; a fresh sidecar/allocation
// shows up every few seconds instead). There is nothing this
// function can safely do for a live-but-not-yet-routable run: the
// caller's own routable wait (`deliverWhenRoutable`, wired through
// `sendRunMailWithReclaimRetry`) is what actually resolves this, by
// polling the routing table until the boot finishes or its budget
// runs out. A no-op here is the correct "nothing more to do".
} catch (error) {
throw wrapWakeInferenceError(error);
}
Expand Down
Loading
Loading