@intx/hub-sessions 0.2.2 → 0.4.0
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/README.md +3 -5
- package/dist/agent-repo.d.ts +23 -7
- package/dist/agent-repo.js +19 -6
- package/dist/agent-state-kind.js +18 -63
- package/dist/asset-service.d.ts +1 -20
- package/dist/asset-service.js +19 -97
- package/dist/committed-source-tree.d.ts +10 -0
- package/dist/committed-source-tree.js +35 -0
- package/dist/credential-push.d.ts +52 -7
- package/dist/credential-push.js +178 -22
- package/dist/event-collector-registry.d.ts +3 -2
- package/dist/event-collector-registry.js +42 -13
- package/dist/event-collector.d.ts +12 -2
- package/dist/event-collector.js +45 -4
- package/dist/hub-session-lookups.d.ts +125 -7
- package/dist/hub-session-lookups.js +541 -86
- package/dist/hub-session-orchestrator.d.ts +2 -3
- package/dist/hub-session-orchestrator.js +22 -56
- package/dist/index.d.ts +19 -9
- package/dist/index.js +16 -7
- package/dist/reconciliation-scheduler.d.ts +14 -0
- package/dist/reconciliation-scheduler.js +55 -0
- package/dist/repo-store/index.d.ts +2 -1
- package/dist/repo-store/index.js +1 -0
- package/dist/repo-store/store.d.ts +1 -1
- package/dist/repo-store/store.js +138 -1
- package/dist/repo-store/subscribe-kind.d.ts +6 -3
- package/dist/repo-store/subscribe-kind.js +42 -77
- package/dist/repo-store/types.d.ts +94 -6
- package/dist/repo-store/user-principal-gate.d.ts +26 -0
- package/dist/repo-store/user-principal-gate.js +78 -0
- package/dist/session-service.d.ts +252 -126
- package/dist/session-service.js +851 -624
- package/dist/sidecar-allocation/capability-policy.d.ts +27 -0
- package/dist/sidecar-allocation/capability-policy.js +124 -0
- package/dist/sidecar-allocation/contracts.d.ts +101 -0
- package/dist/sidecar-allocation/contracts.js +26 -0
- package/dist/sidecar-allocation/index.d.ts +5 -0
- package/dist/sidecar-allocation/index.js +4 -0
- package/dist/sidecar-allocation/operation.d.ts +10 -0
- package/dist/sidecar-allocation/operation.js +54 -0
- package/dist/sidecar-allocation/plugin-registry.d.ts +24 -0
- package/dist/sidecar-allocation/plugin-registry.js +61 -0
- package/dist/sidecar-allocation/reconciler.d.ts +54 -0
- package/dist/sidecar-allocation/reconciler.js +825 -0
- package/dist/skill-kind.js +12 -62
- package/dist/substrate.d.ts +3 -3
- package/dist/substrate.js +1 -1
- package/dist/workflow-allocation-service.d.ts +64 -0
- package/dist/workflow-allocation-service.js +554 -0
- package/dist/workflow-closure-resolution.d.ts +106 -0
- package/dist/workflow-closure-resolution.js +123 -0
- package/dist/workflow-definition-ensure.d.ts +24 -0
- package/dist/workflow-definition-ensure.js +75 -0
- package/dist/workflow-dispatch-service.d.ts +42 -0
- package/dist/workflow-dispatch-service.js +209 -0
- package/dist/workflow-dispatch-settlement.d.ts +29 -0
- package/dist/workflow-dispatch-settlement.js +140 -0
- package/dist/workflow-kind.d.ts +29 -1
- package/dist/workflow-kind.js +143 -139
- package/dist/workflow-probe-gate.d.ts +286 -0
- package/dist/workflow-probe-gate.js +382 -0
- package/dist/workflow-run-kind.d.ts +239 -32
- package/dist/workflow-run-kind.js +874 -188
- package/dist/workflow-run-reader.d.ts +1 -1
- package/dist/workflow-run-reader.js +3 -7
- package/dist/workflow-run-restore.d.ts +16 -0
- package/dist/workflow-run-restore.js +30 -0
- package/dist/workflow-source-closure.d.ts +35 -0
- package/dist/workflow-source-closure.js +342 -0
- package/dist/workflow-source-pins.d.ts +8 -0
- package/dist/workflow-source-pins.js +14 -0
- package/dist/ws/index.d.ts +3 -3
- package/dist/ws/index.js +2 -2
- package/dist/ws/pending-tracker.d.ts +93 -0
- package/dist/ws/pending-tracker.js +132 -0
- package/dist/ws/sidecar-events.d.ts +139 -37
- package/dist/ws/sidecar-events.js +2 -2
- package/dist/ws/sidecar-handler.d.ts +218 -60
- package/dist/ws/sidecar-handler.js +1713 -732
- package/dist/ws/sidecar-handler.test-helpers.d.ts +38 -0
- package/dist/ws/sidecar-handler.test-helpers.js +95 -0
- package/dist/ws/sidecar-token-authenticator.d.ts +3 -1
- package/dist/ws/sidecar-token-authenticator.js +78 -7
- package/package.json +14 -13
- package/dist/available-skills-stanza.d.ts +0 -21
- package/dist/available-skills-stanza.js +0 -32
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { type AuthorizeFn, type KindHandler, type Principal, type RepoId, type RepoStore } from "./repo-store/index.js";
|
|
1
|
+
import { type AuthorizeFn, type CommittedReads, type KindHandler, type Principal, type RepoId, type RepoStore } from "./repo-store/index.js";
|
|
2
2
|
export type WorkflowRunHubPrincipal = {
|
|
3
3
|
readonly kind: "hub";
|
|
4
4
|
};
|
|
@@ -8,23 +8,38 @@ export type WorkflowRunSidecarPrincipal = {
|
|
|
8
8
|
};
|
|
9
9
|
export type WorkflowRunWorkflowProcessPrincipal = {
|
|
10
10
|
readonly kind: "workflow-process";
|
|
11
|
-
readonly
|
|
11
|
+
readonly anchorRunId: string;
|
|
12
12
|
readonly runId?: string;
|
|
13
13
|
};
|
|
14
14
|
export type WorkflowRunSupervisorPrincipal = {
|
|
15
15
|
readonly kind: "supervisor";
|
|
16
|
-
readonly
|
|
16
|
+
readonly anchorRunId: string;
|
|
17
17
|
};
|
|
18
18
|
export type WorkflowRunPrincipal = WorkflowRunHubPrincipal | WorkflowRunSidecarPrincipal | WorkflowRunWorkflowProcessPrincipal | WorkflowRunSupervisorPrincipal;
|
|
19
19
|
export declare const WORKFLOW_RUN_GITIGNORE_PATH = ".gitignore";
|
|
20
20
|
export declare const WORKFLOW_RUN_RUNS_PREFIX = "runs";
|
|
21
21
|
export declare const WORKFLOW_RUN_EVENTS_DIR = "events";
|
|
22
22
|
export declare const WORKFLOW_RUN_BLOBS_DIR = "blobs";
|
|
23
|
+
export declare const WORKFLOW_RUN_GRANTS_FILE = "grants.json";
|
|
23
24
|
export declare const WORKFLOW_RUN_ADDRESSES_PREFIX = "addresses";
|
|
24
25
|
export declare const WORKFLOW_RUN_CONTROL_PREFIX = "control";
|
|
25
26
|
export declare const WORKFLOW_RUN_INBOX_DIR = "inbox";
|
|
26
27
|
export declare const WORKFLOW_RUN_PROCESSING_DIR = "processing";
|
|
27
28
|
export declare const WORKFLOW_RUN_CONSUMED_DIR = "consumed";
|
|
29
|
+
/**
|
|
30
|
+
* Per-run inbound mail-part subtree. Non-text inbound mail content
|
|
31
|
+
* (image/audio/video/document mail parts) is committed here as real
|
|
32
|
+
* files rather than inlined into the JSON event log, whose serialization
|
|
33
|
+
* boundary would corrupt binary bytes. The layout is
|
|
34
|
+
* `runs/<runId>/parts/<urlEncoded(messageId)>/<index>-<name>`: one
|
|
35
|
+
* directory per inbound message (so a long-lived run's successive turns
|
|
36
|
+
* never collide), and one file per mail part carrying its verbatim
|
|
37
|
+
* bytes. The workflow-host ingest writes the bytes and records a
|
|
38
|
+
* lightweight `{ name, contentType, ref }` reference into the run's
|
|
39
|
+
* trigger / signal payload; the step invoker reads the bytes back at
|
|
40
|
+
* `agent.send` time. Files are immutable once written, like `blobs/`.
|
|
41
|
+
*/
|
|
42
|
+
export declare const WORKFLOW_RUN_PARTS_DIR = "parts";
|
|
28
43
|
/**
|
|
29
44
|
* Filename of the per-address retention watermark blob, a direct child
|
|
30
45
|
* of `addresses/<urlEncoded>/` (a file, not a directory). Carries the
|
|
@@ -42,15 +57,28 @@ export declare const WORKFLOW_RUN_WATERMARK_FILE = "watermark.json";
|
|
|
42
57
|
* deduped by a retained consumed entry, short enough that `consumed/`
|
|
43
58
|
* reaches a bounded steady state of one day's message volume.
|
|
44
59
|
*
|
|
45
|
-
* INVARIANT (operator-owned): the horizon must be >= the longest
|
|
46
|
-
*
|
|
47
|
-
*
|
|
48
|
-
*
|
|
49
|
-
* the
|
|
50
|
-
*
|
|
51
|
-
*
|
|
52
|
-
* re-
|
|
53
|
-
*
|
|
60
|
+
* INVARIANT (operator-owned): the horizon must be >= the longest window in
|
|
61
|
+
* which the same `messageId` could legitimately be re-submitted and still must
|
|
62
|
+
* be caught as a duplicate. The hub now redelivers un-acked inbound mail
|
|
63
|
+
* (connected-window retry and reconnect-redelivery), so an at-least-once
|
|
64
|
+
* internal source DOES exist -- but the dedup guarantee against it does not
|
|
65
|
+
* rest on window arithmetic. It rests on a STRUCTURAL fact: `enqueueInbox` is
|
|
66
|
+
* only ever called with a freshly stamped `receivedAt` (a redelivery
|
|
67
|
+
* re-enters `onMailMessage` and re-stamps `Date.now()`, never carrying the
|
|
68
|
+
* original), and the watermark only ever advances to at most
|
|
69
|
+
* `consumedAt - retentionHorizonMs`, which is <= now, so a fresh `receivedAt`
|
|
70
|
+
* always sits a full horizon above the watermark and can never be stale-
|
|
71
|
+
* refused. A redelivery instead hits the `consumed/`/`processing/`/`inbox/`
|
|
72
|
+
* dedup index and is deduped there. The sole path that carries an original
|
|
73
|
+
* (old) `receivedAt` back into the queue is `replayProcessingToInbox`, which
|
|
74
|
+
* writes straight to `inbox/` and bypasses the stale gate entirely. So
|
|
75
|
+
* `claim_check_stale_enqueue` is unreachable via redelivery today. If any
|
|
76
|
+
* redelivery source is ever changed to carry the ORIGINAL `receivedAt` into
|
|
77
|
+
* `enqueueInbox`, stale becomes reachable, the horizon must then be >= that
|
|
78
|
+
* source's maximum redelivery window, and `StaleInboxEnqueueError`'s
|
|
79
|
+
* withhold-not-ack handling becomes load-bearing; a breach surfaces LOUDLY (an
|
|
80
|
+
* old-`receivedAt` re-submission is refused at enqueue) rather than as silent
|
|
81
|
+
* double-processing.
|
|
54
82
|
*/
|
|
55
83
|
export declare const DEFAULT_CONSUMED_RETENTION_MS: number;
|
|
56
84
|
/**
|
|
@@ -68,6 +96,69 @@ export declare const DEFAULT_CONSUMED_RETENTION_MS: number;
|
|
|
68
96
|
* `<agentKey>` directory layer below the prefix).
|
|
69
97
|
*/
|
|
70
98
|
export declare const WORKFLOW_RUN_AGENT_STATE_PREFIX = "agent-state";
|
|
99
|
+
/**
|
|
100
|
+
* Conversational-mailbox subtree for the warm single-step agent. The
|
|
101
|
+
* substrate mailbox backing commits the agent's durable inbox under
|
|
102
|
+
* `mailbox/INBOX/` so the full message history replicates to the hub
|
|
103
|
+
* alongside the run state. The layout is:
|
|
104
|
+
*
|
|
105
|
+
* - `mailbox/INBOX/index.json` — the mailbox index. MUTABLE: the
|
|
106
|
+
* backing rewrites it on every flush, so it is exempt from the
|
|
107
|
+
* retained-blob byte-equality walk the `<uid>.eml` blobs are subject
|
|
108
|
+
* to. It must nonetheless PERSIST once it existed: dropping it drops
|
|
109
|
+
* the whole mailbox and resets uidValidity/uidNext on the next open.
|
|
110
|
+
* - `mailbox/INBOX/<uid>.eml` — one message per file, carrying the
|
|
111
|
+
* raw signed message bytes. `<uid>` is a decimal integer >= 1. A
|
|
112
|
+
* RETAINED `<uid>.eml` (present in both prior and prospective) is
|
|
113
|
+
* opaque and IMMUTABLE: it must reappear byte-identically, exactly
|
|
114
|
+
* like `runs/<runId>/blobs/`. A prior `<uid>.eml` may be ABSENT from
|
|
115
|
+
* the prospective tree — that is the warm agent expunging a message.
|
|
116
|
+
* The raw bytes are not lost: they stay reachable through the parent
|
|
117
|
+
* commit, and a `workflow-run` repo's objects are never GC'd (its
|
|
118
|
+
* kind is off the GC allow-list), so an expunged message survives in
|
|
119
|
+
* history for the life of the run repo. The audit trail rests on
|
|
120
|
+
* "these objects are never pruned", not on the live tree being
|
|
121
|
+
* monotonic.
|
|
122
|
+
*
|
|
123
|
+
* The only entries permitted under `mailbox/` are the `INBOX/`
|
|
124
|
+
* directory; the only entries permitted under `mailbox/INBOX/` are
|
|
125
|
+
* `index.json` and `<uid>.eml` message files. Anything else fails the
|
|
126
|
+
* push.
|
|
127
|
+
*/
|
|
128
|
+
export declare const WORKFLOW_RUN_MAILBOX_PREFIX = "mailbox";
|
|
129
|
+
export declare const WORKFLOW_RUN_MAILBOX_INBOX_DIR = "INBOX";
|
|
130
|
+
export declare const WORKFLOW_RUN_MAILBOX_INDEX_FILE = "index.json";
|
|
131
|
+
/**
|
|
132
|
+
* Parse the seq from a per-event log filename `<seq>.json` under
|
|
133
|
+
* `runs/<runId>/events/`. Returns the non-negative integer seq, or
|
|
134
|
+
* `null` when the name is not a legal per-event filename. This is the
|
|
135
|
+
* one place the filename shape is defined; every reader of the event log
|
|
136
|
+
* narrows names through it rather than re-encoding the regex. Callers
|
|
137
|
+
* decide what an illegal name means -- a foreign entry to skip, or a
|
|
138
|
+
* substrate-invariant violation to surface -- since `validatePush` is
|
|
139
|
+
* the authority that keeps illegal names from landing in the first place.
|
|
140
|
+
*/
|
|
141
|
+
export declare function parseEventSeq(filename: string): number | null;
|
|
142
|
+
/**
|
|
143
|
+
* Narrow a per-event filename to its seq, throwing when it is illegal.
|
|
144
|
+
* A reader that enumerates the committed event log to act on its entries
|
|
145
|
+
* uses this rather than `parseEventSeq`: `validatePush` is the authority
|
|
146
|
+
* that keeps an illegal name from ever landing under
|
|
147
|
+
* `runs/<runId>/events/`, so a name that reaches a reader is corruption,
|
|
148
|
+
* and silently skipping it would drop an event from processing. `context`
|
|
149
|
+
* is the repo-root-relative blob path, surfaced in the error so the
|
|
150
|
+
* offending entry is identifiable.
|
|
151
|
+
*/
|
|
152
|
+
export declare function requireEventSeq(filename: string, context: string): number;
|
|
153
|
+
/**
|
|
154
|
+
* Maximum byte length of a single mail part path component (the
|
|
155
|
+
* URL-encoded message segment, and each `<index>-<name>` filename).
|
|
156
|
+
* messageIds and mail part names arrive from untrusted inbound mail;
|
|
157
|
+
* an over-long RFC 5322 message-id URL-encodes past the filesystem's
|
|
158
|
+
* 255-byte component limit and would otherwise fail at disk-write time,
|
|
159
|
+
* downstream of validation. Reject it at the boundary instead.
|
|
160
|
+
*/
|
|
161
|
+
export declare const MAX_MAIL_PART_PATH_COMPONENT_BYTES = 255;
|
|
71
162
|
/**
|
|
72
163
|
* JSON envelope carried by inbox and processing entries. Keys:
|
|
73
164
|
* - `messageId`: dedup key for the inbound message.
|
|
@@ -115,6 +206,10 @@ declare const ConsumedEnvelope: import("arktype/internal/variants/object.ts").Ob
|
|
|
115
206
|
store: string;
|
|
116
207
|
path: string;
|
|
117
208
|
};
|
|
209
|
+
rejection?: {
|
|
210
|
+
code: string;
|
|
211
|
+
message: string;
|
|
212
|
+
};
|
|
118
213
|
}, {}>;
|
|
119
214
|
/**
|
|
120
215
|
* JSON envelope carried by the per-address `watermark.json` blob. The
|
|
@@ -129,6 +224,35 @@ declare const WatermarkEnvelope: import("arktype/internal/variants/object.ts").O
|
|
|
129
224
|
export type ClaimCheckEnvelope = typeof ClaimCheckEnvelope.infer;
|
|
130
225
|
export type ConsumedEnvelope = typeof ConsumedEnvelope.infer;
|
|
131
226
|
export type WatermarkEnvelope = typeof WatermarkEnvelope.infer;
|
|
227
|
+
/**
|
|
228
|
+
* Terminal event discriminators mapped to the `workflow_run.status` value
|
|
229
|
+
* each settles the run into. A run whose log contains an entry with one of
|
|
230
|
+
* these `type` values must not receive any event with a strictly greater
|
|
231
|
+
* seq.
|
|
232
|
+
*
|
|
233
|
+
* This map is a hand-rolled copy of the runtime's terminal-run vocabulary
|
|
234
|
+
* (`isTerminalRunPhase` in `@intx/workflow` state-machine `state.ts`,
|
|
235
|
+
* re-exported from the state-machine index and consumed by `transition.ts`),
|
|
236
|
+
* duplicated here because `@intx/hub-sessions` must not depend on
|
|
237
|
+
* `@intx/workflow`. It is the sole authority for that vocabulary and MUST
|
|
238
|
+
* stay in sync with the canonical runtime definition:
|
|
239
|
+
* if the runtime adds or removes a terminal run phase, update this map too.
|
|
240
|
+
* Drift silently reopens the restore-time double-driver collision that
|
|
241
|
+
* `scanRunsForBoot` (below) exists to prevent.
|
|
242
|
+
*/
|
|
243
|
+
type TerminalRunStatus = "completed" | "failed" | "cancelled";
|
|
244
|
+
/**
|
|
245
|
+
* Classify a workflow-run event type against the terminal-status vocabulary.
|
|
246
|
+
* `TERMINAL_EVENT_STATUS` is the sole authority (see above), so a type absent
|
|
247
|
+
* from it is by definition not terminal: no separate membership set is
|
|
248
|
+
* consulted and no "unmapped terminal type" case can arise.
|
|
249
|
+
*/
|
|
250
|
+
export declare function classifyTerminalEvent(eventType: string): {
|
|
251
|
+
terminal: true;
|
|
252
|
+
status: TerminalRunStatus;
|
|
253
|
+
} | {
|
|
254
|
+
terminal: false;
|
|
255
|
+
};
|
|
132
256
|
export declare const workflowRunKindHandler: KindHandler;
|
|
133
257
|
export declare const workflowRunAuthorize: AuthorizeFn;
|
|
134
258
|
export type EnqueueInboxArgs = {
|
|
@@ -153,6 +277,54 @@ export type EnqueueInboxResult = {
|
|
|
153
277
|
inboxKey: string;
|
|
154
278
|
envelope: ClaimCheckEnvelope;
|
|
155
279
|
};
|
|
280
|
+
/**
|
|
281
|
+
* Which already-present state an `enqueueInbox` call found the messageId
|
|
282
|
+
* in. Every value is POSITIVE evidence the message's bytes are durably on
|
|
283
|
+
* disk (inbox/processing) or were already consumed -- so a caller gating a
|
|
284
|
+
* receipt on the enqueue may safely acknowledge on any of them.
|
|
285
|
+
*/
|
|
286
|
+
export type EnqueueAlreadyPresentReason = "duplicate" | "already_inbox" | "processing" | "consumed";
|
|
287
|
+
/**
|
|
288
|
+
* Outcome of an `enqueueInbox` call. Modeled as a value (not an exception)
|
|
289
|
+
* precisely because the return/throw boundary is the ack/withhold boundary
|
|
290
|
+
* for a caller gating a durable-receipt ack: a returned outcome is safe to
|
|
291
|
+
* acknowledge (the bytes are on disk -- freshly written or already present),
|
|
292
|
+
* a throw is not (the write could not complete or its disposition cannot be
|
|
293
|
+
* decided). `enqueued` is the only outcome that added a new inbox entry, so
|
|
294
|
+
* it is the only one a dispatch-driving caller wakes its loop on.
|
|
295
|
+
*/
|
|
296
|
+
export type EnqueueInboxOutcome = ({
|
|
297
|
+
outcome: "enqueued";
|
|
298
|
+
} & EnqueueInboxResult) | {
|
|
299
|
+
outcome: "already-present";
|
|
300
|
+
reason: EnqueueAlreadyPresentReason;
|
|
301
|
+
};
|
|
302
|
+
/**
|
|
303
|
+
* Thrown by `enqueueInbox` when the inbound's `receivedAt` is strictly below
|
|
304
|
+
* the address's retention watermark. This is refusal under UNCERTAINTY, not
|
|
305
|
+
* proof of prior receipt: the consumed dedup entry that would rule out a
|
|
306
|
+
* duplicate may have been pruned, so the substrate can no longer tell a
|
|
307
|
+
* duplicate from a never-processed message and refuses rather than risk
|
|
308
|
+
* reprocessing. A caller gating a durable-receipt ack MUST NOT acknowledge on
|
|
309
|
+
* this -- acking an "I cannot tell" would terminally drop a message that was
|
|
310
|
+
* never written. It is its own type (not a generic Error) so that a caller,
|
|
311
|
+
* and monitoring, can surface it as a distinct loud signal rather than
|
|
312
|
+
* blending it into ordinary I/O-failure noise.
|
|
313
|
+
*
|
|
314
|
+
* Structurally unreachable on the mail-inbound path today: `enqueueInbox` is
|
|
315
|
+
* only ever called with a freshly stamped `receivedAt` (a redelivery
|
|
316
|
+
* re-stamps `Date.now()` rather than carrying the original), and the watermark
|
|
317
|
+
* only ever advances to at most `consumedAt - retentionHorizonMs <= now`, so a
|
|
318
|
+
* fresh `receivedAt` sits a full horizon above it. The sole path that carries
|
|
319
|
+
* an original (old) `receivedAt` back into the queue is
|
|
320
|
+
* `replayProcessingToInbox`, which writes straight to `inbox/` and bypasses
|
|
321
|
+
* this gate entirely. If any redelivery source is ever changed to carry the
|
|
322
|
+
* original `receivedAt` into `enqueueInbox`, this becomes reachable and its
|
|
323
|
+
* withhold-not-ack handling becomes load-bearing.
|
|
324
|
+
*/
|
|
325
|
+
export declare class StaleInboxEnqueueError extends Error {
|
|
326
|
+
constructor(message: string);
|
|
327
|
+
}
|
|
156
328
|
/**
|
|
157
329
|
* Append a new inbox entry for `address`. The merge callback reads
|
|
158
330
|
* the address subtree under the per-repo lock, augments the inbox
|
|
@@ -166,7 +338,7 @@ export type EnqueueInboxResult = {
|
|
|
166
338
|
* invariant here also catches the concurrent-enqueue race that the
|
|
167
339
|
* per-repo lock alone cannot surface.
|
|
168
340
|
*/
|
|
169
|
-
export declare function enqueueInbox(store: RepoStore, principal: Principal, repoId: RepoId, args: EnqueueInboxArgs): Promise<
|
|
341
|
+
export declare function enqueueInbox(store: RepoStore, principal: Principal, repoId: RepoId, args: EnqueueInboxArgs): Promise<EnqueueInboxOutcome>;
|
|
170
342
|
export type DequeueToProcessingResult = {
|
|
171
343
|
commitSha: string;
|
|
172
344
|
key: string;
|
|
@@ -208,7 +380,7 @@ export type ReadProcessingEntryResult = {
|
|
|
208
380
|
* committed -- which is exactly when the supervisor forwards
|
|
209
381
|
* `trigger.fired` -- observes the processing entry. Reading the working tree (rather than walking the
|
|
210
382
|
* committed git tree) matches the workflow-process child's sibling
|
|
211
|
-
*
|
|
383
|
+
* read of `runs/<runId>/events/`. Because the
|
|
212
384
|
* read issues no commit it cannot race the supervisor's `markConsumed`
|
|
213
385
|
* write; it returns a point-in-time snapshot of the directory.
|
|
214
386
|
*/
|
|
@@ -218,6 +390,16 @@ export type MarkConsumedArgs = {
|
|
|
218
390
|
messageId: string;
|
|
219
391
|
runId: string;
|
|
220
392
|
consumedAt: number;
|
|
393
|
+
/**
|
|
394
|
+
* Present when the supervisor deliberately refused the message instead of
|
|
395
|
+
* delivering it to the run. The consumed entry remains the durable dedup
|
|
396
|
+
* record, while Hub projection uses this detail to fail (rather than settle)
|
|
397
|
+
* an allocation-dispatch row.
|
|
398
|
+
*/
|
|
399
|
+
rejection?: {
|
|
400
|
+
code: string;
|
|
401
|
+
message: string;
|
|
402
|
+
};
|
|
221
403
|
/**
|
|
222
404
|
* Retention horizon for the consumed dedup index, in milliseconds.
|
|
223
405
|
* The commit advances the per-address watermark to
|
|
@@ -263,27 +445,52 @@ export type ReplayProcessingToInboxResult = {
|
|
|
263
445
|
commitSha: string;
|
|
264
446
|
replayedKeys: string[];
|
|
265
447
|
};
|
|
448
|
+
export type ScanRunsForBootResult = {
|
|
449
|
+
ownedMessageIds: Set<string>;
|
|
450
|
+
pendingSealRunIds: string[];
|
|
451
|
+
};
|
|
452
|
+
/**
|
|
453
|
+
* Walk `runs/` once and return the two boot-recovery inputs the supervisor's
|
|
454
|
+
* spawn needs, from a single traversal of the working tree via `getRepoDir`:
|
|
455
|
+
*
|
|
456
|
+
* - `ownedMessageIds`: the `consumedMessageId`s of NON-terminal runs -- the
|
|
457
|
+
* messages a live run still owns. Spawn feeds this into
|
|
458
|
+
* `replayProcessingToInbox`'s `ownedMessageIds` so a parked run's message is
|
|
459
|
+
* not re-admitted to inbox and dispatched a second time while the run is
|
|
460
|
+
* recovered by re-driving its durable log. Without this, the re-drive AND the
|
|
461
|
+
* re-triggered fresh run both re-park the same awaitSignal gate on the same
|
|
462
|
+
* runId, and the two concurrent runtime bodies race to a corrupt terminal.
|
|
463
|
+
* - `pendingSealRunIds`: runs that are terminal but still in per-event form --
|
|
464
|
+
* an interrupted fold left them unsealed. Spawn hands these to the recovery
|
|
465
|
+
* sweep, which re-runs the idempotent fold. A terminal event is a *proposal*:
|
|
466
|
+
* the authoritative decision is `compactRunEvents`, which independently
|
|
467
|
+
* re-checks the run's max-seq event and no-ops a run that is not actually
|
|
468
|
+
* terminal, so this scan may be loose.
|
|
469
|
+
*
|
|
470
|
+
* The working tree tracks the run-event ref (`refs/heads/main`); the
|
|
471
|
+
* claim-check ref (`refs/heads/events`) cannot see it, which is why this lives
|
|
472
|
+
* at the caller rather than inside `replayProcessingToInbox`'s single-ref
|
|
473
|
+
* delta. A run whose log is sealed (combined `events.jsonl`, only permitted for
|
|
474
|
+
* a terminated run) contributes to neither set; an absent `runs/` directory
|
|
475
|
+
* yields empty results.
|
|
476
|
+
*/
|
|
477
|
+
export declare function scanRunsForBoot(store: RepoStore, repoId: RepoId): Promise<ScanRunsForBootResult>;
|
|
478
|
+
export type WorkflowRunLifecycle = "absent" | "live" | "terminal";
|
|
479
|
+
/** Read one run's lifecycle from a committed workflow-run tree. */
|
|
480
|
+
export declare function readCommittedWorkflowRunLifecycle(reads: CommittedReads | null, runId: string): Promise<WorkflowRunLifecycle>;
|
|
266
481
|
/**
|
|
267
|
-
* Read the
|
|
268
|
-
* `
|
|
269
|
-
*
|
|
270
|
-
*
|
|
271
|
-
*
|
|
272
|
-
* second time while the run is recovered by re-driving its durable log.
|
|
273
|
-
* Without this, the re-drive AND the re-triggered fresh run both re-park
|
|
274
|
-
* the same awaitSignal gate on the same runId, and the two concurrent
|
|
275
|
-
* runtime bodies race to a corrupt terminal.
|
|
482
|
+
* Read the durable lifecycle of one run from the workflow-run working tree.
|
|
483
|
+
* `grants.json` alone is still an absent run: grants are staged before the
|
|
484
|
+
* first trigger, while the first event is the durable proof that the run was
|
|
485
|
+
* fired. A sealed event log is terminal by the kind handler's compaction
|
|
486
|
+
* invariant.
|
|
276
487
|
*
|
|
277
|
-
*
|
|
278
|
-
*
|
|
279
|
-
*
|
|
280
|
-
*
|
|
281
|
-
* `replayProcessingToInbox`'s single-ref delta. A run whose log is sealed
|
|
282
|
-
* (combined `events.json`, only permitted for a terminated run) or
|
|
283
|
-
* carries a terminal event is excluded; an absent `runs/` directory
|
|
284
|
-
* yields an empty set.
|
|
488
|
+
* The supervisor uses this when in-memory cohort membership is empty. That
|
|
489
|
+
* happens both for a genuinely new deployment and briefly during recovery,
|
|
490
|
+
* so treating both states as "fire" would start a second driver for a live
|
|
491
|
+
* log or reuse a terminal run.
|
|
285
492
|
*/
|
|
286
|
-
export declare function
|
|
493
|
+
export declare function readWorkflowRunLifecycle(store: RepoStore, repoId: RepoId, runId: string): Promise<WorkflowRunLifecycle>;
|
|
287
494
|
export type ReplayProcessingToInboxOpts = {
|
|
288
495
|
/**
|
|
289
496
|
* MessageIds whose run is still LIVE (non-terminal) and therefore owns
|