Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
27 commits
Select commit Hold shift + click to select a range
14792a8
Re-vendor Interchange at 4ed8baf4: the workflow.json retirement
TheGreatAxios Aug 20, 2026
aeee913
Folded launch: build the single-step agent from resolved fields
TheGreatAxios Aug 20, 2026
d6624b2
Update docs: map the workflow.json retirement's conversion sites
TheGreatAxios Aug 20, 2026
50f209a
Add tests for onTrigger onBodyFailure and its projection
TheGreatAxios Aug 20, 2026
2792069
onTrigger: restore the onBodyFailure policy and carry it through proj…
TheGreatAxios Aug 20, 2026
bab0a4e
Add tests for the adopting code-sourced deploy front
TheGreatAxios Aug 20, 2026
6649d4e
hub-sessions: a code-sourced deploy front that adopts an existing anc…
TheGreatAxios Aug 20, 2026
3f85697
Update docs: ledger the onBodyFailure projection and the adopting dep…
TheGreatAxios Aug 20, 2026
1c25371
Add tests for the agent-runtime workflow source package
TheGreatAxios Aug 20, 2026
c737dba
Agent runtime: one versioned workflow source package, configured per …
TheGreatAxios Aug 20, 2026
5d39e37
Agent runtime: render the per-run config into the deployed bytes
TheGreatAxios Aug 20, 2026
08d744c
Update docs: the agent-runtime package and what still blocks deployAt…
TheGreatAxios Aug 20, 2026
255b783
Add tests for the code-sourced folded-run deploy
TheGreatAxios Aug 20, 2026
63bd99b
folded-runs: deploy a rendered source package, not a synthesized defi…
TheGreatAxios Aug 20, 2026
6684657
Update docs: deployAtHead is on the code-sourced seam
TheGreatAxios Aug 20, 2026
a136ae7
Add tests for the sidecar's closure-sourced deploy
Aug 20, 2026
31f99ec
Sidecar: deploy from the closure, not from workflow.json
Aug 20, 2026
b9534b7
Update docs: the sidecar is on closures, and what is still unproven
Aug 20, 2026
d2d46fd
Rebase onto main: reconcile the chat suite with the room-store cutover
TheGreatAxios Aug 20, 2026
0b22ee3
seed: push a workflow source codebase, not the retired workflow.json …
TheGreatAxios Aug 20, 2026
5a5023c
seed: deploy the pushed workflow source by source-ref, not by assetId
TheGreatAxios Aug 20, 2026
408c723
Update the seed's test doubles for the source-ref deploy body
TheGreatAxios Aug 20, 2026
97c8bea
Update docs: what the first real boot on the new rails found
TheGreatAxios Aug 20, 2026
a3660df
Add tests for the persisted projection and the dependency-free run tree
TheGreatAxios Aug 20, 2026
4b9a5a3
Persist a definition's inert projection with the freeze that hashed it
TheGreatAxios Aug 20, 2026
18ac014
Deploy a folded run from a tree the sidecar can actually resolve
TheGreatAxios Aug 20, 2026
ab0dd50
Add the CL-6324 four-proof harness, and update docs
TheGreatAxios Aug 20, 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
131 changes: 85 additions & 46 deletions VENDORED.md

Large diffs are not rendered by default.

