@intx/workflow-host 0.2.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +176 -0
- package/README.md +287 -0
- package/dist/adapters/blob-substrate.d.ts +49 -0
- package/dist/adapters/blob-substrate.js +140 -0
- package/dist/adapters/repo-store.d.ts +39 -0
- package/dist/adapters/repo-store.js +344 -0
- package/dist/adapters/spawn-child.d.ts +74 -0
- package/dist/adapters/spawn-child.js +152 -0
- package/dist/adapters/step-invoker.d.ts +114 -0
- package/dist/adapters/step-invoker.js +360 -0
- package/dist/child/env-bootstrap.d.ts +56 -0
- package/dist/child/env-bootstrap.js +120 -0
- package/dist/child/from-process-env.d.ts +127 -0
- package/dist/child/from-process-env.js +183 -0
- package/dist/child/index.d.ts +9 -0
- package/dist/child/index.js +9 -0
- package/dist/child/outbound-mail-bridge.d.ts +36 -0
- package/dist/child/outbound-mail-bridge.js +143 -0
- package/dist/child/proxy-repo-store.d.ts +27 -0
- package/dist/child/proxy-repo-store.js +200 -0
- package/dist/child/run-child.d.ts +320 -0
- package/dist/child/run-child.js +900 -0
- package/dist/child/self-discovery.d.ts +29 -0
- package/dist/child/self-discovery.js +57 -0
- package/dist/child/substrate-write-bridge.d.ts +72 -0
- package/dist/child/substrate-write-bridge.js +188 -0
- package/dist/child/supervisor-backed-transport.d.ts +10 -0
- package/dist/child/supervisor-backed-transport.js +113 -0
- package/dist/child/warm-agent-cache.d.ts +78 -0
- package/dist/child/warm-agent-cache.js +112 -0
- package/dist/drain-controller.d.ts +37 -0
- package/dist/drain-controller.js +46 -0
- package/dist/index.d.ts +10 -0
- package/dist/index.js +10 -0
- package/dist/ipc/control-channel.d.ts +336 -0
- package/dist/ipc/control-channel.js +532 -0
- package/dist/ipc/crypto.d.ts +46 -0
- package/dist/ipc/crypto.js +126 -0
- package/dist/ipc/envelope.d.ts +53 -0
- package/dist/ipc/envelope.js +88 -0
- package/dist/ipc/event-channel.d.ts +677 -0
- package/dist/ipc/event-channel.js +278 -0
- package/dist/ipc/index.d.ts +4 -0
- package/dist/ipc/index.js +143 -0
- package/dist/mail-bus/hub-transport-adapter.d.ts +30 -0
- package/dist/mail-bus/hub-transport-adapter.js +76 -0
- package/dist/mail-bus/index.d.ts +1 -0
- package/dist/mail-bus/index.js +1 -0
- package/dist/seams/index.d.ts +3 -0
- package/dist/seams/index.js +3 -0
- package/dist/seams/scheduler-adapter.d.ts +3 -0
- package/dist/seams/scheduler-adapter.js +24 -0
- package/dist/seams/scheduler.d.ts +94 -0
- package/dist/seams/scheduler.js +397 -0
- package/dist/seams/signal-channel.d.ts +74 -0
- package/dist/seams/signal-channel.js +304 -0
- package/dist/supervisor/cancel-signing.d.ts +68 -0
- package/dist/supervisor/cancel-signing.js +144 -0
- package/dist/supervisor/child-termination.d.ts +51 -0
- package/dist/supervisor/child-termination.js +76 -0
- package/dist/supervisor/credentials.d.ts +101 -0
- package/dist/supervisor/credentials.js +153 -0
- package/dist/supervisor/dispatch-attribution.d.ts +37 -0
- package/dist/supervisor/dispatch-attribution.js +114 -0
- package/dist/supervisor/drain-timeout.d.ts +127 -0
- package/dist/supervisor/drain-timeout.js +231 -0
- package/dist/supervisor/index.d.ts +7 -0
- package/dist/supervisor/index.js +6 -0
- package/dist/supervisor/recycle.d.ts +212 -0
- package/dist/supervisor/recycle.js +440 -0
- package/dist/supervisor/run-event-compaction.d.ts +34 -0
- package/dist/supervisor/run-event-compaction.js +115 -0
- package/dist/supervisor/spawn-env.d.ts +39 -0
- package/dist/supervisor/spawn-env.js +36 -0
- package/dist/supervisor/supervisor.d.ts +202 -0
- package/dist/supervisor/supervisor.js +2244 -0
- package/dist/supervisor/terminal-broadcaster.d.ts +45 -0
- package/dist/supervisor/terminal-broadcaster.js +184 -0
- package/dist/supervisor/types.d.ts +542 -0
- package/dist/supervisor/types.js +10 -0
- package/package.json +35 -0
|
@@ -0,0 +1,320 @@
|
|
|
1
|
+
import type { Principal, RepoId, RepoStore as SubstrateRepoStore } from "@intx/hub-sessions/substrate";
|
|
2
|
+
import type { DirectorRegistry } from "@intx/agent";
|
|
3
|
+
import type { AuthzCallResult } from "@intx/inference";
|
|
4
|
+
import type { RunResult, Scheduler, StepInvokeRequest, StepInvokeResult, SpawnChildWorkflow, WorkflowAuthorizeFn } from "@intx/workflow";
|
|
5
|
+
import { type WorkflowHostDrainController } from "../drain-controller.js";
|
|
6
|
+
import type { InferenceSource } from "@intx/types/runtime";
|
|
7
|
+
import { type ControlChannelSender, type ControlPayload, type EventPayload, type FrameWriter, type NdjsonReader, type NdjsonWriter } from "../ipc/index.js";
|
|
8
|
+
import type { CredentialsSnapshot } from "../supervisor/credentials.js";
|
|
9
|
+
import { hashGrants } from "../supervisor/credentials.js";
|
|
10
|
+
import type { SpawnTimeEnv } from "./env-bootstrap.js";
|
|
11
|
+
import type { ChildOutboundMailBridge } from "./outbound-mail-bridge.js";
|
|
12
|
+
import { type WarmAgentCache } from "./warm-agent-cache.js";
|
|
13
|
+
/**
|
|
14
|
+
* `WorkflowAuthorize` closure factory shape. The child's authorize
|
|
15
|
+
* evaluates a `(resource, action)` request against the active
|
|
16
|
+
* credentialsSnapshot for the originating step. The closure used here
|
|
17
|
+
* is intentionally permissive on missing context: the workflow runtime
|
|
18
|
+
* supplies `stepId` from the `AuthorizeContext` it threads through
|
|
19
|
+
* every step's invoker, so a bare-call without a step id is a
|
|
20
|
+
* programming error rather than a security-sensitive path. The closure
|
|
21
|
+
* surfaces it loudly.
|
|
22
|
+
*
|
|
23
|
+
* Read-site: the closure consults a mutable reference so a
|
|
24
|
+
* `grants-updated` control frame swaps the snapshot in place without
|
|
25
|
+
* the caller having to reconstruct the closure.
|
|
26
|
+
*/
|
|
27
|
+
export type CredentialsSnapshotRef = {
|
|
28
|
+
current: CredentialsSnapshot | null;
|
|
29
|
+
};
|
|
30
|
+
/**
|
|
31
|
+
* Per-step inference-source table the build path reads through a mutable
|
|
32
|
+
* reference, keyed by stepId. Each value is the step's ordered failover
|
|
33
|
+
* chain (element 0 is the active source). The single-step build resolves
|
|
34
|
+
* its sources from `current` at build time, so a rotation that writes
|
|
35
|
+
* `current` before the first build is reflected in the built agent. A
|
|
36
|
+
* warm agent that is already built does not re-read this ref, so rotating
|
|
37
|
+
* its live sources is out of this ref's scope.
|
|
38
|
+
*/
|
|
39
|
+
export type SourcesSnapshotRef = {
|
|
40
|
+
current: Record<string, InferenceSource[]>;
|
|
41
|
+
};
|
|
42
|
+
/**
|
|
43
|
+
* Construct the workflow-level authorize closure backed by a
|
|
44
|
+
* mutable credentialsSnapshot reference.
|
|
45
|
+
*
|
|
46
|
+
* The closure looks up the step's grants by `stepId`, then delegates
|
|
47
|
+
* to the caller-supplied grant evaluator. The evaluator slot exists so
|
|
48
|
+
* the host wires its own grant-rule semantics without leaking the
|
|
49
|
+
* grant-rule grammar into the workflow-host package; tests inject a
|
|
50
|
+
* spy that records inputs.
|
|
51
|
+
*/
|
|
52
|
+
export type GrantEvaluator = (input: {
|
|
53
|
+
resource: string;
|
|
54
|
+
action: string;
|
|
55
|
+
stepId: string;
|
|
56
|
+
attempt: number | undefined;
|
|
57
|
+
runId: string | undefined;
|
|
58
|
+
grants: readonly unknown[];
|
|
59
|
+
}) => Promise<AuthzCallResult>;
|
|
60
|
+
export declare function createCredentialsBackedAuthorize(ref: CredentialsSnapshotRef, evaluate: GrantEvaluator): WorkflowAuthorizeFn;
|
|
61
|
+
/**
|
|
62
|
+
* The workflow-host child's drain controller is the production
|
|
63
|
+
* implementation defined in `../drain-controller.ts`. The control-loop
|
|
64
|
+
* calls `requestDrain()` on receipt of the supervisor's `drain`
|
|
65
|
+
* control mail; the controller flips its signal and the runtime body
|
|
66
|
+
* observes the change at its four observation points. The `behaviorFor`
|
|
67
|
+
* resolver consults the loaded `WorkflowDefinition`.
|
|
68
|
+
*/
|
|
69
|
+
export type DrainController = WorkflowHostDrainController;
|
|
70
|
+
/**
|
|
71
|
+
* Step-invoker shape the child binds. Widens the workflow-runtime
|
|
72
|
+
* `StepInvoker` with an `onEvent` callback the harness fires for
|
|
73
|
+
* every `InferenceEvent` it emits during the step's run, plus the
|
|
74
|
+
* child's credentials-backed `authorize` closure so the step agent's
|
|
75
|
+
* tool-invocation gate evaluates the per-step grants the supervisor
|
|
76
|
+
* pushed (rather than the host minting its own authorize that cannot
|
|
77
|
+
* see the live credentials snapshot). The child's `buildRuntimeEnv`
|
|
78
|
+
* constructs the per-step `onEvent` closure (wrapping the
|
|
79
|
+
* HMAC-authenticated event-channel sender) and threads both here so
|
|
80
|
+
* every event reaches the supervisor over the wire and every tool
|
|
81
|
+
* call resolves against the agent's grants. The runtime-runtime
|
|
82
|
+
* `StepInvoker` exposed via `WorkflowRuntimeEnv` remains the narrower
|
|
83
|
+
* shape -- the child wraps this binding into a `StepInvoker` inside
|
|
84
|
+
* `buildRuntimeEnv` so the workflow-runtime never sees the
|
|
85
|
+
* host-specific surface.
|
|
86
|
+
*
|
|
87
|
+
* The `warmCache` argument carries the run-loop's per-deployment
|
|
88
|
+
* warm-agent cache (design §3b) when the deployment is a warm candidate,
|
|
89
|
+
* and `undefined` otherwise. The binding forwards it to the step-invoker
|
|
90
|
+
* adapter, which builds-or-reuses the cached agent on a warm cache and
|
|
91
|
+
* keeps instantiate-send-teardown when it is absent. The cache is owned
|
|
92
|
+
* by the run-loop (`runWorkflowChild`), not the binding: the binding
|
|
93
|
+
* only reads it through to the adapter.
|
|
94
|
+
*/
|
|
95
|
+
export type ChildStepInvoker = (req: StepInvokeRequest, onEvent: (event: EventPayload) => void, authorize: WorkflowAuthorizeFn, warmCache: WarmAgentCache | undefined, sourcesRef: SourcesSnapshotRef) => Promise<StepInvokeResult>;
|
|
96
|
+
/**
|
|
97
|
+
* Bindings the binary owns: per-deployment substrate identity,
|
|
98
|
+
* principal credentials, the runtime-supplied callbacks the
|
|
99
|
+
* adapter-layer cannot construct from `process.env` alone. Tests
|
|
100
|
+
* supply a fully in-memory bindings object so `runWorkflowChild` runs
|
|
101
|
+
* without touching disk.
|
|
102
|
+
*/
|
|
103
|
+
export interface RunWorkflowChildBindings {
|
|
104
|
+
/** Workflow-run substrate (per-deployment workflow-run repo). */
|
|
105
|
+
substrate: SubstrateRepoStore;
|
|
106
|
+
/** Per-deployment workflow-run repo identity. */
|
|
107
|
+
workflowRunRepoId: RepoId;
|
|
108
|
+
/** Workflow-run repo ref the child reads/writes. */
|
|
109
|
+
workflowRunRef: string;
|
|
110
|
+
/**
|
|
111
|
+
* Substrate-shaped principal the child presents on every workflow-run
|
|
112
|
+
* read/write. Per the IPC threat model the child holds no private
|
|
113
|
+
* key of its own; the principal here is a substrate-level identity
|
|
114
|
+
* the host's substrate accepts for `runs/<runId>/` writes.
|
|
115
|
+
*/
|
|
116
|
+
principal: Principal;
|
|
117
|
+
/** Workflow-asset repo identity (used to load `workflow.json`). */
|
|
118
|
+
workflowDefinitionRepoId: RepoId;
|
|
119
|
+
/** Workflow-asset ref the deploy orchestrator wrote to. */
|
|
120
|
+
workflowDefinitionRef: string;
|
|
121
|
+
/**
|
|
122
|
+
* Step-invoker callback the runtime body invokes per step. The
|
|
123
|
+
* shape is the workflow-runtime `StepInvoker` widened with an
|
|
124
|
+
* `onEvent` slot so the harness can emit `InferenceEvent` frames
|
|
125
|
+
* up through the event channel for every step invocation. The
|
|
126
|
+
* production binary wires this against `createWorkflowStepInvoker`
|
|
127
|
+
* with the host's per-step env builder; tests inject a stub.
|
|
128
|
+
*/
|
|
129
|
+
invokeStep: ChildStepInvoker;
|
|
130
|
+
/**
|
|
131
|
+
* Child-spawn callback the runtime body invokes for `childWorkflow`
|
|
132
|
+
* primitives. The production binary wires this against
|
|
133
|
+
* `createWorkflowSpawnChild`; tests inject a stub.
|
|
134
|
+
*/
|
|
135
|
+
spawnChild: SpawnChildWorkflow;
|
|
136
|
+
/** Host-process scheduler singleton. The child consumes the same instance. */
|
|
137
|
+
scheduler: Scheduler;
|
|
138
|
+
/** Grant evaluator wired against the host's grant-rule grammar. */
|
|
139
|
+
evaluateGrants: GrantEvaluator;
|
|
140
|
+
/**
|
|
141
|
+
* Reclaim the local-disk scratch a run produced once the run has
|
|
142
|
+
* reached its terminal status. The host owns the on-disk layout
|
|
143
|
+
* (`<dataDir>/workflow-step-state/<repoId>/runs/<runId>/`), so the
|
|
144
|
+
* teardown lives next to the path construction in the substrate
|
|
145
|
+
* factory and the run-loop merely fires it at the run-completion
|
|
146
|
+
* moment it observes. Invoked ONLY on the cold (non-warm) path -- a
|
|
147
|
+
* warm deployment's single agent reuses one stable workspace across
|
|
148
|
+
* runs, so deleting per run would wipe a live conversation's files
|
|
149
|
+
* mid-stream. A cleanup failure is logged and swallowed: it is a
|
|
150
|
+
* disk-reclamation best-effort, never a correctness gate on the run's
|
|
151
|
+
* terminal status. Optional so tests and the recursive child-workflow
|
|
152
|
+
* adapter (which roots no per-run scratch of its own) can omit it.
|
|
153
|
+
*/
|
|
154
|
+
cleanupRunStorage?: (runId: string) => Promise<void>;
|
|
155
|
+
/** Optional director registry; defaults to the canonical built-ins. */
|
|
156
|
+
directors?: DirectorRegistry;
|
|
157
|
+
/** Optional clock override; production wires `() => new Date()`. */
|
|
158
|
+
clock?: () => Date;
|
|
159
|
+
/** Optional id generator override; production wires a monotonic one. */
|
|
160
|
+
newId?: (prefix: string) => string;
|
|
161
|
+
/**
|
|
162
|
+
* Optional bootstrap credentialsSnapshot. The host's production
|
|
163
|
+
* wiring supplies this for multi-step deploys whose snapshot is
|
|
164
|
+
* baked at spawn time; tests can pre-seed it directly. Absent
|
|
165
|
+
* value defers to the first `grants-updated` control frame.
|
|
166
|
+
*/
|
|
167
|
+
initialCredentialsSnapshot?: CredentialsSnapshot;
|
|
168
|
+
/**
|
|
169
|
+
* Bootstrap per-step inference-source table (keyed by stepId), parsed
|
|
170
|
+
* from the spawn env by the host's substrate factory. Seeds the
|
|
171
|
+
* mutable `sourcesRef` the build path reads. Absent value defers to an
|
|
172
|
+
* empty table, so a step with no pinned source fails loudly at build
|
|
173
|
+
* rather than resolving a default.
|
|
174
|
+
*/
|
|
175
|
+
initialSources?: Record<string, InferenceSource[]>;
|
|
176
|
+
/**
|
|
177
|
+
* Optional override for the child's Ed25519 keypair factory. The
|
|
178
|
+
* child mints a fresh keypair at startup, holds the private half
|
|
179
|
+
* in its own address space, signs every upstream control frame
|
|
180
|
+
* with it, and publishes the public half in the `ready` frame so
|
|
181
|
+
* the supervisor can verify subsequent upstream frames. Production
|
|
182
|
+
* wires this against `@intx/crypto`'s `generateKeyPair`;
|
|
183
|
+
* tests inject a deterministic factory so they can assert on the
|
|
184
|
+
* published key. The supervisor's private key is NEVER threaded
|
|
185
|
+
* into the child -- the child holds only its own private half.
|
|
186
|
+
*/
|
|
187
|
+
ipcChildKeyPairFactory?: () => Promise<{
|
|
188
|
+
privateKey: Uint8Array;
|
|
189
|
+
publicKey: Uint8Array;
|
|
190
|
+
}>;
|
|
191
|
+
}
|
|
192
|
+
export interface RunWorkflowChildOpts {
|
|
193
|
+
/** Parsed spawn-time env. */
|
|
194
|
+
env: SpawnTimeEnv;
|
|
195
|
+
/** Control-channel reader (supervisor -> child). */
|
|
196
|
+
controlReader: NdjsonReader;
|
|
197
|
+
/**
|
|
198
|
+
* Control-channel writer back to the supervisor. The child does not
|
|
199
|
+
* sign frames here today (the only upstream control frame, the
|
|
200
|
+
* `ready` signal, rides as an unsigned wire shape because the
|
|
201
|
+
* supervisor receives it on its trusted side). Future upstream
|
|
202
|
+
* frames will adopt the same envelope-and-signature contract the
|
|
203
|
+
* downstream side enforces; the writer slot exists today so the
|
|
204
|
+
* control-channel boundary is symmetric in shape.
|
|
205
|
+
*/
|
|
206
|
+
controlWriter: NdjsonWriter;
|
|
207
|
+
/**
|
|
208
|
+
* Event-channel writer (child -> supervisor). The child publishes
|
|
209
|
+
* verified `InferenceEvent` frames the harness emits up through
|
|
210
|
+
* here. Tests inject an in-memory writer; production wires the
|
|
211
|
+
* inherited socketpair fd into a FrameWriter.
|
|
212
|
+
*/
|
|
213
|
+
eventWriter: FrameWriter;
|
|
214
|
+
/** Bindings the binary or test harness owns. */
|
|
215
|
+
bindings: RunWorkflowChildBindings;
|
|
216
|
+
/**
|
|
217
|
+
* Optional pre-built upstream control sender the child uses to emit
|
|
218
|
+
* `ready` and (today) `pack.push.request` frames. Defaults to a
|
|
219
|
+
* sender minted internally against the child's own Ed25519 keypair.
|
|
220
|
+
* The process-shaped wrapper `runWorkflowChildFromProcessEnv`
|
|
221
|
+
* supplies a pre-built sender so the same Ed25519-signed surface is
|
|
222
|
+
* shared with the pack-push bridge it constructs against the
|
|
223
|
+
* substrate factory.
|
|
224
|
+
*/
|
|
225
|
+
upstreamSender?: ControlChannelSender;
|
|
226
|
+
/**
|
|
227
|
+
* Optional substrate-write bridge whose `handleMergeRequest` and
|
|
228
|
+
* `handleWriteResponse` the child's control loop invokes when the
|
|
229
|
+
* matching downstream frames land. When omitted, inbound
|
|
230
|
+
* `substrate.merge.request` / `substrate.write.response` frames are
|
|
231
|
+
* logged at warn-level and dropped -- the wire shapes are
|
|
232
|
+
* well-formed but nobody on the child side asked for them. The
|
|
233
|
+
* pre-built bridge is the path the process-shaped wrapper takes so
|
|
234
|
+
* the substrate factory's proxy `RepoStore` can resolve writes
|
|
235
|
+
* against it.
|
|
236
|
+
*/
|
|
237
|
+
substrateWriteBridge?: SubstrateWriteResponseSink;
|
|
238
|
+
/**
|
|
239
|
+
* Optional outbound-mail bridge (OUTBOUND half of mailbox ownership,
|
|
240
|
+
* §3a). The step agent's mail tools are backed by a transport whose
|
|
241
|
+
* `send` routes through this bridge: it emits an `outbound.message`
|
|
242
|
+
* upstream control frame and resolves the agent's mail-tool `send`
|
|
243
|
+
* once the supervisor's matching `outbound.result` lands. The
|
|
244
|
+
* control loop routes the downstream `outbound.result` frame to the
|
|
245
|
+
* bridge's `handleResult` and invokes `cancelAll` on any exit path so
|
|
246
|
+
* a pending send does not leak an awaiter after the supervisor tears
|
|
247
|
+
* the IPC down. When omitted, inbound `outbound.result` frames are
|
|
248
|
+
* logged at warn-level and dropped -- the wire shape is well-formed
|
|
249
|
+
* but no agent on the child side asked for an outbound send.
|
|
250
|
+
*/
|
|
251
|
+
outboundMailBridge?: ChildOutboundMailBridge;
|
|
252
|
+
}
|
|
253
|
+
/**
|
|
254
|
+
* Narrow interface the child's control loop calls when downstream
|
|
255
|
+
* substrate-write frames arrive, plus the `cancelAll` shutdown
|
|
256
|
+
* surface the loop invokes on any exit path. Decouples the loop from
|
|
257
|
+
* the bridge's `submit` side so a test can drop in a recording sink
|
|
258
|
+
* without standing up the full bridge.
|
|
259
|
+
*/
|
|
260
|
+
export interface SubstrateWriteResponseSink {
|
|
261
|
+
handleMergeRequest(data: Extract<ControlPayload, {
|
|
262
|
+
type: "substrate.merge.request";
|
|
263
|
+
}>["data"]): void;
|
|
264
|
+
handleWriteResponse(data: Extract<ControlPayload, {
|
|
265
|
+
type: "substrate.write.response";
|
|
266
|
+
}>["data"]): void;
|
|
267
|
+
cancelAll(reason: string): void;
|
|
268
|
+
}
|
|
269
|
+
/**
|
|
270
|
+
* Public result the test harness inspects. Production binaries discard
|
|
271
|
+
* the return value (the process exits when this function resolves);
|
|
272
|
+
* tests assert on the discovered-run ids and the active credentials
|
|
273
|
+
* snapshot to verify the loop's behaviour without scraping logs.
|
|
274
|
+
*/
|
|
275
|
+
export interface RunWorkflowChildResult {
|
|
276
|
+
/** RunIds the child resumed at startup. */
|
|
277
|
+
resumedRunIds: readonly string[];
|
|
278
|
+
/** RunIds the child started from `trigger.fired` after `ready`. */
|
|
279
|
+
triggeredRunIds: readonly string[];
|
|
280
|
+
/** Snapshot active at function return. */
|
|
281
|
+
finalCredentialsSnapshot: CredentialsSnapshot | null;
|
|
282
|
+
}
|
|
283
|
+
/**
|
|
284
|
+
* Run the workflow-process child. Resolves once the control channel
|
|
285
|
+
* emits `shutdown` (or ends without a frame, in which case the loop
|
|
286
|
+
* exits cleanly).
|
|
287
|
+
*/
|
|
288
|
+
export declare function runWorkflowChild(opts: RunWorkflowChildOpts): Promise<RunWorkflowChildResult>;
|
|
289
|
+
/**
|
|
290
|
+
* Mirror a run's terminal status back to the supervisor over the
|
|
291
|
+
* upstream control channel. Fired once per run from the resume and
|
|
292
|
+
* trigger.fire paths' `complete` continuation. The supervisor's
|
|
293
|
+
* per-cohort terminal broadcaster fans the event out to the dispatch
|
|
294
|
+
* loop and any armed drainTimeout accumulator subscribed for the
|
|
295
|
+
* runId.
|
|
296
|
+
*
|
|
297
|
+
* The frame mirrors the run's committed terminal event: every field --
|
|
298
|
+
* `kind`, `seq`, `at`, and (for `RunFailed`) `error.message` -- is
|
|
299
|
+
* sourced from that event, which is why the frame's `seq` matches the
|
|
300
|
+
* on-disk audit-log entry. `terminalStatus` is only the cross-check: the
|
|
301
|
+
* found event's `kind` must agree with it. A missing terminal event, or
|
|
302
|
+
* one whose kind disagrees, is a runtime producer bug (the runtime
|
|
303
|
+
* commits the terminal event last), and emitting a frame anyway would
|
|
304
|
+
* desync the supervisor from the durable log that `discoverInFlightRuns`
|
|
305
|
+
* reads on resume -- the supervisor would settle a run the on-disk log
|
|
306
|
+
* still shows in-flight. So this throws instead: no frame keeps the
|
|
307
|
+
* supervisor and the durable log agreeing that the run is unsettled, and
|
|
308
|
+
* the next recycle/restart resumes it. The throw propagates to the
|
|
309
|
+
* caller's `complete` continuation, which logs it.
|
|
310
|
+
*
|
|
311
|
+
* Errors flowing out of `upstreamSender.send` are a different case --
|
|
312
|
+
* a transport send failure, logged but not rethrown. The supervisor's
|
|
313
|
+
* dispatch loop is the authoritative settler through its cohort abort
|
|
314
|
+
* signal, so a lost frame surfaces structurally as a wedged dispatch
|
|
315
|
+
* rather than a silent lifecycle failure. The invariant throws above run
|
|
316
|
+
* before the send so that catch never swallows them.
|
|
317
|
+
*/
|
|
318
|
+
export declare function emitTerminalEvent(upstreamSender: ControlChannelSender, result: RunResult): Promise<void>;
|
|
319
|
+
/** Re-export the hash helper so callers can verify the snapshot's pin. */
|
|
320
|
+
export { hashGrants };
|