3 changes: 0 additions & 3 deletions apps/hub/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1048,7 +1048,6 @@ export async function createHub(config: HubConfig) {
sidecarRouter,
eventCollectors,
credentialCipher,
hubPublicKey,
toolGrantsForPins,
mcpCredentialBindingsFor,
noopInferenceBaseUrl: `${config.baseUrl}/api/chat/noop-inference`,
Expand Down Expand Up @@ -1650,7 +1649,6 @@ export async function createHub(config: HubConfig) {
assetService,
sidecarRouter,
eventCollectors,
hubPublicKey,
toolGrantsForPins,
mcpCredentialBindingsFor,
cryptoProviderCache: foldedRunCryptoProviders,
Expand Down Expand Up @@ -2198,7 +2196,6 @@ export async function createHub(config: HubConfig) {
sidecarRouter,
eventCollectors,
credentialCipher,
hubPublicKey,
toolGrantsForPins,
mcpCredentialBindingsFor,
cryptoProviderCache: foldedRunCryptoProviders,
Expand Down
11 changes: 2 additions & 9 deletions apps/hub/src/routine-launcher.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
// goes through — and that a delivery failure past launch never un-does
// or hides the already-real run. `@corbits/folded-runs` is real here
// except for `launchFoldedRun`/`sendFoldedMailWithRetry`/
// `readDefinitionJSON`, which would otherwise need a real tenant catalog
// `readDefinitionProjection`, which would otherwise need a real tenant catalog
// and asset store — the same "swap the one export that needs a join"
// approach `packages/folded-runs/test/launch.test.ts` and
// `packages/webhook-triggers/test/launch.test.ts` use.
Expand Down Expand Up @@ -33,7 +33,7 @@ let sendFoldedMailWithRetryResult: unknown = {

mock.module("@corbits/folded-runs", () => ({
...actualFoldedRuns,
readDefinitionJSON: async () => ({ __fake: true }),
readDefinitionProjection: async () => ({ __fake: true }),
readFoldedBody: () => FOLDED_BODY,
launchFoldedRun: async (...args: unknown[]) => {
launchFoldedRunCalls.push(args);
Expand Down Expand Up @@ -114,7 +114,6 @@ function buildLauncher(overrides: { definition?: unknown } = {}) {
sessionService: {} as never,
assetService: {} as never,
sidecarRouter: {} as never,
hubPublicKey: "hub-key",
toolGrantsForPins: () => [],
eventCollectors: {} as never,
cryptoProviderCache: { get: async () => ({}) as never },
Expand Down Expand Up @@ -232,7 +231,6 @@ describe("createHubRoutineLauncher — delivery workbench", () => {
sessionService: {} as never,
assetService: {} as never,
sidecarRouter: {} as never,
hubPublicKey: "hub-key",
toolGrantsForPins: () => [],
eventCollectors: {} as never,
cryptoProviderCache: { get: async () => ({}) as never },
Expand All @@ -259,7 +257,6 @@ describe("createHubRoutineLauncher — recurring-task bridge", () => {
sessionService: {} as never,
assetService: {} as never,
sidecarRouter: {} as never,
hubPublicKey: "hub-key",
toolGrantsForPins: () => [],
eventCollectors: {} as never,
cryptoProviderCache: { get: async () => ({}) as never },
Expand Down Expand Up @@ -297,7 +294,6 @@ describe("createHubRoutineLauncher — recurring-task bridge", () => {
sessionService: {} as never,
assetService: {} as never,
sidecarRouter: {} as never,
hubPublicKey: "hub-key",
toolGrantsForPins: () => [],
eventCollectors: {} as never,
cryptoProviderCache: { get: async () => ({}) as never },
Expand All @@ -324,7 +320,6 @@ describe("createHubRoutineLauncher — recurring-task bridge", () => {
sessionService: {} as never,
assetService: {} as never,
sidecarRouter: {} as never,
hubPublicKey: "hub-key",
toolGrantsForPins: () => [],
eventCollectors: {} as never,
cryptoProviderCache: { get: async () => ({}) as never },
Expand Down Expand Up @@ -356,7 +351,6 @@ describe("createHubRoutineLauncher — recurring-task bridge", () => {
sessionService: {} as never,
assetService: {} as never,
sidecarRouter: {} as never,
hubPublicKey: "hub-key",
toolGrantsForPins: () => [],
eventCollectors: {} as never,
cryptoProviderCache: { get: async () => ({}) as never },
Expand All @@ -378,7 +372,6 @@ describe("createHubRoutineLauncher — recurring-task bridge", () => {
sessionService: {} as never,
assetService: {} as never,
sidecarRouter: {} as never,
hubPublicKey: "hub-key",
toolGrantsForPins: () => [],
eventCollectors: {} as never,
cryptoProviderCache: { get: async () => ({}) as never },
Expand Down
10 changes: 5 additions & 5 deletions apps/hub/src/routine-launcher.ts
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ import { tenant as tenantTable, workflowDefinition } from "@intx/db/schema";
import {
domainOf,
launchFoldedRun,
readDefinitionJSON,
readDefinitionProjection,
readFoldedBody,
sendFoldedMailWithRetry,
type CryptoProviderCache,
Expand Down Expand Up @@ -162,11 +162,11 @@ export function createHubRoutineLauncher(
throw new Error(`no tenant "${input.tenantId}"`);
}

const definitionJSON = await readDefinitionJSON(
deps.assetService,
definitionRow.assetId,
const projection = await readDefinitionProjection(deps.db, definitionRow);
const foldedBody = readFoldedBody(
projection,
definitionRow.grantRequirements,
);
const foldedBody = readFoldedBody(definitionJSON);

const instanceId = generateId("workflowRun");
const triggerAddress = formatRunAddress(instanceId, tenantRow.domain);
Expand Down
21 changes: 21 additions & 0 deletions apps/sidecar/bin/workflow-probe-child
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
#!/usr/bin/env bun
// One-shot workflow-probe child. The sidecar host spawns this by path
// (`Bun.spawn([binaryPath])`).
//
// The child reads the materialized package dir and IPC anchors from its
// fresh env, evaluates the workflow entry behind the airlock, and ships
// one HMAC-signed result frame on stdout. An evaluation failure is shipped
// as an `ok: false` frame (handled inside the runner), so a throw reaching
// here is a pre-evaluation defect (bad env, unwritable stdout) that exits
// non-zero -- the host then reaps and answers `workflow.probe.error`.
import { runWorkflowProbeChildFromProcessEnv } from "../src/workflow-probe-handler";

try {
await runWorkflowProbeChildFromProcessEnv();
process.exit(0);
} catch (err) {
process.stderr.write(
`workflow probe child failed: ${err instanceof Error ? err.message : String(err)}\n`,
);
process.exit(1);
}
30 changes: 29 additions & 1 deletion apps/sidecar/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,13 @@ import { createTarballCache } from "@intx/tool-packaging";
import { hexEncode } from "@intx/types";

import { readSidecarConfig } from "./config";
import { DEFAULT_TOOL_REGISTRIES_JSON } from "./tool-materialization";
import {
DEFAULT_TOOL_REGISTRIES_JSON,
parseToolRegistries,
} from "./tool-materialization";
import { createWorkflowProbeExecutor } from "./workflow-probe-handler";
import { createWorkflowClosureMaterializer } from "./workflow-closure-materialization";
import { MAX_INLINE_ASSET_PAYLOAD_BYTES } from "./source-asset-delivery";
import { createDefaultHarnessBuilder } from "./default-harness";
import { createHubLinkWatchdog } from "./hub-link-watchdog";
import { drainWithTimeout } from "./shutdown";
Expand Down Expand Up @@ -181,6 +187,27 @@ if (config.tmpdir !== undefined) {
// `canBuildSource` predicate against the one adapter registry.
const buildHarness = createDefaultHarnessBuilder({ adapters });

// Airlocked workflow-probe executor, assembled here and injected through the
// orchestrator so the sidecar answers `workflow.probe.request` with a real
// inert projection and its wire hash instead of the hub-link's rejecting
// placeholder. The materializer lays a probe frame's frozen closure out under
// a per-probe scratch dir (rooted in the sidecar data dir so it shares that
// dir's lifecycle); the executor spawns the one-shot child that evaluates the
// workflow entry against it. A probe delivers its source assets inline in one
// frame, capped by the shared inline-payload bound.
const workflowProbeExecutor = createWorkflowProbeExecutor({
materialize: createWorkflowClosureMaterializer({
cacheRoot: CACHE_ROOT,
cacheMaxBytes: CACHE_MAX_BYTES,
registryMaxTarballBytes: REGISTRY_MAX_TARBALL_BYTES,
maxAssetPayloadBytes: MAX_INLINE_ASSET_PAYLOAD_BYTES,
registries: parseToolRegistries(
config.toolRegistries ?? DEFAULT_TOOL_REGISTRIES_JSON,
),
scratchRoot: path.join(config.dataDir, "workflow-probe", "closures"),
}),
});

const watchdogLog = getLogger(["sidecar", "hub-link-watchdog"]);
const watchdog = createHubLinkWatchdog({
stallDeadlineMs: 60_000,
Expand Down Expand Up @@ -217,6 +244,7 @@ const orchestrator = createSidecarOrchestrator({
// supervisor spawns, against the unwrapped substrate so the restore is
// never echoed back to the Hub as a new sidecar-authored update.
applyWorkflowRunPack: restoreWorkflowRunPack,
workflowProbeExecutor,
// Called from every connection's open handler -- the watchdog's
// aliveness signal -- and from the close path, which immediately
// re-schedules a reconnect that re-arms the deadline.
Expand Down
Loading
Loading