@orkestrel/workflow 0.0.16 → 0.0.17
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 -3
- package/dist/src/browser/index.d.ts +41 -44
- package/dist/src/browser/index.js +46 -67
- package/dist/src/browser/index.js.map +1 -1
- package/dist/src/core/index.cjs +1160 -674
- package/dist/src/core/index.cjs.map +1 -1
- package/dist/src/core/index.d.cts +1464 -1030
- package/dist/src/core/index.d.ts +1464 -1030
- package/dist/src/core/index.js +1145 -666
- package/dist/src/core/index.js.map +1 -1
- package/dist/src/server/index.cjs +12 -19
- package/dist/src/server/index.cjs.map +1 -1
- package/dist/src/server/index.d.cts +11 -12
- package/dist/src/server/index.d.ts +11 -12
- package/dist/src/server/index.js +13 -20
- package/dist/src/server/index.js.map +1 -1
- package/package.json +16 -16
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import { AbortInterface } from '@orkestrel/abort';
|
|
2
1
|
import { ArrayShape } from '@orkestrel/contract';
|
|
3
2
|
import { BudgetInterface } from '@orkestrel/budget';
|
|
4
3
|
import { ContractInterface } from '@orkestrel/contract';
|
|
@@ -7,6 +6,7 @@ import { EmitterErrorHandler } from '@orkestrel/emitter';
|
|
|
7
6
|
import { EmitterHooks } from '@orkestrel/emitter';
|
|
8
7
|
import { EmitterInterface } from '@orkestrel/emitter';
|
|
9
8
|
import { Failure } from '@orkestrel/contract';
|
|
9
|
+
import { Guard } from '@orkestrel/contract';
|
|
10
10
|
import { JSONRecord } from '@orkestrel/contract';
|
|
11
11
|
import { JSONValue } from '@orkestrel/contract';
|
|
12
12
|
import { LiteralShape } from '@orkestrel/contract';
|
|
@@ -20,7 +20,22 @@ import { TableInterface } from '@orkestrel/database';
|
|
|
20
20
|
import { TokenUsage } from '@orkestrel/budget';
|
|
21
21
|
|
|
22
22
|
/**
|
|
23
|
-
*
|
|
23
|
+
* Names how one task attempt left the race between its handler and its cancellation.
|
|
24
|
+
*
|
|
25
|
+
* @remarks
|
|
26
|
+
* The engine races a dispatched {@link WorkflowFunction} against the attempt's folded signal, so
|
|
27
|
+
* the attempt either SETTLED with the handler's JSON value or did not settle at all. A tuple, not
|
|
28
|
+
* a {@link Result}: the unsettled branch is a cancellation rather than an error, so there is no
|
|
29
|
+
* error to carry, and `genuine` records what the cancellation was — `true` for a genuine cancel
|
|
30
|
+
* (a run-level bound, a task `stop` / `skip`, or a sibling fail-fast, all of which skip the leaf),
|
|
31
|
+
* `false` for a bare per-attempt timeout (a retryable failure of this attempt), and `undefined`
|
|
32
|
+
* when the caller must re-read the discriminator itself. The engine reads the tuple positionally
|
|
33
|
+
* at each of its own settlement points; it never crosses the published surface.
|
|
34
|
+
*/
|
|
35
|
+
export declare type AttemptOutcome = readonly [settled: true, value: JSONValue] | readonly [settled: false, value: undefined, genuine?: boolean];
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* Builds a {@link PhaseContext} — a phase's own identity plus a back-reference to its
|
|
24
39
|
* workflow — from the parent {@link WorkflowContext} and the phase node's identity.
|
|
25
40
|
*
|
|
26
41
|
* @param workflow - The parent workflow context (the lineage pointer UP the tree)
|
|
@@ -30,7 +45,7 @@ import { TokenUsage } from '@orkestrel/budget';
|
|
|
30
45
|
export declare function buildPhaseContext(workflow: WorkflowContext, node: WorkflowContext): PhaseContext;
|
|
31
46
|
|
|
32
47
|
/**
|
|
33
|
-
*
|
|
48
|
+
* Builds a {@link TaskContext} — a task's own identity plus a back-reference to its phase
|
|
34
49
|
* (and, transitively, its workflow) — from the parent {@link PhaseContext} and the task
|
|
35
50
|
* node's identity.
|
|
36
51
|
*
|
|
@@ -41,7 +56,7 @@ export declare function buildPhaseContext(workflow: WorkflowContext, node: Workf
|
|
|
41
56
|
export declare function buildTaskContext(phase: PhaseContext, node: WorkflowContext): TaskContext;
|
|
42
57
|
|
|
43
58
|
/**
|
|
44
|
-
*
|
|
59
|
+
* Builds a {@link WorkflowContext} — the identity every level inherits — from a node's
|
|
45
60
|
* `id` / `name` / optional `description`.
|
|
46
61
|
*
|
|
47
62
|
* @remarks
|
|
@@ -55,8 +70,8 @@ export declare function buildTaskContext(phase: PhaseContext, node: WorkflowCont
|
|
|
55
70
|
export declare function buildWorkflowContext(node: WorkflowContext): WorkflowContext;
|
|
56
71
|
|
|
57
72
|
/**
|
|
58
|
-
*
|
|
59
|
-
* {@link
|
|
73
|
+
* Tests whether the live W-b task state machine may move directly from one
|
|
74
|
+
* {@link LifecycleStatus} to another — the legal-transition guard.
|
|
60
75
|
*
|
|
61
76
|
* @remarks
|
|
62
77
|
* Reads the {@link import('./constants.js').TASK_TRANSITIONS} graph: `true` only when
|
|
@@ -66,12 +81,12 @@ export declare function buildWorkflowContext(node: WorkflowContext): WorkflowCon
|
|
|
66
81
|
*
|
|
67
82
|
* @param from - The task's current status
|
|
68
83
|
* @param to - The status the transition would move it to
|
|
69
|
-
* @returns
|
|
84
|
+
* @returns True if the move is legal; false otherwise
|
|
70
85
|
*/
|
|
71
|
-
export declare function canTransitionTask(from:
|
|
86
|
+
export declare function canTransitionTask(from: LifecycleStatus, to: LifecycleStatus): boolean;
|
|
72
87
|
|
|
73
88
|
/**
|
|
74
|
-
*
|
|
89
|
+
* Captures every top-level {@link WorkflowOptions} value exactly once into an owned plain bag.
|
|
75
90
|
*
|
|
76
91
|
* @remarks
|
|
77
92
|
* Direct property reads preserve inherited and non-enumerable option values while preventing
|
|
@@ -92,7 +107,7 @@ export declare function canTransitionTask(from: TaskStatus, to: TaskStatus): boo
|
|
|
92
107
|
export declare function captureWorkflowOptions(options?: WorkflowOptions): WorkflowOptions;
|
|
93
108
|
|
|
94
109
|
/**
|
|
95
|
-
*
|
|
110
|
+
* Validates and clones one complete task activity frame.
|
|
96
111
|
*
|
|
97
112
|
* @remarks
|
|
98
113
|
* This is the hostile boundary behind task reports and snapshot hydration. Supplying
|
|
@@ -109,7 +124,32 @@ export declare function captureWorkflowOptions(options?: WorkflowOptions): Workf
|
|
|
109
124
|
export declare function cloneTaskActivity(input: unknown, updated?: number): TaskActivity;
|
|
110
125
|
|
|
111
126
|
/**
|
|
112
|
-
*
|
|
127
|
+
* Validates and owns one list of task activity claims.
|
|
128
|
+
*
|
|
129
|
+
* @remarks
|
|
130
|
+
* The one cloner behind both claim lists of a task activity frame — its `operations` and its
|
|
131
|
+
* `constraints` — because {@link import('./types.js').TaskOperation} and
|
|
132
|
+
* {@link import('./types.js').TaskConstraint} are the same {@link import('./types.js').TaskClaim}
|
|
133
|
+
* shape. An omitted
|
|
134
|
+
* list is an empty one. Each member is read exactly once inside the caller's protected boundary
|
|
135
|
+
* and returned frozen; the semantic pass over the copied values is
|
|
136
|
+
* {@link import('./validators.js').isTaskClaimList}, so this cloner refuses only what it cannot
|
|
137
|
+
* read: a non-array list, a non-record member, a hostile prototype, or an unexpected key.
|
|
138
|
+
*
|
|
139
|
+
* @param input - The untrusted claim list
|
|
140
|
+
* @param noun - The singular claim noun the refusal message names, pluralized by adding `s`
|
|
141
|
+
* @returns The owned frozen claims, in input order
|
|
142
|
+
* @throws {WorkflowError} With `MUTATION` when the list or one of its members cannot be read
|
|
143
|
+
*
|
|
144
|
+
* @example
|
|
145
|
+
* ```ts
|
|
146
|
+
* cloneTaskClaims([{ id: 'fetch', name: 'Fetch', started: 1 }], 'operation')
|
|
147
|
+
* ```
|
|
148
|
+
*/
|
|
149
|
+
export declare function cloneTaskClaims(input: unknown, noun: string): readonly unknown[];
|
|
150
|
+
|
|
151
|
+
/**
|
|
152
|
+
* Validates and owns a workflow snapshot before live construction.
|
|
113
153
|
*
|
|
114
154
|
* @param input - The hostile snapshot boundary
|
|
115
155
|
* @param id - The optional storage key the owned snapshot must match
|
|
@@ -119,7 +159,156 @@ export declare function cloneTaskActivity(input: unknown, updated?: number): Tas
|
|
|
119
159
|
export declare function cloneWorkflowSnapshot(input: unknown, id?: string): WorkflowSnapshot;
|
|
120
160
|
|
|
121
161
|
/**
|
|
122
|
-
*
|
|
162
|
+
* Implements the insertion-ordered gated store both lean managers hold — entities keyed by `id`,
|
|
163
|
+
* positional order preserved across an interior `skip` or `remove`.
|
|
164
|
+
*
|
|
165
|
+
* @remarks
|
|
166
|
+
* - **One engine, two managers.** {@link import('./tasks/TaskManager.js').TaskManager} and
|
|
167
|
+
* {@link import('./phases/PhaseManager.js').PhaseManager} differ only in the entity noun and the
|
|
168
|
+
* patch shape they validate, so both hold one of these and add only their domain accessors
|
|
169
|
+
* (`task` / `tasks`, `phase` / `phases`). The `Map`'s insertion order is the single source of
|
|
170
|
+
* positional truth; `add` and `move` rebuild it through the pure
|
|
171
|
+
* {@link import('./helpers.js').insertEntry} / {@link import('./helpers.js').moveEntry} leaves.
|
|
172
|
+
* - **Gated mutation API.** `append` is the build-time wiring path and THROWS on a
|
|
173
|
+
* duplicate id; `add` / `remove` / `move` / `update` return a graceful `MUTATION`
|
|
174
|
+
* {@link WorkflowError} failure instead. Gating reads ONLY the target's own existence, `pending`
|
|
175
|
+
* status, id, and bounds — a container's own status is the owning entity's gate, applied before
|
|
176
|
+
* it delegates here.
|
|
177
|
+
* - **Event-free.** A purely structural container; the entity that owns it emits on success.
|
|
178
|
+
*
|
|
179
|
+
* @typeParam TEntry - The stored entity
|
|
180
|
+
* @typeParam TPatch - The declarative partial update `update` validates and applies
|
|
181
|
+
*
|
|
182
|
+
* @example
|
|
183
|
+
* ```ts
|
|
184
|
+
* import { compileGuard } from '@orkestrel/contract'
|
|
185
|
+
* import { Collection, taskUpdateShape } from '@orkestrel/workflow'
|
|
186
|
+
* import type { TaskInterface, TaskUpdate } from '@orkestrel/workflow'
|
|
187
|
+
*
|
|
188
|
+
* const tasks = new Collection<TaskInterface, TaskUpdate>('task', compileGuard(taskUpdateShape))
|
|
189
|
+
* tasks.append(task) // a live Task
|
|
190
|
+
* tasks.entry(task.id) // the same task
|
|
191
|
+
* tasks.entries() // [task]
|
|
192
|
+
* tasks.count // 1
|
|
193
|
+
* tasks.add(other, 0) // Result — inserted first
|
|
194
|
+
* tasks.move(other.id, 1) // Result — repositioned
|
|
195
|
+
* tasks.update(task.id, { name: 'Renamed task' }) // Result — patched
|
|
196
|
+
* tasks.remove(other.id) // Result — dropped
|
|
197
|
+
* ```
|
|
198
|
+
*/
|
|
199
|
+
export declare class Collection<TEntry extends CollectionEntry<TPatch>, TPatch> implements CollectionInterface<TEntry, TPatch> {
|
|
200
|
+
#private;
|
|
201
|
+
constructor(noun: string, patch: Guard<TPatch>);
|
|
202
|
+
get count(): number;
|
|
203
|
+
append(entry: TEntry): void;
|
|
204
|
+
add(entry: TEntry, index?: number): Result<TEntry, WorkflowError>;
|
|
205
|
+
remove(id: string): Result<TEntry, WorkflowError>;
|
|
206
|
+
move(id: string, index: number): Result<TEntry, WorkflowError>;
|
|
207
|
+
update(id: string, patch: TPatch): Result<TEntry, WorkflowError>;
|
|
208
|
+
entry(id: string): TEntry | undefined;
|
|
209
|
+
entries(): readonly TEntry[];
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
/**
|
|
213
|
+
* Declares what the {@link CollectionInterface} store requires of the entities it holds — a stable `id`, a
|
|
214
|
+
* gating {@link LifecycleStatus}, and a `patch` the store applies after validation.
|
|
215
|
+
*
|
|
216
|
+
* @remarks
|
|
217
|
+
* Both {@link TaskInterface} and {@link PhaseInterface} satisfy it, which is what lets one engine
|
|
218
|
+
* serve {@link TaskManagerInterface} and {@link PhaseManagerInterface}. The store reads `status`
|
|
219
|
+
* only to gate a `remove` / `move` / `update` on the target being `pending`; it never derives,
|
|
220
|
+
* writes, or interprets it further.
|
|
221
|
+
*
|
|
222
|
+
* @typeParam TPatch - The declarative partial update the entity's `patch` accepts
|
|
223
|
+
*/
|
|
224
|
+
export declare interface CollectionEntry<TPatch> {
|
|
225
|
+
readonly id: string;
|
|
226
|
+
readonly status: LifecycleStatus;
|
|
227
|
+
patch(value: TPatch): void;
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
/**
|
|
231
|
+
* Declares an insertion-ordered store of {@link CollectionEntry} entities keyed by `id`, with the gated
|
|
232
|
+
* mutation quartet a lean manager delegates to.
|
|
233
|
+
*
|
|
234
|
+
* @remarks
|
|
235
|
+
* The ONE engine behind {@link TaskManagerInterface} and {@link PhaseManagerInterface}: positional
|
|
236
|
+
* order is the backing `Map`'s insertion order, so it survives an interior `skip` (a status
|
|
237
|
+
* change, never a removal) and a snapshot restore reproduces it by re-`append`ing in order.
|
|
238
|
+
* `append` is the build-time wiring path and THROWS a `MUTATION`
|
|
239
|
+
* {@link import('./errors.js').WorkflowError} on a duplicate id (a genuine programmer error);
|
|
240
|
+
* `add` / `remove` / `move` / `update` are its graceful `Result` counterparts, gating ONLY on the
|
|
241
|
+
* target's own existence, `pending` status, id, and bounds. The store is event-free — the entity
|
|
242
|
+
* that owns it emits on success. Each refusal names the entity noun the store was built with, so
|
|
243
|
+
* a task store and a phase store report in their own vocabulary.
|
|
244
|
+
*
|
|
245
|
+
* @typeParam TEntry - The stored entity
|
|
246
|
+
* @typeParam TPatch - The declarative partial update `update` validates and applies
|
|
247
|
+
*/
|
|
248
|
+
export declare interface CollectionInterface<TEntry, TPatch> {
|
|
249
|
+
readonly count: number;
|
|
250
|
+
/**
|
|
251
|
+
* Adds `entry` at the end — the build-time wiring path.
|
|
252
|
+
*
|
|
253
|
+
* @remarks
|
|
254
|
+
* THROWS a `MUTATION` {@link import('./errors.js').WorkflowError} on a duplicate `id` instead
|
|
255
|
+
* of silently overwriting the existing entry.
|
|
256
|
+
*
|
|
257
|
+
* @param entry - The entity to append
|
|
258
|
+
*/
|
|
259
|
+
append(entry: TEntry): void;
|
|
260
|
+
/**
|
|
261
|
+
* Inserts `entry` at `index` (default the end) — the gated counterpart to {@link append}.
|
|
262
|
+
*
|
|
263
|
+
* @param entry - The entity to insert
|
|
264
|
+
* @param index - The insertion position (`[0, count]`); omitted inserts at the end
|
|
265
|
+
* @returns A {@link Result} boxing the inserted entity, or a `MUTATION` failure on a duplicate
|
|
266
|
+
* id or an out-of-bounds `index`
|
|
267
|
+
*/
|
|
268
|
+
add(entry: TEntry, index?: number): Result<TEntry, WorkflowError>;
|
|
269
|
+
/**
|
|
270
|
+
* Removes the `pending` entity `id`.
|
|
271
|
+
*
|
|
272
|
+
* @param id - The entity id to remove
|
|
273
|
+
* @returns A {@link Result} boxing the removed entity, or a `MUTATION` failure when `id` is
|
|
274
|
+
* absent or not `pending`
|
|
275
|
+
*/
|
|
276
|
+
remove(id: string): Result<TEntry, WorkflowError>;
|
|
277
|
+
/**
|
|
278
|
+
* Repositions the `pending` entity `id` to `index`.
|
|
279
|
+
*
|
|
280
|
+
* @param id - The entity id to move
|
|
281
|
+
* @param index - The destination position (`[0, count)`)
|
|
282
|
+
* @returns A {@link Result} boxing the moved entity, or a `MUTATION` failure when `id` is
|
|
283
|
+
* absent, not `pending`, or `index` is out of bounds
|
|
284
|
+
*/
|
|
285
|
+
move(id: string, index: number): Result<TEntry, WorkflowError>;
|
|
286
|
+
/**
|
|
287
|
+
* Applies a validated patch to the `pending` entity `id`.
|
|
288
|
+
*
|
|
289
|
+
* @param id - The entity id to patch
|
|
290
|
+
* @param patch - The fields to update
|
|
291
|
+
* @returns A {@link Result} boxing the patched entity, or a `MUTATION` failure when `id` is
|
|
292
|
+
* absent, not `pending`, or `patch` fails validation
|
|
293
|
+
*/
|
|
294
|
+
update(id: string, patch: TPatch): Result<TEntry, WorkflowError>;
|
|
295
|
+
/**
|
|
296
|
+
* Looks up one stored entity by its `id`.
|
|
297
|
+
*
|
|
298
|
+
* @param id - The entity id to resolve
|
|
299
|
+
* @returns The stored entity, or `undefined` when none is stored under `id`
|
|
300
|
+
*/
|
|
301
|
+
entry(id: string): TEntry | undefined;
|
|
302
|
+
/**
|
|
303
|
+
* Lists every stored entity in positional order.
|
|
304
|
+
*
|
|
305
|
+
* @returns The stored entities, in insertion order
|
|
306
|
+
*/
|
|
307
|
+
entries(): readonly TEntry[];
|
|
308
|
+
}
|
|
309
|
+
|
|
310
|
+
/**
|
|
311
|
+
* Flattens a nested list of per-phase {@link TaskResult} lists into one positional list
|
|
123
312
|
* — the workflow tier of the result tree, built from each phase's `results()`.
|
|
124
313
|
*
|
|
125
314
|
* @remarks
|
|
@@ -133,45 +322,7 @@ export declare function cloneWorkflowSnapshot(input: unknown, id?: string): Work
|
|
|
133
322
|
export declare function collectResults(phases: ReadonlyArray<readonly TaskResult[]>): readonly TaskResult[];
|
|
134
323
|
|
|
135
324
|
/**
|
|
136
|
-
*
|
|
137
|
-
* input, cancellation, and the run controls (`wait` / `spawn` / `abort`).
|
|
138
|
-
*
|
|
139
|
-
* @remarks
|
|
140
|
-
* - **Built by the Runner per unit.** The runner constructs one `Controller` per
|
|
141
|
-
* unit it dispatches, handing it the unit's `id`, `input`, the unit's `Abort`
|
|
142
|
-
* handle, the queue attempt's `signal`, and a `spawn` callback that launches a
|
|
143
|
-
* sibling through the same queue.
|
|
144
|
-
* - **Signal.** `signal` is the queue attempt's signal, which ANY-combines the
|
|
145
|
-
* unit's own abort, the runner-level abort (the runner aborts every unit), and
|
|
146
|
-
* the per-attempt timeout — so it fires on any of the three. `aborted` and
|
|
147
|
-
* `abort(reason)` delegate to the unit's `Abort` (the cancellation source of
|
|
148
|
-
* truth); since the attempt signal ANY-includes that abort, `abort()` fires
|
|
149
|
-
* `signal` too.
|
|
150
|
-
* - **`wait` promise-parks (never a timer).** It resolves the instant the unit's
|
|
151
|
-
* `signal` fires (immediately if already aborted) via a one-shot listener — no
|
|
152
|
-
* `setTimeout`, no polling, no busy-yield — so a parked unit costs no CPU.
|
|
153
|
-
* - **`spawn` is fire-and-track.** It delegates to the runner's launch-a-sibling
|
|
154
|
-
* callback, which routes the sibling through the queue; the runner's `execute`
|
|
155
|
-
* awaits the spawn closure, so the sibling runs whether or not its promise is
|
|
156
|
-
* awaited. (Inline-awaiting a spawn from a slot-holding handler on a bounded
|
|
157
|
-
* runner can deadlock — fan out instead; see {@link ControllerInterface.spawn}.)
|
|
158
|
-
* - **Event-free by design.** The per-unit handle carries no Emitter; observe the
|
|
159
|
-
* {@link RunnerInterface.emitter} instead (`unit` / `spawn` / `settle` / `fail` carry the id).
|
|
160
|
-
*/
|
|
161
|
-
export declare class Controller<TInput, TResult> implements ControllerInterface<TInput, TResult> {
|
|
162
|
-
#private;
|
|
163
|
-
readonly id: string;
|
|
164
|
-
readonly input: TInput;
|
|
165
|
-
readonly signal: AbortSignal;
|
|
166
|
-
constructor(id: string, input: TInput, abort: AbortInterface, signal: AbortSignal, spawn: (input: TInput) => Promise<TResult>);
|
|
167
|
-
get aborted(): boolean;
|
|
168
|
-
wait(): Promise<void>;
|
|
169
|
-
spawn(input: TInput): Promise<TResult>;
|
|
170
|
-
abort(reason?: unknown): void;
|
|
171
|
-
}
|
|
172
|
-
|
|
173
|
-
/**
|
|
174
|
-
* The per-unit handle a {@link RunnerHandler} receives — the running unit's
|
|
325
|
+
* Declares the per-unit handle a {@link RunnerHandler} receives — the running unit's
|
|
175
326
|
* identity, input, cancellation, and the controls to cooperate with the run.
|
|
176
327
|
*
|
|
177
328
|
* @remarks
|
|
@@ -195,7 +346,7 @@ export declare interface ControllerInterface<TInput, TResult> {
|
|
|
195
346
|
readonly signal: AbortSignal;
|
|
196
347
|
readonly aborted: boolean;
|
|
197
348
|
/**
|
|
198
|
-
*
|
|
349
|
+
* Parks until this unit's `signal` aborts — **promise-parked**, never a timer.
|
|
199
350
|
*
|
|
200
351
|
* @remarks
|
|
201
352
|
* Resolves the moment the unit's `signal` fires (unit abort, runner abort, or
|
|
@@ -203,11 +354,11 @@ export declare interface ControllerInterface<TInput, TResult> {
|
|
|
203
354
|
* one-shot `'abort'` listener and never polls — no `setTimeout`, no `delay`, no
|
|
204
355
|
* busy-yield — so a parked unit consumes no CPU until it is actually cancelled.
|
|
205
356
|
*
|
|
206
|
-
* @returns A promise that resolves
|
|
357
|
+
* @returns A promise that resolves after the unit's `signal` aborts
|
|
207
358
|
*/
|
|
208
359
|
wait(): Promise<void>;
|
|
209
360
|
/**
|
|
210
|
-
*
|
|
361
|
+
* Adds a sibling unit to the run; returns its result promise.
|
|
211
362
|
*
|
|
212
363
|
* @remarks
|
|
213
364
|
* **Fire-and-track.** The spawned unit is routed through the same backing queue
|
|
@@ -228,7 +379,7 @@ export declare interface ControllerInterface<TInput, TResult> {
|
|
|
228
379
|
*/
|
|
229
380
|
spawn(input: TInput): Promise<TResult>;
|
|
230
381
|
/**
|
|
231
|
-
*
|
|
382
|
+
* Cancels this unit — fires its `signal` with the optional reason.
|
|
232
383
|
*
|
|
233
384
|
* @param reason - An optional cancellation reason carried on the signal
|
|
234
385
|
*/
|
|
@@ -236,7 +387,7 @@ export declare interface ControllerInterface<TInput, TResult> {
|
|
|
236
387
|
}
|
|
237
388
|
|
|
238
389
|
/**
|
|
239
|
-
*
|
|
390
|
+
* Creates a {@link DatabaseWorkflowStore} over any {@link DriverInterface} — the durable,
|
|
240
391
|
* driver-pluggable backing for the W-d persistence seam, the opt-in twin of
|
|
241
392
|
* {@link createMemoryWorkflowStore}.
|
|
242
393
|
*
|
|
@@ -247,8 +398,9 @@ export declare interface ControllerInterface<TInput, TResult> {
|
|
|
247
398
|
* snapshot is already a COMPLETE, self-contained, pure-JSON payload, so storing it whole is lossless
|
|
248
399
|
* AND keeps the row type FLAT — a structured multi-column snapshot table would force the contract to
|
|
249
400
|
* `Infer` the deeply-nested snapshot shape (workflow → phases → tasks → results) and trip TS2589;
|
|
250
|
-
* the opaque column sidesteps it (the column reads back as `unknown`, narrowed on `get` by
|
|
251
|
-
* {@link
|
|
401
|
+
* the opaque column sidesteps it (the column reads back as `unknown`, owned and narrowed on `get` by
|
|
402
|
+
* {@link cloneWorkflowSnapshot}, whose semantic pass is
|
|
403
|
+
* {@link import('./validators.js').isOwnedWorkflowSnapshot}). The `driver` DEFAULTS to
|
|
252
404
|
* {@link createMemoryDriver}, so the store ALSO works in memory out of the box; pass a server
|
|
253
405
|
* `createJSONDriver` / `createSQLiteDriver` (or a browser IndexedDB driver) for a persistent one —
|
|
254
406
|
* the durability is the driver's job, the store engine is shared. It swaps in behind
|
|
@@ -272,23 +424,15 @@ export declare interface ControllerInterface<TInput, TResult> {
|
|
|
272
424
|
export declare function createDatabaseWorkflowStore(driver?: DriverInterface): WorkflowStoreInterface;
|
|
273
425
|
|
|
274
426
|
/**
|
|
275
|
-
*
|
|
276
|
-
* externally, so a caller can resolve/reject it from outside the executor.
|
|
277
|
-
*
|
|
278
|
-
* @typeParam T - The value the deferred promise resolves
|
|
279
|
-
* @returns A deferred `promise` plus its `resolve` / `reject`
|
|
280
|
-
*/
|
|
281
|
-
export declare function createDeferred<T>(): DeferredInterface<T>;
|
|
282
|
-
|
|
283
|
-
/**
|
|
284
|
-
* Create the in-memory durable {@link WorkflowStoreInterface} — a process-lifetime
|
|
427
|
+
* Creates the in-memory durable {@link WorkflowStoreInterface} — a process-lifetime
|
|
285
428
|
* {@link MemoryWorkflowStore} persisting {@link WorkflowSnapshot}s by workflow id, the DEFAULT
|
|
286
429
|
* backend behind the W-d persistence seam.
|
|
287
430
|
*
|
|
288
431
|
* @remarks
|
|
289
432
|
* The snapshot analogue of the server package's `createMemorySessionStore`
|
|
290
433
|
* (and the `createMemoryQueueStore` family), but LEANER — there is no idle-TTL, so no
|
|
291
|
-
* options bag (
|
|
434
|
+
* options bag (the smallest interface the capability requires): a persisted run-state lives until
|
|
435
|
+
* an explicit `delete`. This is
|
|
292
436
|
* the zero-plumbing DEFAULT (a plain `Map`); its driver-pluggable twin is
|
|
293
437
|
* {@link createDatabaseWorkflowStore} (the snapshot as one opaque JSON column over a `databases`
|
|
294
438
|
* table) — for a DURABLE store (run-state surviving a restart) pass it a JSON / SQLite / IndexedDB
|
|
@@ -311,10 +455,10 @@ export declare function createDeferred<T>(): DeferredInterface<T>;
|
|
|
311
455
|
export declare function createMemoryWorkflowStore(): WorkflowStoreInterface;
|
|
312
456
|
|
|
313
457
|
/**
|
|
314
|
-
*
|
|
458
|
+
* Builds an interrupted workflow back to life at its remaining retry budget.
|
|
315
459
|
*
|
|
316
460
|
* @remarks
|
|
317
|
-
* Each phase captures every unique initial `
|
|
461
|
+
* Each phase captures every unique initial `behavior` binding once before constructing tasks. Recovery
|
|
318
462
|
* validates those live tasks' captured callable handlers without rereading the registry, while the
|
|
319
463
|
* retained registry identity remains available to resolve future live additions at their mint time.
|
|
320
464
|
*
|
|
@@ -333,7 +477,7 @@ export declare function createMemoryWorkflowStore(): WorkflowStoreInterface;
|
|
|
333
477
|
export declare function createRecoveredWorkflow(snapshot: unknown, options?: WorkflowOptions): WorkflowInterface;
|
|
334
478
|
|
|
335
479
|
/**
|
|
336
|
-
*
|
|
480
|
+
* Builds an equivalent live W-b entity tree from a {@link WorkflowSnapshot} — the
|
|
337
481
|
* inverse of {@link WorkflowInterface.snapshot}, restoring structure + each node's status
|
|
338
482
|
* + recorded results + positional order + the persisted `#override`.
|
|
339
483
|
*
|
|
@@ -348,7 +492,7 @@ export declare function createRecoveredWorkflow(snapshot: unknown, options?: Wor
|
|
|
348
492
|
* still wins when supplied (to deliberately re-run under a different policy). A structurally
|
|
349
493
|
* invalid snapshot (a status — or override — outside the lifecycle vocabulary, or a
|
|
350
494
|
* non-boolean `bail`) throws a `RESTORE` {@link WorkflowError}.
|
|
351
|
-
* Runtime handlers are optional: without a matching `functions` entry, a persisted `
|
|
495
|
+
* Runtime handlers are optional: without a matching `functions` entry, a persisted `behavior`
|
|
352
496
|
* remains visible with an undefined `handler` so the exact state is inspectable. The runner
|
|
353
497
|
* rejects that unresolved tree if execution is attempted.
|
|
354
498
|
*
|
|
@@ -367,7 +511,7 @@ export declare function createRecoveredWorkflow(snapshot: unknown, options?: Wor
|
|
|
367
511
|
export declare function createRestoredWorkflow(snapshot: unknown, options?: WorkflowOptions): WorkflowInterface;
|
|
368
512
|
|
|
369
513
|
/**
|
|
370
|
-
*
|
|
514
|
+
* Creates a thin generic orchestrator that drives declared units — and any they
|
|
371
515
|
* `spawn` — through a bounded-concurrency queue, collecting their results in order.
|
|
372
516
|
*
|
|
373
517
|
* @remarks
|
|
@@ -379,13 +523,13 @@ export declare function createRestoredWorkflow(snapshot: unknown, options?: Work
|
|
|
379
523
|
* `id` / `input`, a `signal` that fires on the unit's `abort`, a runner-level `abort`,
|
|
380
524
|
* or the attempt's timeout, a promise-parked `wait()`, and `spawn(input)` to fan out
|
|
381
525
|
* sibling units. The run is **fail-fast**: the first unit failure (after retries)
|
|
382
|
-
* aborts every other unit and rejects `execute` with that error. **Observable
|
|
526
|
+
* aborts every other unit and rejects `execute` with that error. **Observable:** a
|
|
383
527
|
* typed `emitter` surfaces `start` / `unit` / `spawn` / `settle` / `fail` / `finish` / `abort`.
|
|
384
528
|
*
|
|
385
|
-
* Because `spawn` is fire-and-track (the runner awaits the whole spawn closure
|
|
529
|
+
* Because `spawn` is fire-and-track (the runner awaits the whole spawn closure through an
|
|
386
530
|
* outstanding-unit count, not a one-time snapshot), a handler need NOT await its spawns
|
|
387
|
-
* for them to run — and on a bounded runner
|
|
388
|
-
*
|
|
531
|
+
* for them to run — and on a bounded runner do NOT `await` a spawn inline (a slot-holding
|
|
532
|
+
* handler awaiting its own spawn can deadlock); fan out and return instead.
|
|
389
533
|
*
|
|
390
534
|
* @typeParam TInput - The work input each unit carries
|
|
391
535
|
* @typeParam TResult - The value a unit's handler resolves
|
|
@@ -413,12 +557,12 @@ export declare function createRestoredWorkflow(snapshot: unknown, options?: Work
|
|
|
413
557
|
export declare function createRunner<TInput, TResult>(options: RunnerOptions<TInput, TResult>): RunnerInterface<TInput, TResult>;
|
|
414
558
|
|
|
415
559
|
/**
|
|
416
|
-
*
|
|
560
|
+
* Creates the safe cross-environment cooperative-yield default — a
|
|
417
561
|
* {@link SchedulerInterface} built on `setTimeout` / `clearTimeout` alone, so it
|
|
418
562
|
* runs unchanged in both the browser and Node.
|
|
419
563
|
*
|
|
420
564
|
* @remarks
|
|
421
|
-
* `yield()` gives the host a turn
|
|
565
|
+
* `yield()` gives the host a turn through a zero-delay macrotask (so pending I/O,
|
|
422
566
|
* timers, and rendering actually run — a microtask would not); `delay(ms)` resumes
|
|
423
567
|
* after at least `ms`. Pass `options.signal` to make a pending yield/delay reject
|
|
424
568
|
* with the signal's exact `reason`; the shared owned-signal lifecycle clears the timer
|
|
@@ -458,7 +602,7 @@ export declare function createRunner<TInput, TResult>(options: RunnerOptions<TIn
|
|
|
458
602
|
export declare function createScheduler(): SchedulerInterface;
|
|
459
603
|
|
|
460
604
|
/**
|
|
461
|
-
*
|
|
605
|
+
* Builds the live W-b entity tree from a {@link WorkflowDefinition} — the whole
|
|
462
606
|
* {@link WorkflowInterface} → {@link import('./types.js').PhaseInterface} →
|
|
463
607
|
* {@link import('./types.js').TaskInterface} tree, each level wired with its lineage
|
|
464
608
|
* context, its emitter, and the cascade.
|
|
@@ -470,11 +614,11 @@ export declare function createScheduler(): SchedulerInterface;
|
|
|
470
614
|
* definition's `bail`, else the graceful {@link import('./constants.js').DEFAULT_BAIL}; it
|
|
471
615
|
* feeds {@link import('./helpers.js').deriveWorkflowStatus}. Per-phase / per-task initial
|
|
472
616
|
* listeners + metadata travel through `options.phases[id].on` /
|
|
473
|
-
* `options.phases[id].tasks[id]` (the
|
|
617
|
+
* `options.phases[id].tasks[id]` (the nested-by-id bag). The W-b tree is the
|
|
474
618
|
* state machine ONLY — it does not execute tasks (W-c drives the transitions).
|
|
475
619
|
*
|
|
476
|
-
* `options.functions` is the {@link import('./types.js').
|
|
477
|
-
* task's `
|
|
620
|
+
* `options.functions` is the {@link import('./types.js').WorkflowRegistry} registry each live
|
|
621
|
+
* task's `behavior` name resolves against ONCE at construction into its runtime
|
|
478
622
|
* {@link import('./types.js').TaskInterface.handler}. An omitted name is the deliberate no-op;
|
|
479
623
|
* an unresolved present name remains inspectable but is rejected if execution is attempted.
|
|
480
624
|
*
|
|
@@ -494,7 +638,7 @@ export declare function createScheduler(): SchedulerInterface;
|
|
|
494
638
|
export declare function createWorkflow(definition: WorkflowDefinition, options?: WorkflowOptions): WorkflowInterface;
|
|
495
639
|
|
|
496
640
|
/**
|
|
497
|
-
*
|
|
641
|
+
* Compiles the workflow definition contract — the JSON Schema, guard, parser, and
|
|
498
642
|
* seeded generator for a {@link WorkflowDefinition}, all derived from one shape and
|
|
499
643
|
* kept in lockstep.
|
|
500
644
|
*
|
|
@@ -523,13 +667,13 @@ export declare function createWorkflow(definition: WorkflowDefinition, options?:
|
|
|
523
667
|
export declare function createWorkflowContract(): ContractInterface<WorkflowDefinition>;
|
|
524
668
|
|
|
525
669
|
/**
|
|
526
|
-
*
|
|
670
|
+
* Creates a {@link WorkflowManagerInterface} — the store-backed registry of
|
|
527
671
|
* {@link WorkflowInterface}s, the additive manager tier mirroring the `@orkestrel/agent`
|
|
528
672
|
* line's `createConversationManager` / `createWorkspaceManager`.
|
|
529
673
|
*
|
|
530
674
|
* @remarks
|
|
531
|
-
* `options.functions` flows into every workflow the manager mints (`add`,
|
|
532
|
-
* {@link createWorkflow}) or hydrates (`open`'s registry-miss path,
|
|
675
|
+
* `options.functions` flows into every workflow the manager mints (`add`, through
|
|
676
|
+
* {@link createWorkflow}) or hydrates (`open`'s registry-miss path, through
|
|
533
677
|
* {@link createRestoredWorkflow}), so a hydrated workflow is RUNNABLE rather than a dead snapshot
|
|
534
678
|
* mirror. `options.store` is the EXACT analogue of the twins' `store` seam — omitted ⇒ the
|
|
535
679
|
* manager is registry-only (`open` resolves only what is registered, `save` is a no-op). This
|
|
@@ -556,9 +700,9 @@ export declare function createWorkflowContract(): ContractInterface<WorkflowDefi
|
|
|
556
700
|
export declare function createWorkflowManager(options?: WorkflowManagerOptions): WorkflowManagerInterface;
|
|
557
701
|
|
|
558
702
|
/**
|
|
559
|
-
*
|
|
560
|
-
* workflow tree by COMPOSING the shipped substrate: phases sequential, tasks concurrent,
|
|
561
|
-
*
|
|
703
|
+
* Creates the thin orchestrator — a {@link WorkflowRunnerInterface} — that EXECUTES a live W-b
|
|
704
|
+
* workflow tree by COMPOSING the shipped substrate: phases sequential, tasks concurrent, each
|
|
705
|
+
* task dispatched through its OWN resolved handler under the workflow's `bail` policy.
|
|
562
706
|
*
|
|
563
707
|
* @remarks
|
|
564
708
|
* The runner is a PURE engine — it re-implements no concurrency / retry / abort logic, AND it
|
|
@@ -571,14 +715,14 @@ export declare function createWorkflowManager(options?: WorkflowManagerOptions):
|
|
|
571
715
|
* rest) vs settle-all (`false` — failures are recorded, the run finishes); the run-level abort
|
|
572
716
|
* / timeout / budget ({@link import('./types.js').WorkflowRunOptions}) fold through
|
|
573
717
|
* `AbortSignal.any` (the agent runtime's pattern); pacing is the shipped scheduler.
|
|
574
|
-
* `execute(definition, options?)` BUILDS the live tree from the definition itself (
|
|
718
|
+
* `execute(definition, options?)` BUILDS the live tree from the definition itself (through
|
|
575
719
|
* {@link createWorkflow} — one source of truth, returned in `WorkflowResult.workflow`), drives
|
|
576
720
|
* the live entity (`start` → `complete` / `fail`), and resolves a
|
|
577
721
|
* {@link import('./types.js').WorkflowResult}.
|
|
578
722
|
*
|
|
579
723
|
* External integrations remain application-owned: a caller wires an ordinary
|
|
580
724
|
* {@link import('./types.js').WorkflowFunction} into its own {@link WorkflowOptions.functions}
|
|
581
|
-
* registry. Only a task that omits `
|
|
725
|
+
* registry. Only a task that omits `behavior` auto-completes; unresolved named work is rejected
|
|
582
726
|
* before dispatch.
|
|
583
727
|
*
|
|
584
728
|
* @param options - An optional pacing `scheduler` (default the shipped cross-environment one).
|
|
@@ -591,7 +735,7 @@ export declare function createWorkflowManager(options?: WorkflowManagerOptions):
|
|
|
591
735
|
*
|
|
592
736
|
* const runner = createWorkflowRunner()
|
|
593
737
|
* const definition = { id: 'w', name: 'W', phases: [{ id: 'p', name: 'P', tasks: [
|
|
594
|
-
* { id: 't', name: 'T',
|
|
738
|
+
* { id: 't', name: 'T', behavior: 'compile' },
|
|
595
739
|
* ] }] }
|
|
596
740
|
* const result = await runner.execute(definition, {
|
|
597
741
|
* functions: { compile: async (controller) => `built ${controller.task.id}` },
|
|
@@ -603,7 +747,43 @@ export declare function createWorkflowManager(options?: WorkflowManagerOptions):
|
|
|
603
747
|
export declare function createWorkflowRunner(options?: WorkflowRunnerOptions): WorkflowRunnerInterface;
|
|
604
748
|
|
|
605
749
|
/**
|
|
606
|
-
*
|
|
750
|
+
* Builds the live entity tree one definition and one owned options bag describe — the shared
|
|
751
|
+
* construction path behind every definition-driven mint.
|
|
752
|
+
*
|
|
753
|
+
* @remarks
|
|
754
|
+
* Seeds an initial all-`pending` {@link WorkflowSnapshot} from the definition and constructs the
|
|
755
|
+
* live {@link WorkflowInterface} over it. `bail` is the caller's own override, forwarded to
|
|
756
|
+
* {@link definitionToSnapshot} so it reaches BOTH tiers: the workflow snapshot AND the inheritance
|
|
757
|
+
* default of every phase that declares no `bail` of its own, while a phase declaring one still
|
|
758
|
+
* wins. Omitted, the definition's own `bail` governs, defaulting to the graceful
|
|
759
|
+
* {@link import('./constants.js').DEFAULT_BAIL}.
|
|
760
|
+
*
|
|
761
|
+
* `captured` is forwarded to the entity UNCHANGED — its own `bail` is deliberately not replaced
|
|
762
|
+
* with the resolved policy, because the snapshot already carries the resolved value at both tiers
|
|
763
|
+
* and an injected one would make `Workflow` read it as an EXPLICIT uniform override and clobber
|
|
764
|
+
* the per-phase overrides. Each task's `behavior` / `retries` / `timeout` travel onto the snapshot
|
|
765
|
+
* too, so `captured.functions` resolves every handler identically whether the tree is built fresh
|
|
766
|
+
* or restored. Pass a bag {@link captureWorkflowOptions} already owns: this constructs over it
|
|
767
|
+
* without re-capturing.
|
|
768
|
+
*
|
|
769
|
+
* @param definition - The workflow definition to bring to life
|
|
770
|
+
* @param captured - The already-owned {@link WorkflowOptions} bag the entity is constructed with,
|
|
771
|
+
* whose `bail` is the caller's failure-policy override, or `undefined` to take the definition's
|
|
772
|
+
* @returns The live {@link WorkflowInterface} root
|
|
773
|
+
*
|
|
774
|
+
* @example
|
|
775
|
+
* ```ts
|
|
776
|
+
* import { captureWorkflowOptions, createWorkflowTree } from '@orkestrel/workflow'
|
|
777
|
+
*
|
|
778
|
+
* const captured = captureWorkflowOptions({ bail: true })
|
|
779
|
+
* const workflow = createWorkflowTree(definition, captured)
|
|
780
|
+
* workflow.bail // true — the override reached the workflow and every inheriting phase
|
|
781
|
+
* ```
|
|
782
|
+
*/
|
|
783
|
+
export declare function createWorkflowTree(definition: WorkflowDefinition, captured: WorkflowOptions): WorkflowInterface;
|
|
784
|
+
|
|
785
|
+
/**
|
|
786
|
+
* Implements a {@link WorkflowStoreInterface} backed by one table of the `databases` layer — a
|
|
607
787
|
* workflow's durable run-state IS a row, so persistence reduces to keyed point-access
|
|
608
788
|
* (`get` / `set` / `delete`) over a `TableInterface`, the driver-pluggable twin of the
|
|
609
789
|
* plain-`Map` {@link import('./MemoryWorkflowStore.js').MemoryWorkflowStore}.
|
|
@@ -627,16 +807,18 @@ export declare function createWorkflowRunner(options?: WorkflowRunnerOptions): W
|
|
|
627
807
|
*
|
|
628
808
|
* - **`set(snapshot)` upserts under the snapshot's OWN `id`** (no separate id param) — it writes
|
|
629
809
|
* the row `{ id: snapshot.id, snapshot }`.
|
|
630
|
-
* - **`get(id)` resolves the stored snapshot for an id**, narrowing the opaque JSON
|
|
631
|
-
* a {@link WorkflowSnapshot}
|
|
632
|
-
*
|
|
633
|
-
*
|
|
810
|
+
* - **`get(id)` resolves the stored snapshot for an id**, owning and narrowing the opaque JSON
|
|
811
|
+
* column back to a {@link WorkflowSnapshot} through
|
|
812
|
+
* {@link import('../cloners.js').cloneWorkflowSnapshot}, whose semantic pass is
|
|
813
|
+
* {@link import('../validators.js').isOwnedWorkflowSnapshot} — the boundary narrow for
|
|
814
|
+
* an untrusted storage read — or `undefined` if none is stored. A present snapshot whose own id
|
|
815
|
+
* differs from the requested key rejects with normalized `RESTORE` evidence.
|
|
634
816
|
* - **`delete(id)` drops a snapshot by id**; an absent id is a no-op (no throw).
|
|
635
817
|
*
|
|
636
818
|
* UNLIKE the server package's `SessionStoreInterface` there is NO
|
|
637
819
|
* idle-TTL / eviction — a persisted run-state is durable orchestration state that lives until an
|
|
638
820
|
* explicit `delete`. The public surface is EXACTLY `get` / `set` / `delete` — no extra members (the
|
|
639
|
-
*
|
|
821
|
+
* guide's method bijection with {@link WorkflowStoreInterface}). Restore stays a caller concern: read a
|
|
640
822
|
* snapshot back and rebuild the live tree with {@link import('../factories.js').createRestoredWorkflow}.
|
|
641
823
|
*
|
|
642
824
|
* @example
|
|
@@ -655,25 +837,25 @@ export declare function createWorkflowRunner(options?: WorkflowRunnerOptions): W
|
|
|
655
837
|
export declare class DatabaseWorkflowStore implements WorkflowStoreInterface {
|
|
656
838
|
#private;
|
|
657
839
|
/**
|
|
658
|
-
*
|
|
840
|
+
* Wraps a table as a workflow store.
|
|
659
841
|
*
|
|
660
842
|
* @param table - The {@link TableInterface} holding the snapshots — its row is the
|
|
661
843
|
* {@link WorkflowSnapshotRow} `{ id; snapshot }` shape (the snapshot one opaque JSON column)
|
|
662
844
|
*/
|
|
663
845
|
constructor(table: TableInterface<WorkflowSnapshotRow>);
|
|
664
|
-
/**
|
|
846
|
+
/** Resolves and key-checks the snapshot for `id`, narrowing the opaque column to `WorkflowSnapshot`. */
|
|
665
847
|
get(id: string): Promise<WorkflowSnapshot | undefined>;
|
|
666
|
-
/**
|
|
848
|
+
/** Inserts or replaces under the snapshot's OWN `id` (no separate id param) — the row is `{ id, snapshot }`. */
|
|
667
849
|
set(snapshot: WorkflowSnapshot): Promise<void>;
|
|
668
|
-
/**
|
|
850
|
+
/** Drops a snapshot by id; an absent id is a no-op (no throw). */
|
|
669
851
|
delete(id: string): Promise<void>;
|
|
670
852
|
}
|
|
671
853
|
|
|
672
|
-
/**
|
|
854
|
+
/** Names the default {@link import('./types.js').WorkflowDefinition.bail} — graceful (continue on a leaf failure). */
|
|
673
855
|
export declare const DEFAULT_BAIL = false;
|
|
674
856
|
|
|
675
857
|
/**
|
|
676
|
-
*
|
|
858
|
+
* Names the default per-phase task concurrency the {@link import('./factories.js').createWorkflowRunner}
|
|
677
859
|
* runner applies when a {@link import('./types.js').PhaseDefinition} omits its `concurrency`
|
|
678
860
|
* throttle — a cap that is effectively unbounded for any realistic phase.
|
|
679
861
|
*
|
|
@@ -694,32 +876,20 @@ export declare const DEFAULT_BAIL = false;
|
|
|
694
876
|
export declare const DEFAULT_PHASE_CONCURRENCY = 1024;
|
|
695
877
|
|
|
696
878
|
/**
|
|
697
|
-
*
|
|
698
|
-
* is exposed to the caller instead of being buried in an executor closure.
|
|
699
|
-
*
|
|
700
|
-
* @typeParam T - The value the deferred's `promise` resolves
|
|
701
|
-
*/
|
|
702
|
-
export declare interface DeferredInterface<T> {
|
|
703
|
-
readonly promise: Promise<T>;
|
|
704
|
-
resolve(value: T): void;
|
|
705
|
-
reject(reason: unknown): void;
|
|
706
|
-
}
|
|
707
|
-
|
|
708
|
-
/**
|
|
709
|
-
* Convert a {@link WorkflowDefinition} into an INITIAL {@link WorkflowSnapshot} — every
|
|
879
|
+
* Converts a {@link WorkflowDefinition} into an INITIAL {@link WorkflowSnapshot} — every
|
|
710
880
|
* node `pending`, no results, empty metadata — so the live W-b tree has ONE construction
|
|
711
881
|
* path (snapshot-driven) for both a fresh build and a restore.
|
|
712
882
|
*
|
|
713
883
|
* @remarks
|
|
714
884
|
* The structural fields (`id` / `name` / `description` + the ordered phases / tasks)
|
|
715
885
|
* carry over verbatim, as does each phase's `concurrency` (persisted on the
|
|
716
|
-
* {@link PhaseSnapshot} so a restore reinstates the same throttle) and each task's `
|
|
886
|
+
* {@link PhaseSnapshot} so a restore reinstates the same throttle) and each task's `behavior` /
|
|
717
887
|
* `retries` / `timeout` (persisted on the {@link TaskSnapshot}, like `bail` / `concurrency`,
|
|
718
888
|
* so a restore + a {@link import('./types.js').WorkflowOptions.functions} registry resumes
|
|
719
889
|
* real work). The `bail` policy carries over — at the
|
|
720
890
|
* workflow tier AND, per phase, the
|
|
721
891
|
* EFFECTIVE policy (`phase.bail ?? workflowBail`) on each {@link PhaseSnapshot} — so the seeded
|
|
722
|
-
* snapshot is self-contained; a fresh seed has no `override`. `created` / `updated` are stamped
|
|
892
|
+
* snapshot is self-contained; a fresh seed has no `override`. `created` / `updated` are stamped at that point.
|
|
723
893
|
* {@link import('./factories.js').createWorkflow} builds from this.
|
|
724
894
|
*
|
|
725
895
|
* The optional `bail` override is the EFFECTIVE workflow policy the tree will run under
|
|
@@ -736,16 +906,41 @@ export declare interface DeferredInterface<T> {
|
|
|
736
906
|
export declare function definitionToSnapshot(definition: WorkflowDefinition, bail?: boolean): WorkflowSnapshot;
|
|
737
907
|
|
|
738
908
|
/**
|
|
739
|
-
*
|
|
909
|
+
* Schedules the shared host timer boundary every scheduler backend resumes from.
|
|
910
|
+
*
|
|
911
|
+
* @remarks
|
|
912
|
+
* The one `setTimeout` / `clearTimeout` boundary in the package: the cross-environment
|
|
913
|
+
* {@link import('./Scheduler.js').Scheduler}, both Node primitives, and every browser backend's
|
|
914
|
+
* `delay` and macrotask fallback route here, so the timer is armed and cleared in one place. It
|
|
915
|
+
* composes {@link scheduleHost}, which owns listener safety, the cancellation race, the exact
|
|
916
|
+
* caller reason, and once-only settlement. It does NOT validate `ms`: the value passes straight to
|
|
917
|
+
* the host `setTimeout`, which clamps a negative value or `NaN` to about zero, so an
|
|
918
|
+
* out-of-domain `ms` resumes on the next host turn rather than throwing. Pass a non-negative
|
|
919
|
+
* finite `ms`.
|
|
920
|
+
*
|
|
921
|
+
* @param ms - The milliseconds to wait before resuming
|
|
922
|
+
* @param signal - Optional caller cancellation signal
|
|
923
|
+
* @returns A promise that resolves after `ms`, or rejects with the caller's exact abort reason
|
|
924
|
+
*
|
|
925
|
+
* @example
|
|
926
|
+
* ```ts
|
|
927
|
+
* const controller = new AbortController()
|
|
928
|
+
* await delayHost(0, controller.signal) // a real macrotask host turn
|
|
929
|
+
* ```
|
|
930
|
+
*/
|
|
931
|
+
export declare function delayHost(ms: number, signal?: AbortSignal): Promise<void>;
|
|
932
|
+
|
|
933
|
+
/**
|
|
934
|
+
* Derives the PENDING SUFFIX boundary of a positional list of {@link LifecycleStatus}es —
|
|
740
935
|
* the index of the first entry in the contiguous trailing run of `pending` entries.
|
|
741
936
|
*
|
|
742
937
|
* @remarks
|
|
743
|
-
* The native, hook-free replacement for a runner-installed cursor
|
|
938
|
+
* The native, hook-free replacement for a runner-installed cursor: a
|
|
744
939
|
* {@link import('./types.js').WorkflowInterface}'s `add` / `remove` / `move` / `update`
|
|
745
940
|
* reads this over its live phases' statuses to decide which positions are safe to edit.
|
|
746
941
|
* Because entries run SEQUENTIALLY (phases sequential, AGENTS determinism), every
|
|
747
942
|
* already-started entry forms a contiguous LEADING prefix and every still-`pending`
|
|
748
|
-
* entry forms the trailing suffix — so the boundary is
|
|
943
|
+
* entry forms the trailing suffix — so the boundary is the count of leading
|
|
749
944
|
* non-`pending` entries: the index of the first `pending` entry, or the full length when
|
|
750
945
|
* none is `pending` (nothing is safely editable). A `pending` container's entries are ALL
|
|
751
946
|
* `pending`, so the boundary is `0` and every position is naturally accepted — callers
|
|
@@ -764,7 +959,7 @@ export declare function definitionToSnapshot(definition: WorkflowDefinition, bai
|
|
|
764
959
|
export declare function deriveBoundary(statuses: readonly LifecycleStatus[]): number;
|
|
765
960
|
|
|
766
961
|
/**
|
|
767
|
-
*
|
|
962
|
+
* Derives a phase's status from its tasks' statuses (tasks are concurrent, so this
|
|
768
963
|
* is an order-insensitive reduction).
|
|
769
964
|
*
|
|
770
965
|
* @remarks
|
|
@@ -782,18 +977,18 @@ export declare function deriveBoundary(statuses: readonly LifecycleStatus[]): nu
|
|
|
782
977
|
* task makes the phase `failed`.
|
|
783
978
|
*
|
|
784
979
|
* @param tasks - The phase's task statuses, in any order
|
|
785
|
-
* @returns The derived {@link
|
|
980
|
+
* @returns The derived phase {@link LifecycleStatus}
|
|
786
981
|
*/
|
|
787
|
-
export declare function derivePhaseStatus(tasks: readonly
|
|
982
|
+
export declare function derivePhaseStatus(tasks: readonly LifecycleStatus[]): LifecycleStatus;
|
|
788
983
|
|
|
789
984
|
/**
|
|
790
|
-
*
|
|
985
|
+
* Derives a workflow's status from its phases' {@link PhaseDerivation}s — each phase's status
|
|
791
986
|
* paired with the EFFECTIVE `bail` it ran under (`phase.bail ?? workflow.bail`) — so the
|
|
792
987
|
* failure outcome is PER-PHASE-bail-aware (phases are sequential, but the derivation is an
|
|
793
988
|
* order-insensitive reduction over the settled set).
|
|
794
989
|
*
|
|
795
990
|
* @remarks
|
|
796
|
-
* `bail` is
|
|
991
|
+
* `bail` is a per-phase override, so it is carried on each
|
|
797
992
|
* {@link PhaseDerivation} rather than passed as one scalar. It is the ONLY axis that changes
|
|
798
993
|
* the failure outcome, decided per phase:
|
|
799
994
|
* - **A `failed` phase whose effective `bail` is `true` (halt)** propagates ⇒ the workflow is
|
|
@@ -812,12 +1007,12 @@ export declare function derivePhaseStatus(tasks: readonly TaskStatus[]): PhaseSt
|
|
|
812
1007
|
* else (all `skipped`) ⇒ `skipped`.
|
|
813
1008
|
*
|
|
814
1009
|
* @param phases - The workflow's per-phase {@link PhaseDerivation}s (status + effective bail), in any order
|
|
815
|
-
* @returns The derived {@link
|
|
1010
|
+
* @returns The derived workflow {@link LifecycleStatus}
|
|
816
1011
|
*/
|
|
817
|
-
export declare function deriveWorkflowStatus(phases: readonly PhaseDerivation[]):
|
|
1012
|
+
export declare function deriveWorkflowStatus(phases: readonly PhaseDerivation[]): LifecycleStatus;
|
|
818
1013
|
|
|
819
1014
|
/**
|
|
820
|
-
*
|
|
1015
|
+
* Normalizes an unknown thrown value to a non-empty persistence-safe message.
|
|
821
1016
|
*
|
|
822
1017
|
* @param error - The caught value
|
|
823
1018
|
* @returns A non-empty message without stack or cause data
|
|
@@ -825,7 +1020,7 @@ export declare function deriveWorkflowStatus(phases: readonly PhaseDerivation[])
|
|
|
825
1020
|
export declare function errorToMessage(error: unknown): string;
|
|
826
1021
|
|
|
827
1022
|
/**
|
|
828
|
-
*
|
|
1023
|
+
* Boxes an error as a {@link Failure} — the graceful outcome half of a {@link Result}.
|
|
829
1024
|
*
|
|
830
1025
|
* @typeParam E - The boxed error's type
|
|
831
1026
|
* @param error - The error to box
|
|
@@ -839,7 +1034,7 @@ export declare function errorToMessage(error: unknown): string;
|
|
|
839
1034
|
export declare function failure<E>(error: E): Failure<E>;
|
|
840
1035
|
|
|
841
1036
|
/**
|
|
842
|
-
*
|
|
1037
|
+
* Finds the first {@link TaskResult} in a positional list whose boxed outcome is a
|
|
843
1038
|
* `Failure` — the pure scan shared by a phase's and a workflow's derived-`failed`
|
|
844
1039
|
* `fail`-event lookup.
|
|
845
1040
|
*
|
|
@@ -847,8 +1042,8 @@ export declare function failure<E>(error: E): Failure<E>;
|
|
|
847
1042
|
* The shared leaf behind {@link import('./phases/Phase.js').Phase} and
|
|
848
1043
|
* {@link import('./Workflow.js').Workflow}'s own `#failure` — each gathers ITS tier's
|
|
849
1044
|
* results (a phase's own settled tasks, a workflow's flattened `results()`) and feeds
|
|
850
|
-
* them here; the tier-local method keeps the
|
|
851
|
-
* status
|
|
1045
|
+
* them here; the tier-local method keeps the invariant throw (a derived `failed`
|
|
1046
|
+
* status means a failing result exists) because throwing on `undefined` is
|
|
852
1047
|
* orchestration, not a leaf concern.
|
|
853
1048
|
*
|
|
854
1049
|
* @param results - The results to scan, in any order
|
|
@@ -862,30 +1057,33 @@ export declare function failure<E>(error: E): Failure<E>;
|
|
|
862
1057
|
export declare function findFailure(results: readonly TaskResult[]): TaskResult | undefined;
|
|
863
1058
|
|
|
864
1059
|
/**
|
|
865
|
-
*
|
|
1060
|
+
* Tests that every named task has a callable runtime handler before dispatch.
|
|
866
1061
|
*
|
|
867
1062
|
* @remarks
|
|
868
|
-
* A snapshot lookup reads each unique `
|
|
1063
|
+
* A snapshot lookup reads each unique `behavior` binding at most once from `functions`. A live workflow
|
|
869
1064
|
* validates its tasks' already-resolved handlers without consulting the retained registry again.
|
|
1065
|
+
* `functions` belongs to the snapshot overload alone; the live-workflow overload takes no registry
|
|
1066
|
+
* and reads each task's already-resolved `handler`.
|
|
870
1067
|
*
|
|
871
1068
|
* @param workflow - The persisted snapshot or constructed live workflow to validate
|
|
872
|
-
* @
|
|
1069
|
+
* @param functions - The behavior registry the snapshot overload resolves each unique `behavior`
|
|
1070
|
+
* name against; omitted or `undefined` leaves every named task unresolved
|
|
1071
|
+
* @returns True if every named task resolves to a callable handler; false otherwise
|
|
873
1072
|
*/
|
|
874
1073
|
export declare function hasWorkflowHandlers(workflow: WorkflowInterface): boolean;
|
|
875
1074
|
|
|
876
|
-
export declare function hasWorkflowHandlers(workflow: WorkflowSnapshot, functions:
|
|
1075
|
+
export declare function hasWorkflowHandlers(workflow: WorkflowSnapshot, functions: WorkflowRegistry | undefined): boolean;
|
|
877
1076
|
|
|
878
1077
|
/**
|
|
879
|
-
*
|
|
1078
|
+
* Inserts one `[key, value]` entry at a positional index into a readonly entries array —
|
|
880
1079
|
* the pure splice-in step behind an insertion-ordered registry's `add`.
|
|
881
1080
|
*
|
|
882
1081
|
* @remarks
|
|
883
|
-
*
|
|
884
|
-
*
|
|
885
|
-
*
|
|
886
|
-
*
|
|
887
|
-
*
|
|
888
|
-
* mutate `entries`; returns a new array.
|
|
1082
|
+
* Used by the shared {@link import('./Collection.js').Collection} store both managers hold: it
|
|
1083
|
+
* converts its insertion-ordered `Map` to `[...map.entries()]`, calls this to splice the new entry
|
|
1084
|
+
* in at the target index, then rebuilds the `Map` from the result (a stateful step that stays a
|
|
1085
|
+
* `#` private method — this helper does no `Map` construction). Does not mutate `entries`;
|
|
1086
|
+
* returns a new array.
|
|
889
1087
|
*
|
|
890
1088
|
* @typeParam T - The entry's value type
|
|
891
1089
|
* @param entries - The current positional entries, in order
|
|
@@ -901,56 +1099,269 @@ export declare function hasWorkflowHandlers(workflow: WorkflowSnapshot, function
|
|
|
901
1099
|
*/
|
|
902
1100
|
export declare function insertEntry<T>(entries: ReadonlyArray<readonly [string, T]>, index: number, key: string, value: T): ReadonlyArray<readonly [string, T]>;
|
|
903
1101
|
|
|
904
|
-
/**
|
|
1102
|
+
/**
|
|
1103
|
+
* Tests whether a naturally-finished run may force its workflow `completed`.
|
|
1104
|
+
*
|
|
1105
|
+
* @remarks
|
|
1106
|
+
* A run that walked every phase and still derives `pending` executed nothing — zero phases, or
|
|
1107
|
+
* every phase empty — so it is vacuously done and the run settles it `completed`. Gated on
|
|
1108
|
+
* EXACTLY `pending` so a real `completed`, a `bail: true` `failed`, a `stopped`, or a derived
|
|
1109
|
+
* `skipped` is never overridden. The tree-is-empty half of the rule is
|
|
1110
|
+
* {@link WorkflowInterface.complete}'s own guard, which refuses a pending tree that still holds
|
|
1111
|
+
* tasks.
|
|
1112
|
+
*
|
|
1113
|
+
* @param workflow - The live workflow the run has finished walking
|
|
1114
|
+
* @returns True if the run may force the vacuous completion; false otherwise
|
|
1115
|
+
*
|
|
1116
|
+
* @example
|
|
1117
|
+
* ```ts
|
|
1118
|
+
* isCompletable(createWorkflow({ id: 'w', name: 'W', phases: [] })) // true
|
|
1119
|
+
* ```
|
|
1120
|
+
*/
|
|
1121
|
+
export declare function isCompletable(workflow: WorkflowInterface): boolean;
|
|
1122
|
+
|
|
1123
|
+
/**
|
|
1124
|
+
* Tests whether a driving run must stop giving a workflow more work.
|
|
1125
|
+
*
|
|
1126
|
+
* @remarks
|
|
1127
|
+
* The halt gate a {@link import('./WorkflowRunner.js').WorkflowRunner} consults before starting a
|
|
1128
|
+
* phase, before dispatching a task, and after every cooperative gate. A workflow is halted after
|
|
1129
|
+
* its derived status is terminal but NOT `completed` — a `bail: true` failure, a caller's own
|
|
1130
|
+
* graceful `stop()`, or a forced `skip`. `completed` is excluded deliberately: a workflow that
|
|
1131
|
+
* completed vacuously is settled, not halted, and the distinction is what keeps the run from
|
|
1132
|
+
* sweeping a finished tree. When a `phase` is supplied, its own forced `skipped` / `stopped` halts
|
|
1133
|
+
* that phase's work too; a `failed` phase does not, because the workflow's own `bail` policy
|
|
1134
|
+
* decides whether a failed phase ends the run.
|
|
1135
|
+
*
|
|
1136
|
+
* @param workflow - The live workflow the run is driving
|
|
1137
|
+
* @param phase - The phase whose own forced terminal status also halts its tasks
|
|
1138
|
+
* @returns True if the run must stop giving this workflow (or phase) more work; false otherwise
|
|
1139
|
+
*
|
|
1140
|
+
* @example
|
|
1141
|
+
* ```ts
|
|
1142
|
+
* isHalted(workflow) // false while pending or running
|
|
1143
|
+
* workflow.stop()
|
|
1144
|
+
* isHalted(workflow) // true
|
|
1145
|
+
* ```
|
|
1146
|
+
*/
|
|
1147
|
+
export declare function isHalted(workflow: WorkflowInterface, phase?: PhaseInterface): boolean;
|
|
1148
|
+
|
|
1149
|
+
/**
|
|
1150
|
+
* Checks whether an unknown value belongs to the workflow lifecycle vocabulary.
|
|
1151
|
+
*
|
|
1152
|
+
* @remarks
|
|
1153
|
+
* Reads {@link import('./constants.js').LIFECYCLE_STATUSES}, the runtime array every tier draws
|
|
1154
|
+
* from, so the vocabulary has one definition rather than a hard-coded copy per guard.
|
|
1155
|
+
*
|
|
1156
|
+
* @param value - The value to test
|
|
1157
|
+
* @returns True if `value` is a {@link LifecycleStatus}; false otherwise
|
|
1158
|
+
*
|
|
1159
|
+
* @example
|
|
1160
|
+
* ```ts
|
|
1161
|
+
* isLifecycleStatus('running') // true
|
|
1162
|
+
* isLifecycleStatus('paused') // false
|
|
1163
|
+
* ```
|
|
1164
|
+
*/
|
|
905
1165
|
export declare function isLifecycleStatus(value: unknown): value is LifecycleStatus;
|
|
906
1166
|
|
|
907
1167
|
/**
|
|
908
|
-
*
|
|
1168
|
+
* Validates a safe owned JSON graph as a coherent workflow snapshot.
|
|
909
1169
|
*
|
|
910
1170
|
* @remarks
|
|
911
1171
|
* Callers at hostile boundaries use {@link isWorkflowSnapshot}, which owns the
|
|
912
1172
|
* graph first so this semantic pass never observes accessors or prototypes.
|
|
1173
|
+
*
|
|
1174
|
+
* @param value - The already-owned JSON graph to validate
|
|
1175
|
+
* @returns True if `value` is a coherent {@link WorkflowSnapshot}; false otherwise
|
|
1176
|
+
*
|
|
1177
|
+
* @example
|
|
1178
|
+
* ```ts
|
|
1179
|
+
* isOwnedWorkflowSnapshot(workflow.snapshot()) // true
|
|
1180
|
+
* ```
|
|
913
1181
|
*/
|
|
914
1182
|
export declare function isOwnedWorkflowSnapshot(value: unknown): value is WorkflowSnapshot;
|
|
915
1183
|
|
|
916
1184
|
/**
|
|
917
|
-
*
|
|
1185
|
+
* Tests whether a task attempt is being genuinely cancelled rather than merely timed out.
|
|
1186
|
+
*
|
|
1187
|
+
* @remarks
|
|
1188
|
+
* The discriminator that keeps a per-attempt deadline off the skip path. Three causes fire a
|
|
1189
|
+
* running task's folded signal, and only two of them mean "skip this task": the task's own
|
|
1190
|
+
* `signal` (its `stop` / `skip`), and the unit or run signal (a sibling fail-fast under
|
|
1191
|
+
* `bail: true`, or a run-level abort / timeout / budget / `destroy`). A bare per-attempt timeout
|
|
1192
|
+
* fires NEITHER — it aborts only the deadline portion of the attempt signal — so it stays a
|
|
1193
|
+
* retryable failure of that attempt instead of skipping the leaf and losing the recorded fault.
|
|
1194
|
+
* Read fresh at each call so a cancel that lands mid-dispatch is seen.
|
|
1195
|
+
*
|
|
1196
|
+
* @param task - The live task the attempt is driving
|
|
1197
|
+
* @param controller - The substrate unit handle carrying the unit-level abort
|
|
1198
|
+
* @param runSignal - The run's folded cancellation signal
|
|
1199
|
+
* @returns True if the attempt is being genuinely cancelled; false otherwise
|
|
1200
|
+
*
|
|
1201
|
+
* @example
|
|
1202
|
+
* ```ts
|
|
1203
|
+
* isSkipping(task, controller, runSignal) // false until a cancel fires
|
|
1204
|
+
* ```
|
|
1205
|
+
*/
|
|
1206
|
+
export declare function isSkipping(task: TaskInterface, controller: ControllerInterface<TaskInterface, void>, runSignal: AbortSignal): boolean;
|
|
1207
|
+
|
|
1208
|
+
/**
|
|
1209
|
+
* Tests whether forcing a workflow `stopped` would still record something.
|
|
1210
|
+
*
|
|
1211
|
+
* @remarks
|
|
1212
|
+
* `stop()` is a no-op after a workflow's status becomes terminal, so a run that must record a
|
|
1213
|
+
* cancellation forces it only while this holds. It is NOT the negation of
|
|
1214
|
+
* {@link isTerminalStatus}: `completed` and `skipped` both pass, because a run-level cancel that
|
|
1215
|
+
* lands on a vacuously-completed or fully-skipped tree still records `stopped` as the outcome the
|
|
1216
|
+
* caller asked for. Only an already-`failed` or already-`stopped` workflow has a terminal state
|
|
1217
|
+
* worth keeping.
|
|
1218
|
+
*
|
|
1219
|
+
* @param workflow - The live workflow a run-level cancel would force
|
|
1220
|
+
* @returns True if forcing `stopped` would change the recorded outcome; false otherwise
|
|
1221
|
+
*
|
|
1222
|
+
* @example
|
|
1223
|
+
* ```ts
|
|
1224
|
+
* isStoppable(workflow) // true while pending, running, completed, or skipped
|
|
1225
|
+
* workflow.stop()
|
|
1226
|
+
* isStoppable(workflow) // false
|
|
1227
|
+
* ```
|
|
1228
|
+
*/
|
|
1229
|
+
export declare function isStoppable(workflow: WorkflowInterface): boolean;
|
|
1230
|
+
|
|
1231
|
+
/**
|
|
1232
|
+
* Tests whether an unknown value is valid persisted task activity.
|
|
1233
|
+
*
|
|
1234
|
+
* @remarks
|
|
1235
|
+
* The persisted counterpart of {@link isTaskActivityInput}: the same frame plus the REQUIRED
|
|
1236
|
+
* `operations`, `constraints`, and a finite non-negative `updated` stamp, because a stored frame
|
|
1237
|
+
* has already been accepted and normalized. Total — a hostile prototype or accessor answers
|
|
1238
|
+
* `false` rather than throwing.
|
|
1239
|
+
*
|
|
1240
|
+
* @param value - The value to test
|
|
1241
|
+
* @returns True if `value` is a persisted {@link TaskActivity}; false otherwise
|
|
1242
|
+
*
|
|
1243
|
+
* @example
|
|
1244
|
+
* ```ts
|
|
1245
|
+
* isTaskActivity({ operations: [], constraints: [], updated: 1 }) // true
|
|
1246
|
+
* ```
|
|
918
1247
|
*/
|
|
919
1248
|
export declare function isTaskActivity(value: unknown): value is TaskActivity;
|
|
920
1249
|
|
|
921
1250
|
/**
|
|
922
|
-
*
|
|
1251
|
+
* Tests whether an unknown value is a valid whole-frame activity report.
|
|
1252
|
+
*
|
|
1253
|
+
* @remarks
|
|
1254
|
+
* The guard behind {@link import('./types.js').TaskInterface.report}: exactly the optional `note`,
|
|
1255
|
+
* `progress`, `operations`, and `constraints` keys, with the two claim lists checked by
|
|
1256
|
+
* {@link isTaskClaimList} and `progress` a finite non-negative value under an optional `total` at
|
|
1257
|
+
* least as large. Total — a hostile prototype or accessor answers `false` rather than throwing.
|
|
1258
|
+
*
|
|
1259
|
+
* @param value - The value to test
|
|
1260
|
+
* @returns True if `value` is a valid {@link TaskActivityInput}; false otherwise
|
|
1261
|
+
*
|
|
1262
|
+
* @example
|
|
1263
|
+
* ```ts
|
|
1264
|
+
* isTaskActivityInput({ note: 'compiling', progress: { progress: 2, total: 5 } }) // true
|
|
1265
|
+
* ```
|
|
923
1266
|
*/
|
|
924
1267
|
export declare function isTaskActivityInput(value: unknown): value is TaskActivityInput;
|
|
925
1268
|
|
|
926
|
-
/**
|
|
1269
|
+
/**
|
|
1270
|
+
* Checks whether an unknown value is a valid list of task activity claims.
|
|
1271
|
+
*
|
|
1272
|
+
* @remarks
|
|
1273
|
+
* The one guard behind both claim lists of a {@link TaskActivityInput} — its `operations` and its
|
|
1274
|
+
* `constraints` — because {@link import('./types.js').TaskOperation} and
|
|
1275
|
+
* {@link import('./types.js').TaskConstraint} are the same {@link TaskClaim} shape. Every member must be a plain record carrying exactly `id`, `name`, and
|
|
1276
|
+
* `started`, with non-empty string `id` and `name`, a finite non-negative `started`, and an `id`
|
|
1277
|
+
* unique within the list. Total: a hostile prototype, an accessor, or a cycle returns `false`
|
|
1278
|
+
* rather than throwing.
|
|
1279
|
+
*
|
|
1280
|
+
* @param value - The value to test
|
|
1281
|
+
* @returns True if `value` is a list of valid, uniquely identified claims; false otherwise
|
|
1282
|
+
*
|
|
1283
|
+
* @example
|
|
1284
|
+
* ```ts
|
|
1285
|
+
* isTaskClaimList([{ id: 'fetch', name: 'Fetch', started: 1 }]) // true
|
|
1286
|
+
* isTaskClaimList([{ id: 'fetch', name: 'Fetch' }]) // false
|
|
1287
|
+
* ```
|
|
1288
|
+
*/
|
|
1289
|
+
export declare function isTaskClaimList(value: unknown): value is readonly TaskClaim[];
|
|
1290
|
+
|
|
1291
|
+
/**
|
|
1292
|
+
* Tests a normalized persisted task failure.
|
|
1293
|
+
*
|
|
1294
|
+
* @remarks
|
|
1295
|
+
* The exact-record guard behind a persisted {@link TaskFailure}: exactly `origin` and `message`,
|
|
1296
|
+
* an `origin` drawn from the {@link import('./types.js').TaskFailureOrigin} vocabulary, and a
|
|
1297
|
+
* non-empty `message`. Total — a hostile prototype or accessor answers `false` rather than
|
|
1298
|
+
* throwing.
|
|
1299
|
+
*
|
|
1300
|
+
* @param value - The value to test
|
|
1301
|
+
* @returns True if `value` is a persisted {@link TaskFailure}; false otherwise
|
|
1302
|
+
*
|
|
1303
|
+
* @example
|
|
1304
|
+
* ```ts
|
|
1305
|
+
* isTaskFailure({ origin: 'handler', message: 'boom' }) // true
|
|
1306
|
+
* isTaskFailure({ origin: 'handler' }) // false
|
|
1307
|
+
* ```
|
|
1308
|
+
*/
|
|
927
1309
|
export declare function isTaskFailure(value: unknown): value is TaskFailure;
|
|
928
1310
|
|
|
929
|
-
/**
|
|
1311
|
+
/**
|
|
1312
|
+
* Tests a result's lineage against its containing snapshot nodes.
|
|
1313
|
+
*
|
|
1314
|
+
* @remarks
|
|
1315
|
+
* The four arguments are the result and the three snapshot nodes it claims to belong to, read
|
|
1316
|
+
* from the OUTSIDE in: a {@link TaskResult} is self-describing, so restoring one is only safe
|
|
1317
|
+
* when every identity it carries agrees with the tree it was found in. It checks the exact key
|
|
1318
|
+
* set at each level, that `status` equals the owning task's, and that the `task` / `phase` /
|
|
1319
|
+
* `workflow` contexts — including the nested `task.phase.workflow` lineage — carry the same `id`,
|
|
1320
|
+
* `name`, and `description` as the nodes containing them. It then requires the boxed outcome to
|
|
1321
|
+
* match the status: a `Success` holding JSON for `completed`, a `Failure` holding a
|
|
1322
|
+
* {@link TaskFailure} for `failed`, and nothing for any other status. Total — a hostile
|
|
1323
|
+
* prototype, accessor, or cycle answers `false` rather than throwing.
|
|
1324
|
+
*
|
|
1325
|
+
* @param value - The candidate {@link TaskResult}
|
|
1326
|
+
* @param workflow - The workflow snapshot node containing it
|
|
1327
|
+
* @param phase - The phase snapshot node containing it
|
|
1328
|
+
* @param task - The task snapshot node the result belongs to
|
|
1329
|
+
* @returns True if `value` is a {@link TaskResult} whose lineage and outcome match
|
|
1330
|
+
* those nodes; false otherwise
|
|
1331
|
+
*
|
|
1332
|
+
* @example
|
|
1333
|
+
* ```ts
|
|
1334
|
+
* const snapshot = workflow.snapshot()
|
|
1335
|
+
* const phase = snapshot.phases[0]
|
|
1336
|
+
* const task = phase?.tasks[0]
|
|
1337
|
+
* isTaskResult(task?.result, snapshot, phase, task) // true for a settled task
|
|
1338
|
+
* ```
|
|
1339
|
+
*/
|
|
930
1340
|
export declare function isTaskResult(value: unknown, workflow: unknown, phase: unknown, task: unknown): value is TaskResult;
|
|
931
1341
|
|
|
932
1342
|
/**
|
|
933
|
-
*
|
|
1343
|
+
* Tests whether a {@link LifecycleStatus} is TERMINAL — a node in this state will not
|
|
934
1344
|
* transition further.
|
|
935
1345
|
*
|
|
936
1346
|
* @remarks
|
|
937
|
-
* The ONE terminal check across
|
|
1347
|
+
* The ONE terminal check across every tier (AGENTS.md § Design laws, "one concept, one term"):
|
|
938
1348
|
* a task, a phase, and a workflow share the same {@link LifecycleStatus} vocabulary, so a
|
|
939
1349
|
* single predicate covers them — {@link derivePhaseStatus} and {@link deriveWorkflowStatus}
|
|
940
|
-
* both consult it to tell a settled node from an in-flight one.
|
|
941
|
-
* `
|
|
942
|
-
* `
|
|
1350
|
+
* both consult it to tell a settled node from an in-flight one. It reads the terminal set from
|
|
1351
|
+
* {@link import('./constants.js').TERMINAL_STATUSES} (`completed` / `failed` / `skipped` /
|
|
1352
|
+
* `stopped`), so that constant is the one definition; the only non-terminal states are `pending`
|
|
1353
|
+
* and `running`.
|
|
943
1354
|
*
|
|
944
1355
|
* @param status - The lifecycle status to test (a task / phase / workflow status)
|
|
945
|
-
* @returns
|
|
1356
|
+
* @returns True if the status is terminal; false otherwise
|
|
946
1357
|
*/
|
|
947
1358
|
export declare function isTerminalStatus(status: LifecycleStatus): boolean;
|
|
948
1359
|
|
|
949
1360
|
/**
|
|
950
|
-
*
|
|
1361
|
+
* Narrows an unknown caught value to a {@link WorkflowError}.
|
|
951
1362
|
*
|
|
952
1363
|
* @param value - The value to test (typically a `catch` binding)
|
|
953
|
-
* @returns
|
|
1364
|
+
* @returns True if `value` is a {@link WorkflowError}; false otherwise
|
|
954
1365
|
*
|
|
955
1366
|
* @example
|
|
956
1367
|
* ```ts
|
|
@@ -963,41 +1374,112 @@ export declare function isTerminalStatus(status: LifecycleStatus): boolean;
|
|
|
963
1374
|
*/
|
|
964
1375
|
export declare function isWorkflowError(value: unknown): value is WorkflowError;
|
|
965
1376
|
|
|
966
|
-
/**
|
|
1377
|
+
/**
|
|
1378
|
+
* Checks whether an unknown value is a live workflow entity rather than a definition.
|
|
1379
|
+
*
|
|
1380
|
+
* @remarks
|
|
1381
|
+
* The discriminator behind the overloaded
|
|
1382
|
+
* {@link import('./types.js').WorkflowRunnerInterface.execute}: a
|
|
1383
|
+
* {@link import('./types.js').WorkflowInterface} is the only one of the two carrying `destroyed`
|
|
1384
|
+
* (RUNTIME-ONLY, never a field on the pure-JSON
|
|
1385
|
+
* {@link import('./types.js').WorkflowDefinition}) AND a callable `snapshot`. Requiring both is
|
|
1386
|
+
* sturdier than `destroyed` alone — a definition could coincidentally carry a `destroyed` field as
|
|
1387
|
+
* arbitrary data, and pairing it with a function-typed `snapshot` narrows to the actual entity
|
|
1388
|
+
* shape without an `as`. It reads a live class instance, so it tests object identity rather than a
|
|
1389
|
+
* plain-record brand, and it is total: any other value answers `false`.
|
|
1390
|
+
*
|
|
1391
|
+
* @param value - The value to test
|
|
1392
|
+
* @returns True if `value` is a live {@link WorkflowInterface}; false otherwise
|
|
1393
|
+
*
|
|
1394
|
+
* @example
|
|
1395
|
+
* ```ts
|
|
1396
|
+
* isWorkflowInterface(createWorkflow(definition)) // true
|
|
1397
|
+
* isWorkflowInterface(definition) // false
|
|
1398
|
+
* ```
|
|
1399
|
+
*/
|
|
1400
|
+
export declare function isWorkflowInterface(value: unknown): value is WorkflowInterface;
|
|
1401
|
+
|
|
1402
|
+
/**
|
|
1403
|
+
* Guards the hostile boundary totally for a workflow snapshot.
|
|
1404
|
+
*
|
|
1405
|
+
* @remarks
|
|
1406
|
+
* Owns the value first through the exact-JSON clone of `@orkestrel/contract`, then runs the
|
|
1407
|
+
* semantic pass {@link isOwnedWorkflowSnapshot} over the owned copy — so no accessor, prototype,
|
|
1408
|
+
* or cycle in the caller's graph is ever observed by the semantic pass. Total: an unclonable
|
|
1409
|
+
* value answers `false` rather than throwing.
|
|
1410
|
+
*
|
|
1411
|
+
* @param value - The untrusted value to test
|
|
1412
|
+
* @returns True if `value` is a coherent {@link WorkflowSnapshot}; false otherwise
|
|
1413
|
+
*
|
|
1414
|
+
* @example
|
|
1415
|
+
* ```ts
|
|
1416
|
+
* isWorkflowSnapshot(JSON.parse(payload)) // true only for a coherent snapshot
|
|
1417
|
+
* ```
|
|
1418
|
+
*/
|
|
967
1419
|
export declare function isWorkflowSnapshot(value: unknown): value is WorkflowSnapshot;
|
|
968
1420
|
|
|
969
1421
|
/**
|
|
970
|
-
*
|
|
1422
|
+
* Lists every {@link LifecycleStatus} value, frozen — the vocabulary every tier draws from.
|
|
1423
|
+
*
|
|
1424
|
+
* @remarks
|
|
1425
|
+
* Ordered pending → running → terminal (`completed` / `failed` / `skipped` /
|
|
1426
|
+
* `stopped`). The runtime source of truth for the union:
|
|
1427
|
+
* {@link import('./validators.js').isLifecycleStatus} reads this array.
|
|
1428
|
+
*/
|
|
1429
|
+
export declare const LIFECYCLE_STATUSES: readonly LifecycleStatus[];
|
|
1430
|
+
|
|
1431
|
+
/**
|
|
1432
|
+
* Names the shared lifecycle vocabulary every tier draws from — `pending` before it runs,
|
|
971
1433
|
* `running` while in flight, then one of the terminal states `completed` / `failed` /
|
|
972
1434
|
* `skipped` / `stopped`.
|
|
973
1435
|
*
|
|
974
1436
|
* @remarks
|
|
975
|
-
* The ONE literal set
|
|
976
|
-
*
|
|
977
|
-
*
|
|
978
|
-
*
|
|
979
|
-
* {@link
|
|
980
|
-
* `
|
|
981
|
-
*
|
|
982
|
-
*
|
|
1437
|
+
* The ONE literal set the workflow, phase, and task tiers all draw from, so the vocabulary
|
|
1438
|
+
* lives in one place and a signature reading `LifecycleStatus` means the same thing at
|
|
1439
|
+
* every tier. Each member's tier-specific meaning belongs to the member that declares it:
|
|
1440
|
+
* `skipped` is "deliberately not run" and `stopped` is "ended early", and the terminal
|
|
1441
|
+
* members for which a {@link TaskResult} is meaningful are exactly `completed` and
|
|
1442
|
+
* `failed`, which box a {@link Result}, while `skipped` and `stopped` settle without a
|
|
1443
|
+
* boxed outcome. It also types the single runtime terminal check
|
|
1444
|
+
* {@link import('./helpers.js').isTerminalStatus}, which therefore accepts a value from
|
|
1445
|
+
* any tier.
|
|
983
1446
|
*/
|
|
984
1447
|
export declare type LifecycleStatus = 'pending' | 'running' | 'completed' | 'failed' | 'skipped' | 'stopped';
|
|
985
1448
|
|
|
986
|
-
/**
|
|
1449
|
+
/**
|
|
1450
|
+
* Compares two optional description values.
|
|
1451
|
+
*
|
|
1452
|
+
* @remarks
|
|
1453
|
+
* The equality rule a lineage check needs: two descriptions match when they are the same value
|
|
1454
|
+
* AND that value is either a string or genuine absence. Anything else — a number, an object, a
|
|
1455
|
+
* `null` — never matches, even against itself, so a lineage stamped with a non-string description
|
|
1456
|
+
* is rejected rather than silently accepted.
|
|
1457
|
+
*
|
|
1458
|
+
* @param left - The first description value
|
|
1459
|
+
* @param right - The second description value
|
|
1460
|
+
* @returns True if both are the same string or both absent; false otherwise
|
|
1461
|
+
*
|
|
1462
|
+
* @example
|
|
1463
|
+
* ```ts
|
|
1464
|
+
* matchesDescription('build', 'build') // true
|
|
1465
|
+
* matchesDescription(undefined, undefined) // true
|
|
1466
|
+
* matchesDescription('build', undefined) // false
|
|
1467
|
+
* ```
|
|
1468
|
+
*/
|
|
987
1469
|
export declare function matchesDescription(left: unknown, right: unknown): boolean;
|
|
988
1470
|
|
|
989
1471
|
/**
|
|
990
|
-
*
|
|
1472
|
+
* Names the largest delay representable by the host timer APIs without overflow or clamping.
|
|
991
1473
|
*/
|
|
992
1474
|
export declare const MAX_TIMER_MS = 2147483647;
|
|
993
1475
|
|
|
994
1476
|
/**
|
|
995
|
-
*
|
|
1477
|
+
* Implements the in-memory {@link WorkflowStoreInterface} — a process-lifetime `Map` of
|
|
996
1478
|
* {@link WorkflowSnapshot}s keyed by workflow id, the DEFAULT store
|
|
997
1479
|
* {@link import('../factories.js').createMemoryWorkflowStore} builds.
|
|
998
1480
|
*
|
|
999
1481
|
* @remarks
|
|
1000
|
-
* A plain `Map<string, WorkflowSnapshot>` (
|
|
1482
|
+
* A plain `Map<string, WorkflowSnapshot>` (the snapshot is already pure,
|
|
1001
1483
|
* self-contained JSON, so no encoding is needed for the memory tier). UNLIKE the server
|
|
1002
1484
|
* package's `SessionStoreInterface`'s memory store there is
|
|
1003
1485
|
* NO idle-TTL and NO eviction: a persisted workflow run-state is durable orchestration state
|
|
@@ -1013,7 +1495,7 @@ export declare const MAX_TIMER_MS = 2147483647;
|
|
|
1013
1495
|
* - **`set` inserts / replaces under the snapshot's OWN `id`** (no separate id param).
|
|
1014
1496
|
* - **`delete` drops a snapshot by id**; an absent id is a no-op (no throw).
|
|
1015
1497
|
*
|
|
1016
|
-
* The public surface is EXACTLY `get` / `set` / `delete` — no extra members (the
|
|
1498
|
+
* The public surface is EXACTLY `get` / `set` / `delete` — no extra members (the guide's method
|
|
1017
1499
|
* bijection with {@link WorkflowStoreInterface}). Restore is a caller concern: read a snapshot
|
|
1018
1500
|
* back and rebuild the live tree with {@link import('../factories.js').createRestoredWorkflow}.
|
|
1019
1501
|
*
|
|
@@ -1037,16 +1519,17 @@ export declare class MemoryWorkflowStore implements WorkflowStoreInterface {
|
|
|
1037
1519
|
}
|
|
1038
1520
|
|
|
1039
1521
|
/**
|
|
1040
|
-
*
|
|
1522
|
+
* Repositions the entry keyed `key` to a new positional index in a readonly entries
|
|
1041
1523
|
* array — the pure remove-then-reinsert step behind an insertion-ordered registry's
|
|
1042
1524
|
* `move`.
|
|
1043
1525
|
*
|
|
1044
1526
|
* @remarks
|
|
1045
1527
|
* The move counterpart of {@link insertEntry}: finds the entry by `key`, splices it
|
|
1046
1528
|
* out, then splices it back in at `index`. An absent `key` is a no-op (returns a copy
|
|
1047
|
-
* of `entries` unchanged) — the caller
|
|
1048
|
-
* already gates on the target's
|
|
1049
|
-
*
|
|
1529
|
+
* of `entries` unchanged) — the caller, the shared
|
|
1530
|
+
* {@link import('./Collection.js').Collection} store's `move`, already gates on the target's
|
|
1531
|
+
* existence before calling this, so the no-op branch is defensive, never reached in practice.
|
|
1532
|
+
* Does not mutate `entries`; returns a new array.
|
|
1050
1533
|
*
|
|
1051
1534
|
* @typeParam T - The entry's value type
|
|
1052
1535
|
* @param entries - The current positional entries, in order
|
|
@@ -1062,7 +1545,31 @@ export declare class MemoryWorkflowStore implements WorkflowStoreInterface {
|
|
|
1062
1545
|
export declare function moveEntry<T>(entries: ReadonlyArray<readonly [string, T]>, key: string, index: number): ReadonlyArray<readonly [string, T]>;
|
|
1063
1546
|
|
|
1064
1547
|
/**
|
|
1065
|
-
*
|
|
1548
|
+
* Tests whether one attempt still owns the task it launched.
|
|
1549
|
+
*
|
|
1550
|
+
* @remarks
|
|
1551
|
+
* A retried task is re-dispatched while an earlier attempt's handler may still be resolving, so
|
|
1552
|
+
* every settlement path re-checks ownership before touching the leaf. Ownership needs BOTH
|
|
1553
|
+
* halves: the run-local `owners` ledger must still name this attempt, and the live task's own
|
|
1554
|
+
* `attempts` tally must still match it. A superseded attempt reads `false` and returns without
|
|
1555
|
+
* recording anything, so a late resolution can never overwrite the newer attempt's outcome.
|
|
1556
|
+
*
|
|
1557
|
+
* @param owners - The run-local ledger of the attempt owning each task id
|
|
1558
|
+
* @param task - The live task the attempt launched
|
|
1559
|
+
* @param attempt - The one-based attempt number to test
|
|
1560
|
+
* @returns True if `attempt` still owns `task`; false otherwise
|
|
1561
|
+
*
|
|
1562
|
+
* @example
|
|
1563
|
+
* ```ts
|
|
1564
|
+
* const owners = new Map([[task.id, 1]])
|
|
1565
|
+
* ownsAttempt(owners, task, 1) // true while the task's own `attempts` is 1
|
|
1566
|
+
* ownsAttempt(owners, task, 2) // false
|
|
1567
|
+
* ```
|
|
1568
|
+
*/
|
|
1569
|
+
export declare function ownsAttempt(owners: Map<string, number>, task: TaskInterface, attempt: number): boolean;
|
|
1570
|
+
|
|
1571
|
+
/**
|
|
1572
|
+
* Parks until `signal` aborts — a promise-parked wait, never a timer or
|
|
1066
1573
|
* busy-loop, that NEVER rejects.
|
|
1067
1574
|
*
|
|
1068
1575
|
* @remarks
|
|
@@ -1072,7 +1579,7 @@ export declare function moveEntry<T>(entries: ReadonlyArray<readonly [string, T]
|
|
|
1072
1579
|
* at every fold point.
|
|
1073
1580
|
*
|
|
1074
1581
|
* @param signal - The signal to park on
|
|
1075
|
-
* @returns A promise that resolves
|
|
1582
|
+
* @returns A promise that resolves after `signal` has aborted
|
|
1076
1583
|
*
|
|
1077
1584
|
* @example
|
|
1078
1585
|
* ```ts
|
|
@@ -1085,94 +1592,32 @@ export declare function moveEntry<T>(entries: ReadonlyArray<readonly [string, T]
|
|
|
1085
1592
|
export declare function parkSignal(signal: AbortSignal): Promise<void>;
|
|
1086
1593
|
|
|
1087
1594
|
/**
|
|
1088
|
-
*
|
|
1089
|
-
*
|
|
1090
|
-
* reactively as a task transitions (the middle tier of the cascade).
|
|
1595
|
+
* Lists the {@link WorkflowEventMap} / {@link PhaseEventMap} events that make a durable observer
|
|
1596
|
+
* re-persist the live tree, frozen.
|
|
1091
1597
|
*
|
|
1092
1598
|
* @remarks
|
|
1093
|
-
*
|
|
1094
|
-
*
|
|
1095
|
-
*
|
|
1096
|
-
*
|
|
1097
|
-
*
|
|
1098
|
-
|
|
1099
|
-
|
|
1100
|
-
* - **Children (AGENTS §9).** `tasks` is the lean {@link TaskManager} (an accessor + `count`,
|
|
1101
|
-
* no batch matrix); built positionally from the snapshot so order survives an interior `skip`.
|
|
1102
|
-
* `results()` collects the settled tasks' {@link TaskResult}s (the phase tier of the result
|
|
1103
|
-
* tree); `workflow` navigates UP to the live parent.
|
|
1104
|
-
* - **Observable (AGENTS §13).** The owned {@link emitter} ({@link PhaseEventMap}) fires
|
|
1105
|
-
* `start` / `complete` / `fail` / `pause` / `resume` / `skip` / `stop` after the
|
|
1106
|
-
* corresponding status or runtime-gate change. Status events fire after the phase recomputes
|
|
1107
|
-
* and before it escalates to the workflow, preserving child/phase cause before parent effect.
|
|
1108
|
-
* The emitter isolates a listener throw and routes it to its `error` handler (the `error`
|
|
1109
|
-
* option); `fail` carries the failing task's {@link TaskResult}.
|
|
1110
|
-
* - **Structural API (AGENTS §7).** `add` / `remove` / `move` / `update` gate BEFORE
|
|
1111
|
-
* delegating to {@link tasks} (the manager gates the target's own existence/status/id/
|
|
1112
|
-
* bounds), then emit the matching {@link PhaseEventMap} event on success only. NATIVE
|
|
1113
|
-
* gating, purely from this phase's own derived `status` (no runner-installed hook): while
|
|
1114
|
-
* `pending`, any valid `index` is accepted; while `running`, `add` accepts ONLY a pure
|
|
1115
|
-
* append (a live runner subscribed to the `add` event picks it up), and `remove` / `move` /
|
|
1116
|
-
* `update` always fail gracefully (the tasks are already handed to the execution
|
|
1117
|
-
* substrate); while terminal, everything is refused.
|
|
1118
|
-
* - **Patch (AGENTS §12).** `patch` applies a validated {@link PhaseUpdate} to SELF
|
|
1119
|
-
* (`name` / `description` / `concurrency` / `bail`) — defense-in-depth: it throws a
|
|
1120
|
-
* `MUTATION` {@link WorkflowError} unless this phase's own `status` is `pending`, mirroring
|
|
1121
|
-
* the owning {@link WorkflowInterface.update}'s gate.
|
|
1122
|
-
* - **Minting (AGENTS §7).** {@link add} MINTS a live {@link Task} from a {@link TaskDefinition}
|
|
1123
|
-
* (converts it to a {@link TaskSnapshot}, builds the task wired to THIS phase) — the same
|
|
1124
|
-
* construction path {@link #append} uses at build time, so a live mint and a restored/built
|
|
1125
|
-
* task are wired IDENTICALLY. At construction, the workflow-level
|
|
1126
|
-
* {@link import('../types.js').WorkflowFunctions} registry (threaded from
|
|
1127
|
-
* {@link import('../types.js').WorkflowOptions.functions}) resolves every unique initial `run`
|
|
1128
|
-
* name ONCE before any task is built; siblings sharing a name receive the exact same captured
|
|
1129
|
-
* runtime {@link import('../types.js').TaskInterface.handler}. A later live {@link add} reads
|
|
1130
|
-
* that name once from the retained registry at its own mint moment. An omitted or unregistered
|
|
1131
|
-
* `run` resolves to no handler; only omission is a no-op, while an unresolved present name makes
|
|
1132
|
-
* the containing tree non-drivable.
|
|
1133
|
-
* - **Runtime lifecycle (AGENTS §10).** `pause` / `resume` / `wait` mirror the workflow's own
|
|
1134
|
-
* quartet, scoped to this phase — a driving
|
|
1135
|
-
* {@link import('../types.js').WorkflowRunnerInterface.execute} gates a task's own
|
|
1136
|
-
* pre-dispatch on the workflow's gate FIRST, then this phase's gate, WITHOUT touching
|
|
1137
|
-
* {@link status} — `paused` is runtime-only, never persisted. `skip` / `stop` (this phase's
|
|
1138
|
-
* own terminal forcing) always release a parked {@link wait} waiter, mirroring
|
|
1139
|
-
* {@link import('../Workflow.js').Workflow.destroy}'s cascade — a permanently-ended phase
|
|
1140
|
-
* has nothing left to pause for.
|
|
1141
|
-
*/
|
|
1142
|
-
export declare class Phase implements PhaseInterface {
|
|
1143
|
-
#private;
|
|
1144
|
-
readonly description?: string;
|
|
1145
|
-
constructor(snapshot: PhaseSnapshot, workflow: WorkflowInterface, escalate: () => void, options?: PhaseOptions, bail?: boolean, functions?: WorkflowFunctions, silence?: number);
|
|
1146
|
-
get emitter(): EmitterInterface<PhaseEventMap>;
|
|
1147
|
-
get id(): string;
|
|
1148
|
-
get name(): string;
|
|
1149
|
-
get context(): PhaseContext;
|
|
1150
|
-
get workflow(): WorkflowInterface;
|
|
1151
|
-
get bail(): boolean;
|
|
1152
|
-
get concurrency(): number | undefined;
|
|
1153
|
-
get paused(): boolean;
|
|
1154
|
-
get status(): PhaseStatus;
|
|
1155
|
-
get tasks(): TaskManagerInterface;
|
|
1156
|
-
task(id: string): TaskInterface | undefined;
|
|
1157
|
-
results(): readonly TaskResult[];
|
|
1158
|
-
skip(): void;
|
|
1159
|
-
stop(): void;
|
|
1160
|
-
pause(): void;
|
|
1161
|
-
resume(): void;
|
|
1162
|
-
wait(): Promise<void>;
|
|
1163
|
-
add(definition: TaskDefinition, index?: number): Result<TaskInterface, WorkflowError>;
|
|
1164
|
-
remove(id: string): Result<TaskInterface, WorkflowError>;
|
|
1165
|
-
move(id: string, index: number): Result<TaskInterface, WorkflowError>;
|
|
1166
|
-
update(id: string, patch: TaskUpdate): Result<TaskInterface, WorkflowError>;
|
|
1167
|
-
patch(value: PhaseUpdate): void;
|
|
1168
|
-
snapshot(): PhaseSnapshot;
|
|
1169
|
-
}
|
|
1599
|
+
* The two maps carry the same event names, so one list serves both tiers. It is the source of
|
|
1600
|
+
* truth behind {@link import('./WorkflowPersistence.js').WorkflowPersistence}'s attach and detach
|
|
1601
|
+
* passes: subscribing and unsubscribing loop over these names, so an added event reaches both
|
|
1602
|
+
* passes from one edit. `add` and `remove` are deliberately absent — they carry the new or dropped
|
|
1603
|
+
* child, so the persistence layer binds its own attaching handler to them instead.
|
|
1604
|
+
*/
|
|
1605
|
+
export declare const PERSISTED_NODE_EVENTS: ReadonlyArray<keyof WorkflowEventMap & keyof PhaseEventMap>;
|
|
1170
1606
|
|
|
1171
|
-
/**
|
|
1172
|
-
|
|
1607
|
+
/**
|
|
1608
|
+
* Lists the {@link TaskEventMap} events that make a durable observer re-persist the live tree, frozen.
|
|
1609
|
+
*
|
|
1610
|
+
* @remarks
|
|
1611
|
+
* The leaf counterpart of {@link PERSISTED_NODE_EVENTS}, and the source of truth behind the task
|
|
1612
|
+
* attach and detach passes of
|
|
1613
|
+
* {@link import('./WorkflowPersistence.js').WorkflowPersistence}. `report` and `pulse` join the
|
|
1614
|
+
* lifecycle events because an accepted activity frame changes the persisted snapshot; a leaf has
|
|
1615
|
+
* no children, so there is no structural event to bind separately.
|
|
1616
|
+
*/
|
|
1617
|
+
export declare const PERSISTED_TASK_EVENTS: ReadonlyArray<keyof TaskEventMap>;
|
|
1173
1618
|
|
|
1174
1619
|
/**
|
|
1175
|
-
*
|
|
1620
|
+
* Represents the ambient context of a phase — its own identity plus a back-reference to the
|
|
1176
1621
|
* workflow it belongs to.
|
|
1177
1622
|
*
|
|
1178
1623
|
* @remarks
|
|
@@ -1184,7 +1629,7 @@ export declare interface PhaseContext extends WorkflowContext {
|
|
|
1184
1629
|
}
|
|
1185
1630
|
|
|
1186
1631
|
/**
|
|
1187
|
-
*
|
|
1632
|
+
* Represents the serializable definition of one phase — its identity, its ordered tasks, and
|
|
1188
1633
|
* an optional resource throttle.
|
|
1189
1634
|
*
|
|
1190
1635
|
* @remarks
|
|
@@ -1199,11 +1644,13 @@ export declare interface PhaseDefinition {
|
|
|
1199
1644
|
readonly name: string;
|
|
1200
1645
|
readonly description?: string;
|
|
1201
1646
|
readonly tasks: readonly TaskDefinition[];
|
|
1202
|
-
/**
|
|
1647
|
+
/** Caps the tasks in flight at once (a resource throttle); omitted ⇒ unbounded. */
|
|
1203
1648
|
readonly concurrency?: number;
|
|
1204
1649
|
/**
|
|
1650
|
+
* Sets the phase's failure policy.
|
|
1651
|
+
*
|
|
1205
1652
|
* @remarks
|
|
1206
|
-
* The per-phase failure-policy OVERRIDE
|
|
1653
|
+
* The per-phase failure-policy OVERRIDE. Omitted ⇒ the phase INHERITS the
|
|
1207
1654
|
* workflow `bail`; supplied, it wins (`effectiveBail = phase.bail ?? workflow.bail`). A
|
|
1208
1655
|
* `bail: true` phase HALTS the run on its first task failure even under a graceful workflow
|
|
1209
1656
|
* default; a `bail: false` phase does NOT halt even under a strict workflow default.
|
|
@@ -1212,7 +1659,7 @@ export declare interface PhaseDefinition {
|
|
|
1212
1659
|
}
|
|
1213
1660
|
|
|
1214
1661
|
/**
|
|
1215
|
-
*
|
|
1662
|
+
* Converts one {@link import('./types.js').PhaseDefinition} into an initial, all-`pending`
|
|
1216
1663
|
* {@link PhaseSnapshot} — the per-phase step of {@link definitionToSnapshot}.
|
|
1217
1664
|
*
|
|
1218
1665
|
* @remarks
|
|
@@ -1228,11 +1675,12 @@ export declare interface PhaseDefinition {
|
|
|
1228
1675
|
export declare function phaseDefinitionToSnapshot(phase: WorkflowDefinition['phases'][number], workflowBail: boolean): PhaseSnapshot;
|
|
1229
1676
|
|
|
1230
1677
|
/**
|
|
1231
|
-
*
|
|
1232
|
-
* with the EFFECTIVE `bail` policy it ran under
|
|
1678
|
+
* Represents one phase's contribution to the workflow-status derivation — its
|
|
1679
|
+
* {@link LifecycleStatus} paired with the EFFECTIVE `bail` policy it ran under
|
|
1680
|
+
* (`phase.bail ?? workflow.bail`).
|
|
1233
1681
|
*
|
|
1234
1682
|
* @remarks
|
|
1235
|
-
* The input shape of {@link import('./helpers.js').deriveWorkflowStatus}:
|
|
1683
|
+
* The input shape of {@link import('./helpers.js').deriveWorkflowStatus}: because `bail` is a
|
|
1236
1684
|
* per-phase override, the workflow `failed` derivation is per-phase-bail-aware, so each phase
|
|
1237
1685
|
* must carry its OWN effective policy rather than the derivation taking one scalar `bail`. A
|
|
1238
1686
|
* `failed` phase propagates `failed` to the workflow only when ITS `bail` is `true`; a `failed`
|
|
@@ -1240,12 +1688,13 @@ export declare function phaseDefinitionToSnapshot(phase: WorkflowDefinition['pha
|
|
|
1240
1688
|
* builds one per live phase (`{ status: phase.status, bail: phase.bail }`).
|
|
1241
1689
|
*/
|
|
1242
1690
|
export declare interface PhaseDerivation {
|
|
1243
|
-
|
|
1691
|
+
/** Holds the phase's derived lifecycle status. */
|
|
1692
|
+
readonly status: LifecycleStatus;
|
|
1244
1693
|
readonly bail: boolean;
|
|
1245
1694
|
}
|
|
1246
1695
|
|
|
1247
1696
|
/**
|
|
1248
|
-
*
|
|
1697
|
+
* Declares the push observation surface of the phase entity (W-b) — analogous
|
|
1249
1698
|
* to {@link WorkflowEventMap}, scoped to one phase.
|
|
1250
1699
|
*
|
|
1251
1700
|
* @remarks
|
|
@@ -1255,63 +1704,59 @@ export declare interface PhaseDerivation {
|
|
|
1255
1704
|
* `skip` when the phase was intentionally skipped; `stop` when the phase was ended.
|
|
1256
1705
|
* `add` / `remove` / `move` / `update` fire on a successful
|
|
1257
1706
|
* structural or patch edit through
|
|
1258
|
-
* {@link PhaseInterface.add} / `remove` / `move` / `update`
|
|
1707
|
+
* {@link PhaseInterface.add} / `remove` / `move` / `update` — never on a
|
|
1259
1708
|
* refused/gated one. A throwing listener is isolated by the emitter and routed to its
|
|
1260
|
-
* `error` handler, not the domain surface
|
|
1261
|
-
* so it satisfies `EventMap`.
|
|
1709
|
+
* `error` handler, not the domain surface. A `type` alias so it satisfies `EventMap`.
|
|
1262
1710
|
*/
|
|
1263
1711
|
export declare type PhaseEventMap = {
|
|
1264
|
-
/**
|
|
1712
|
+
/** Signals that the phase began — its `id`. */
|
|
1265
1713
|
readonly start: readonly [id: string];
|
|
1266
|
-
/**
|
|
1714
|
+
/** Signals that every task in the phase settled successfully. */
|
|
1267
1715
|
readonly complete: readonly [];
|
|
1268
|
-
/**
|
|
1716
|
+
/** Signals that a task failed under `bail` — the failing task's result. */
|
|
1269
1717
|
readonly fail: readonly [result: TaskResult];
|
|
1270
|
-
/**
|
|
1718
|
+
/** Signals that the phase's runtime gate closed. */
|
|
1271
1719
|
readonly pause: readonly [];
|
|
1272
|
-
/**
|
|
1720
|
+
/** Signals that the phase's runtime gate opened. */
|
|
1273
1721
|
readonly resume: readonly [];
|
|
1274
|
-
/**
|
|
1722
|
+
/** Signals that the phase was intentionally skipped. */
|
|
1275
1723
|
readonly skip: readonly [];
|
|
1276
|
-
/**
|
|
1724
|
+
/** Signals that the phase was permanently stopped. */
|
|
1277
1725
|
readonly stop: readonly [];
|
|
1278
|
-
/**
|
|
1726
|
+
/** Signals that a task was inserted — the inserted task + its final index. */
|
|
1279
1727
|
readonly add: readonly [task: TaskInterface, index: number];
|
|
1280
|
-
/**
|
|
1728
|
+
/** Signals that a task was removed — the removed task. */
|
|
1281
1729
|
readonly remove: readonly [task: TaskInterface];
|
|
1282
|
-
/**
|
|
1730
|
+
/** Signals that a task was repositioned — the moved task + its new index. */
|
|
1283
1731
|
readonly move: readonly [task: TaskInterface, index: number];
|
|
1284
|
-
/**
|
|
1732
|
+
/** Signals that a task was patched — the patched task. */
|
|
1285
1733
|
readonly update: readonly [task: TaskInterface];
|
|
1286
1734
|
};
|
|
1287
1735
|
|
|
1288
|
-
/**
|
|
1289
|
-
export declare type PhaseHooks = EmitterHooks<PhaseEventMap>;
|
|
1290
|
-
|
|
1291
|
-
/** The minimal data to create a phase context — a partial {@link PhaseContext}. */
|
|
1736
|
+
/** Represents the minimal data to create a phase context — a partial {@link PhaseContext}. */
|
|
1292
1737
|
export declare type PhaseInput = Partial<PhaseContext>;
|
|
1293
1738
|
|
|
1294
1739
|
/**
|
|
1295
|
-
*
|
|
1296
|
-
* observable
|
|
1740
|
+
* Declares the live derived state machine (W-b) for one {@link PhaseDefinition} — an
|
|
1741
|
+
* observable phase whose {@link LifecycleStatus} is DERIVED from its tasks
|
|
1297
1742
|
* (never set directly) and recomputed reactively as a task transitions (the cascade).
|
|
1298
1743
|
*
|
|
1299
1744
|
* @remarks
|
|
1300
|
-
* - **Derived status.** `status` is computed
|
|
1745
|
+
* - **Derived status.** `status` is computed through
|
|
1301
1746
|
* {@link import('./helpers.js').derivePhaseStatus} over the live tasks' statuses,
|
|
1302
1747
|
* UNLESS an override is in force. It recomputes whenever a child task transitions; a
|
|
1303
1748
|
* CHANGE emits.
|
|
1304
|
-
* - **Children.** `tasks` is the lean {@link TaskManagerInterface} (
|
|
1749
|
+
* - **Children.** `tasks` is the lean {@link TaskManagerInterface} (an
|
|
1305
1750
|
* accessor + `count`, no batch matrix); `task(id)` / `tasks().tasks()` read in positional
|
|
1306
1751
|
* order. `results` collects the settled tasks' {@link TaskResult}s (the phase tier of the
|
|
1307
1752
|
* result tree); `workflow` navigates UP to the live parent.
|
|
1308
|
-
* - **Override.** `skip` / `stop`
|
|
1309
|
-
* derived value (
|
|
1310
|
-
* - **Observable
|
|
1753
|
+
* - **Override.** `skip` / `stop` FORCE the phase's status, overriding the
|
|
1754
|
+
* derived value (for example, skipping a whole phase); the override survives a snapshot.
|
|
1755
|
+
* - **Observable.** The owned {@link emitter} ({@link PhaseEventMap}) fires
|
|
1311
1756
|
* `start` / `complete` / `fail` / `pause` / `resume` / `stop` after the corresponding
|
|
1312
1757
|
* status or runtime-gate change; the emitter isolates a listener throw and routes it to
|
|
1313
1758
|
* its `error` handler (the `error` option).
|
|
1314
|
-
* - **Runtime lifecycle
|
|
1759
|
+
* - **Runtime lifecycle.** `pause` / `resume` / `wait` mirror
|
|
1315
1760
|
* {@link WorkflowInterface.pause} / `resume` / `wait`, scoped to this phase — a driving
|
|
1316
1761
|
* {@link WorkflowRunnerInterface.execute} gates a task's own pre-dispatch on BOTH the
|
|
1317
1762
|
* workflow's and its phase's gate. `paused` is RUNTIME-ONLY, never persisted; idempotent;
|
|
@@ -1322,49 +1767,51 @@ export declare interface PhaseInterface {
|
|
|
1322
1767
|
readonly emitter: EmitterInterface<PhaseEventMap>;
|
|
1323
1768
|
readonly id: string;
|
|
1324
1769
|
readonly name: string;
|
|
1325
|
-
|
|
1770
|
+
/** Holds this phase's prose, or `undefined` when the definition or snapshot declared none. */
|
|
1771
|
+
readonly description: string | undefined;
|
|
1326
1772
|
readonly context: PhaseContext;
|
|
1327
1773
|
readonly workflow: WorkflowInterface;
|
|
1328
|
-
|
|
1329
|
-
|
|
1774
|
+
/** Holds this phase's effective lifecycle status, derived from its tasks unless an override is in force. */
|
|
1775
|
+
readonly status: LifecycleStatus;
|
|
1776
|
+
/** Reports the RESOLVED effective failure policy this phase runs under (`phase.bail ?? workflow.bail`); mirrors {@link WorkflowInterface.bail}. */
|
|
1330
1777
|
readonly bail: boolean;
|
|
1331
|
-
/**
|
|
1778
|
+
/** Caps the tasks in flight at once (a resource throttle); mirrors {@link PhaseSnapshot.concurrency}. `undefined` ⇒ unbounded. */
|
|
1332
1779
|
readonly concurrency: number | undefined;
|
|
1333
1780
|
/**
|
|
1334
|
-
*
|
|
1335
|
-
* {@link
|
|
1781
|
+
* Reports whether the phase is paused (resumable); RUNTIME-ONLY — never a
|
|
1782
|
+
* {@link LifecycleStatus}, never persisted in a {@link PhaseSnapshot} (a paused phase's
|
|
1336
1783
|
* `status` still reports its ordinary derived value).
|
|
1337
1784
|
*/
|
|
1338
1785
|
readonly paused: boolean;
|
|
1339
1786
|
readonly tasks: TaskManagerInterface;
|
|
1340
|
-
/**
|
|
1787
|
+
/** Looks up one live task by its `id`. */
|
|
1341
1788
|
task(id: string): TaskInterface | undefined;
|
|
1342
|
-
/**
|
|
1789
|
+
/** Lists the settled tasks' results, in positional order — the phase tier of the result tree. */
|
|
1343
1790
|
results(): readonly TaskResult[];
|
|
1344
1791
|
/**
|
|
1345
|
-
*
|
|
1792
|
+
* Forces this phase to `skipped`, overriding the derived value; idempotent.
|
|
1346
1793
|
*
|
|
1347
1794
|
* @remarks
|
|
1348
|
-
* A NO-OP
|
|
1795
|
+
* A NO-OP after `status` becomes terminal — a settled phase cannot be re-forced. Always
|
|
1349
1796
|
* releases a parked {@link wait} waiter regardless (a terminal phase has nothing left to
|
|
1350
1797
|
* pause for).
|
|
1351
1798
|
*/
|
|
1352
1799
|
skip(): void;
|
|
1353
1800
|
/**
|
|
1354
|
-
*
|
|
1801
|
+
* Forces this phase to `stopped`, overriding the derived value; idempotent.
|
|
1355
1802
|
*
|
|
1356
1803
|
* @remarks
|
|
1357
|
-
* A NO-OP
|
|
1804
|
+
* A NO-OP after `status` becomes terminal (a settled phase cannot be re-forced). Always
|
|
1358
1805
|
* releases a parked {@link wait} waiter regardless (a terminal phase has nothing left to
|
|
1359
1806
|
* pause for).
|
|
1360
1807
|
*/
|
|
1361
1808
|
stop(): void;
|
|
1362
1809
|
/**
|
|
1363
|
-
*
|
|
1810
|
+
* Suspends the phase (resumable); idempotent.
|
|
1364
1811
|
*
|
|
1365
1812
|
* @remarks
|
|
1366
|
-
* A no-op when already `paused` or when `status` is terminal. RUNTIME-ONLY
|
|
1367
|
-
* never a {@link
|
|
1813
|
+
* A no-op when already `paused` or when `status` is terminal. RUNTIME-ONLY —
|
|
1814
|
+
* never a {@link LifecycleStatus}, never persisted in a {@link PhaseSnapshot}. A driving
|
|
1368
1815
|
* {@link WorkflowRunnerInterface.execute} gates a task's own pre-dispatch on this phase's
|
|
1369
1816
|
* gate (after the workflow's own gate). **Pausing does NOT suspend a driving run's
|
|
1370
1817
|
* timeout / budget / abort clocks** — those bounds keep ticking while paused, so a long
|
|
@@ -1378,7 +1825,7 @@ export declare interface PhaseInterface {
|
|
|
1378
1825
|
*/
|
|
1379
1826
|
pause(): void;
|
|
1380
1827
|
/**
|
|
1381
|
-
*
|
|
1828
|
+
* Continues a paused phase; idempotent — a no-op unless {@link paused}.
|
|
1382
1829
|
*
|
|
1383
1830
|
* @example
|
|
1384
1831
|
* ```ts
|
|
@@ -1388,25 +1835,25 @@ export declare interface PhaseInterface {
|
|
|
1388
1835
|
*/
|
|
1389
1836
|
resume(): void;
|
|
1390
1837
|
/**
|
|
1391
|
-
*
|
|
1392
|
-
* (
|
|
1838
|
+
* Parks until this phase is not paused — **promise-parked**, never a timer or busy-loop
|
|
1839
|
+
* (mirrors {@link WorkflowInterface.wait}).
|
|
1393
1840
|
*
|
|
1394
1841
|
* @remarks
|
|
1395
1842
|
* Resolves IMMEDIATELY when not {@link paused}. While paused, parks until `resume` or
|
|
1396
1843
|
* this phase's own `stop` / `skip` forcing a terminal status — all release a parked
|
|
1397
1844
|
* waiter. NEVER rejects.
|
|
1398
1845
|
*
|
|
1399
|
-
* @returns A promise that resolves
|
|
1846
|
+
* @returns A promise that resolves after the phase is no longer paused
|
|
1400
1847
|
*/
|
|
1401
1848
|
wait(): Promise<void>;
|
|
1402
1849
|
/**
|
|
1403
|
-
*
|
|
1404
|
-
* (
|
|
1850
|
+
* Mints a live {@link TaskInterface} from `definition` and inserts it into this phase
|
|
1851
|
+
* (the entity structural API) — gated BEFORE delegating to {@link tasks}'
|
|
1405
1852
|
* manager.
|
|
1406
1853
|
*
|
|
1407
1854
|
* @remarks
|
|
1408
1855
|
* Converts `definition` → {@link TaskSnapshot} and constructs the live task (wired to
|
|
1409
|
-
* THIS phase, its recompute cascade, and its emitter hooks), carrying its `
|
|
1856
|
+
* THIS phase, its recompute cascade, and its emitter hooks), carrying its `behavior` /
|
|
1410
1857
|
* `retries` / `timeout` from `definition` and resolving its {@link TaskInterface.handler}
|
|
1411
1858
|
* against the workflow-level {@link WorkflowOptions.functions} registry — the SAME
|
|
1412
1859
|
* resolution {@link import('./factories.js').createWorkflow} performs at build time.
|
|
@@ -1414,20 +1861,20 @@ export declare interface PhaseInterface {
|
|
|
1414
1861
|
* task ids — a duplicate is a `MUTATION` failure (mirrors
|
|
1415
1862
|
* {@link TaskManagerInterface.add}'s own duplicate-id gate).
|
|
1416
1863
|
*
|
|
1417
|
-
* NATIVE gating, purely from this phase's own derived `status` (
|
|
1864
|
+
* NATIVE gating, purely from this phase's own derived `status` (no
|
|
1418
1865
|
* runner-installed hook), UNCHANGED from the entity-taking predecessor. While
|
|
1419
1866
|
* `pending`: any valid `index` is accepted (delegates the minted task to
|
|
1420
1867
|
* {@link TaskManagerInterface.add} then emits `add`). While `running`: accepted ONLY as
|
|
1421
1868
|
* a pure append (`index` omitted or `=== tasks.count`) — a live runner subscribed to
|
|
1422
1869
|
* the `add` event picks the new task up for same-run execution; the derived-status
|
|
1423
|
-
* model
|
|
1424
|
-
* still `pending` (its status feeds `status`
|
|
1870
|
+
* model keeps this phase from reaching a terminal status while the accepted task is
|
|
1871
|
+
* still `pending` (its status feeds `status` through {@link import('./helpers.js').derivePhaseStatus}).
|
|
1425
1872
|
* While terminal: always refused.
|
|
1426
1873
|
*
|
|
1427
1874
|
* **Abort edge.** An append ACCEPTED while `running` can still settle `skipped` rather
|
|
1428
1875
|
* than run — if the driving run is cancelled (abort / timeout / budget / `workflow.destroy()`)
|
|
1429
1876
|
* before the substrate actually dispatches the newly-minted task, the runner's halt sweep
|
|
1430
|
-
* `skip`s it like any other not-yet-started task. Acceptance here only
|
|
1877
|
+
* `skip`s it like any other not-yet-started task. Acceptance here means only that the task
|
|
1431
1878
|
* is WIRED into the live tree, not that it will execute.
|
|
1432
1879
|
*
|
|
1433
1880
|
* @param definition - The {@link TaskDefinition} to mint a live task from
|
|
@@ -1436,7 +1883,7 @@ export declare interface PhaseInterface {
|
|
|
1436
1883
|
*/
|
|
1437
1884
|
add(definition: TaskDefinition, index?: number): Result<TaskInterface, WorkflowError>;
|
|
1438
1885
|
/**
|
|
1439
|
-
*
|
|
1886
|
+
* Removes the `pending` task `id` from this phase.
|
|
1440
1887
|
*
|
|
1441
1888
|
* @remarks
|
|
1442
1889
|
* NATIVE gating: allowed only while this phase's own `status` is `pending`. While
|
|
@@ -1449,7 +1896,7 @@ export declare interface PhaseInterface {
|
|
|
1449
1896
|
*/
|
|
1450
1897
|
remove(id: string): Result<TaskInterface, WorkflowError>;
|
|
1451
1898
|
/**
|
|
1452
|
-
*
|
|
1899
|
+
* Repositions the `pending` task `id` to `index` within this phase.
|
|
1453
1900
|
*
|
|
1454
1901
|
* @remarks
|
|
1455
1902
|
* NATIVE gating: allowed only while this phase's own `status` is `pending`; `running` /
|
|
@@ -1461,7 +1908,7 @@ export declare interface PhaseInterface {
|
|
|
1461
1908
|
*/
|
|
1462
1909
|
move(id: string, index: number): Result<TaskInterface, WorkflowError>;
|
|
1463
1910
|
/**
|
|
1464
|
-
*
|
|
1911
|
+
* Applies a validated {@link TaskUpdate} patch to the `pending` task `id` in this phase.
|
|
1465
1912
|
*
|
|
1466
1913
|
* @remarks
|
|
1467
1914
|
* NATIVE gating: allowed only while this phase's own `status` is `pending`; `running` /
|
|
@@ -1473,11 +1920,11 @@ export declare interface PhaseInterface {
|
|
|
1473
1920
|
*/
|
|
1474
1921
|
update(id: string, patch: TaskUpdate): Result<TaskInterface, WorkflowError>;
|
|
1475
1922
|
/**
|
|
1476
|
-
*
|
|
1923
|
+
* Applies a validated declarative patch to SELF (`name` / `description` /
|
|
1477
1924
|
* `concurrency` / `bail`).
|
|
1478
1925
|
*
|
|
1479
1926
|
* @remarks
|
|
1480
|
-
* Defense-in-depth
|
|
1927
|
+
* Defense-in-depth: the owning {@link WorkflowInterface.update} gates
|
|
1481
1928
|
* FIRST, so a direct call here THROWS a `MUTATION`
|
|
1482
1929
|
* {@link import('./errors.js').WorkflowError} unless this phase's own `status` is
|
|
1483
1930
|
* `pending`.
|
|
@@ -1493,24 +1940,28 @@ export declare interface PhaseInterface {
|
|
|
1493
1940
|
}
|
|
1494
1941
|
|
|
1495
1942
|
/**
|
|
1496
|
-
*
|
|
1497
|
-
*
|
|
1943
|
+
* Implements the lean child manager of a {@link import('../Workflow.js').Workflow}'s live
|
|
1944
|
+
* phases — the phase vocabulary over one insertion-ordered {@link Collection}, the phase analogue
|
|
1498
1945
|
* of {@link import('../tasks/TaskManager.js').TaskManager}.
|
|
1499
1946
|
*
|
|
1500
1947
|
* @remarks
|
|
1501
|
-
* - **
|
|
1502
|
-
* `
|
|
1503
|
-
*
|
|
1504
|
-
*
|
|
1505
|
-
* - **
|
|
1506
|
-
*
|
|
1507
|
-
*
|
|
1508
|
-
*
|
|
1509
|
-
*
|
|
1510
|
-
*
|
|
1511
|
-
*
|
|
1512
|
-
*
|
|
1513
|
-
*
|
|
1948
|
+
* - **One shared store.** The insertion-ordered `Map`, the reorder step, the bounds checks, and
|
|
1949
|
+
* the gated `add` / `remove` / `move` / `update` all live in {@link Collection}, built with the
|
|
1950
|
+
* `phase` noun its refusals name and the compiled {@link phaseUpdateShape} guard. This class
|
|
1951
|
+
* adds the domain accessors `phase` / `phases` and nothing else.
|
|
1952
|
+
* - **Positional store.** `append` adds one live {@link PhaseInterface} at the end, `phase(id)`
|
|
1953
|
+
* looks one up, `phases()` lists them in positional order, `count` is the tally. A snapshot
|
|
1954
|
+
* RESTORE re-`append`s in the snapshot's order, reproducing it exactly.
|
|
1955
|
+
* - **Gated mutation API.** `add` / `remove` / `move` / `update` are the graceful
|
|
1956
|
+
* `Result` counterparts to `append`, gating ONLY on the target's OWN existence/status/id/bounds
|
|
1957
|
+
* — a duplicate id, an absent/non-`pending` target, an out-of-bounds `index`, or a patch that
|
|
1958
|
+
* fails {@link phaseUpdateShape} validation all fail gracefully with a `MUTATION`
|
|
1959
|
+
* {@link WorkflowError} instead of throwing.
|
|
1960
|
+
* - **No batch matrix.** A workflow's phases are a fixed positional set, so the batch verbs of
|
|
1961
|
+
* `.claude/rules/patterns.md` § Batch operations are
|
|
1962
|
+
* deliberately omitted.
|
|
1963
|
+
* - **Event-free.** A purely structural container — the live {@link PhaseInterface}s own their own
|
|
1964
|
+
* emitters.
|
|
1514
1965
|
*
|
|
1515
1966
|
* @example
|
|
1516
1967
|
* ```ts
|
|
@@ -1533,13 +1984,13 @@ export declare class PhaseManager implements PhaseManagerInterface {
|
|
|
1533
1984
|
}
|
|
1534
1985
|
|
|
1535
1986
|
/**
|
|
1536
|
-
*
|
|
1987
|
+
* Declares the lean child manager of a {@link WorkflowInterface}'s live phases —
|
|
1537
1988
|
* positional accessors plus `count`, the phase analogue of {@link TaskManagerInterface}.
|
|
1538
1989
|
*
|
|
1539
1990
|
* @remarks
|
|
1540
1991
|
* `append` adds one live {@link PhaseInterface} at the end; `phase(id)` looks one up;
|
|
1541
1992
|
* `phases()` lists them in positional order; `count` is the tally. No batch matrix.
|
|
1542
|
-
* `add` / `remove` / `move` / `update`
|
|
1993
|
+
* `add` / `remove` / `move` / `update` are the GATED mutation
|
|
1543
1994
|
* counterparts a {@link WorkflowInterface.add} / `remove` / `move` / `update`
|
|
1544
1995
|
* delegates to AFTER its own container-status/hook gating — the manager gates ONLY
|
|
1545
1996
|
* on the target's OWN existence/status/id/bounds and stays event-free (the entity
|
|
@@ -1548,18 +1999,18 @@ export declare class PhaseManager implements PhaseManagerInterface {
|
|
|
1548
1999
|
export declare interface PhaseManagerInterface {
|
|
1549
2000
|
readonly count: number;
|
|
1550
2001
|
/**
|
|
1551
|
-
*
|
|
2002
|
+
* Adds `phase` at the end (the build-time wiring path).
|
|
1552
2003
|
*
|
|
1553
2004
|
* @remarks
|
|
1554
2005
|
* THROWS a `MUTATION` {@link import('./errors.js').WorkflowError} on a duplicate
|
|
1555
|
-
* `id` (a genuine programmer error — a build-time wiring bug
|
|
2006
|
+
* `id` (a genuine programmer error — a build-time wiring bug) instead of
|
|
1556
2007
|
* silently overwriting the existing entry.
|
|
1557
2008
|
*
|
|
1558
2009
|
* @param phase - The live phase to append
|
|
1559
2010
|
*/
|
|
1560
2011
|
append(phase: PhaseInterface): void;
|
|
1561
2012
|
/**
|
|
1562
|
-
*
|
|
2013
|
+
* Inserts `phase` at `index` (default the end) — the GATED mutation counterpart to
|
|
1563
2014
|
* {@link append}: a duplicate `id` or an out-of-bounds `index` fails gracefully
|
|
1564
2015
|
* instead of throwing.
|
|
1565
2016
|
*
|
|
@@ -1569,7 +2020,7 @@ export declare interface PhaseManagerInterface {
|
|
|
1569
2020
|
*/
|
|
1570
2021
|
add(phase: PhaseInterface, index?: number): Result<PhaseInterface, WorkflowError>;
|
|
1571
2022
|
/**
|
|
1572
|
-
*
|
|
2023
|
+
* Removes the `pending` phase `id`.
|
|
1573
2024
|
*
|
|
1574
2025
|
* @param id - The phase id to remove
|
|
1575
2026
|
* @returns A {@link Result} boxing the removed phase, or a `MUTATION` failure when
|
|
@@ -1577,7 +2028,7 @@ export declare interface PhaseManagerInterface {
|
|
|
1577
2028
|
*/
|
|
1578
2029
|
remove(id: string): Result<PhaseInterface, WorkflowError>;
|
|
1579
2030
|
/**
|
|
1580
|
-
*
|
|
2031
|
+
* Repositions the `pending` phase `id` to `index`.
|
|
1581
2032
|
*
|
|
1582
2033
|
* @param id - The phase id to move
|
|
1583
2034
|
* @param index - The destination position (`[0, count)`)
|
|
@@ -1586,7 +2037,7 @@ export declare interface PhaseManagerInterface {
|
|
|
1586
2037
|
*/
|
|
1587
2038
|
move(id: string, index: number): Result<PhaseInterface, WorkflowError>;
|
|
1588
2039
|
/**
|
|
1589
|
-
*
|
|
2040
|
+
* Applies a validated {@link PhaseUpdate} patch to the `pending` phase `id`.
|
|
1590
2041
|
*
|
|
1591
2042
|
* @param id - The phase id to patch
|
|
1592
2043
|
* @param patch - The fields to update
|
|
@@ -1599,25 +2050,25 @@ export declare interface PhaseManagerInterface {
|
|
|
1599
2050
|
}
|
|
1600
2051
|
|
|
1601
2052
|
/**
|
|
1602
|
-
*
|
|
2053
|
+
* Declares the runtime options for a {@link PhaseInterface} — the construction bag the live
|
|
1603
2054
|
* derived phase state machine (W-b) carries.
|
|
1604
2055
|
*
|
|
1605
2056
|
* @remarks
|
|
1606
|
-
* The reserved `on`
|
|
2057
|
+
* The reserved `on` wires initial {@link PhaseEventMap} listeners.
|
|
1607
2058
|
* `tasks` keys per-task {@link TaskOptions} by task `id`, so {@link createWorkflow}
|
|
1608
2059
|
* can thread a leaf's options (its `on` / `metadata`) down through the phase when it
|
|
1609
2060
|
* builds the whole tree.
|
|
1610
2061
|
*/
|
|
1611
2062
|
export declare interface PhaseOptions {
|
|
1612
|
-
readonly on?:
|
|
1613
|
-
/**
|
|
2063
|
+
readonly on?: EmitterHooks<PhaseEventMap>;
|
|
2064
|
+
/** Holds the emitter's listener-error handler — a listener throw routes here, not to a domain event. */
|
|
1614
2065
|
readonly error?: EmitterErrorHandler;
|
|
1615
|
-
/**
|
|
2066
|
+
/** Holds the per-task {@link TaskOptions}, keyed by the task's `id`. */
|
|
1616
2067
|
readonly tasks?: Readonly<Record<string, TaskOptions>>;
|
|
1617
2068
|
}
|
|
1618
2069
|
|
|
1619
2070
|
/**
|
|
1620
|
-
*
|
|
2071
|
+
* Describes the shape of a {@link import('./types.js').PhaseDefinition} — identity, its ordered
|
|
1621
2072
|
* {@link taskShape} tasks, and an optional positive-integer `concurrency` throttle
|
|
1622
2073
|
* (max tasks in flight; omitted ⇒ unbounded).
|
|
1623
2074
|
*/
|
|
@@ -1629,7 +2080,7 @@ export declare const phaseShape: ObjectShape<{
|
|
|
1629
2080
|
id: StringShape;
|
|
1630
2081
|
name: StringShape;
|
|
1631
2082
|
description: OptionalShape<StringShape>;
|
|
1632
|
-
|
|
2083
|
+
behavior: OptionalShape<StringShape>;
|
|
1633
2084
|
retries: OptionalShape<NumberShape>;
|
|
1634
2085
|
timeout: OptionalShape<NumberShape>;
|
|
1635
2086
|
}, false>>;
|
|
@@ -1638,12 +2089,12 @@ export declare const phaseShape: ObjectShape<{
|
|
|
1638
2089
|
}, false>;
|
|
1639
2090
|
|
|
1640
2091
|
/**
|
|
1641
|
-
*
|
|
2092
|
+
* Represents a JSON-serializable snapshot of one phase's state — its identity, status, its forced
|
|
1642
2093
|
* override (if any), and its nested task snapshots.
|
|
1643
2094
|
*
|
|
1644
2095
|
* @remarks
|
|
1645
2096
|
* Pure JSON DATA. `status` is the EFFECTIVE status (override-or-derived) at snapshot time.
|
|
1646
|
-
* `override` is the forced status of a whole-phase `skip` / `stop`
|
|
2097
|
+
* `override` is the forced status of a whole-phase `skip` / `stop` — PRESENT only
|
|
1647
2098
|
* when one is in force, so a restore reinstates it DIRECTLY (no fragile derivation comparison)
|
|
1648
2099
|
* and a genuinely-derived phase carries none. A leaf {@link TaskSnapshot} needs no `override`
|
|
1649
2100
|
* field — a task's terminal status IS its forced marker. `tasks` are the phase's
|
|
@@ -1653,17 +2104,18 @@ export declare interface PhaseSnapshot {
|
|
|
1653
2104
|
readonly id: string;
|
|
1654
2105
|
readonly name: string;
|
|
1655
2106
|
readonly description?: string;
|
|
1656
|
-
|
|
1657
|
-
|
|
1658
|
-
|
|
2107
|
+
/** Holds the phase's persisted effective lifecycle status (override-or-derived). */
|
|
2108
|
+
readonly status: LifecycleStatus;
|
|
2109
|
+
/** Records the forced status of a whole-phase `skip` / `stop`; present only when an override is in force. */
|
|
2110
|
+
readonly override?: LifecycleStatus;
|
|
1659
2111
|
/**
|
|
1660
|
-
*
|
|
2112
|
+
* Records the EFFECTIVE failure policy this phase ran under (`phase.bail ?? workflow.bail`)
|
|
1661
2113
|
* — persisted (REQUIRED, like {@link WorkflowSnapshot.bail}) so a restore reinstates the same
|
|
1662
2114
|
* per-phase policy identically without a silent default.
|
|
1663
2115
|
*/
|
|
1664
2116
|
readonly bail: boolean;
|
|
1665
2117
|
/**
|
|
1666
|
-
*
|
|
2118
|
+
* Caps the tasks in flight at once (a resource throttle), persisted so a restore reinstates the
|
|
1667
2119
|
* same per-phase throttle — mirrors {@link import('./types.js').PhaseDefinition.concurrency}.
|
|
1668
2120
|
* Omitted ⇒ unbounded.
|
|
1669
2121
|
*/
|
|
@@ -1672,21 +2124,9 @@ export declare interface PhaseSnapshot {
|
|
|
1672
2124
|
}
|
|
1673
2125
|
|
|
1674
2126
|
/**
|
|
1675
|
-
*
|
|
1676
|
-
* derived from its tasks' statuses.
|
|
1677
|
-
*
|
|
1678
|
-
* @remarks
|
|
1679
|
-
* A semantic tier of the shared {@link LifecycleStatus} vocabulary. A failed task makes
|
|
1680
|
-
* its phase `failed` regardless of policy; the phase's effective `bail` determines whether
|
|
1681
|
-
* that failure propagates to the workflow or is retained as graceful result data. `stopped`
|
|
1682
|
-
* propagates when every task was stopped. See {@link import('./helpers.js').derivePhaseStatus}.
|
|
1683
|
-
*/
|
|
1684
|
-
export declare type PhaseStatus = LifecycleStatus;
|
|
1685
|
-
|
|
1686
|
-
/**
|
|
1687
|
-
* A declarative partial update to a {@link PhaseInterface} — the fields a `pending`
|
|
2127
|
+
* Represents a declarative partial update to a {@link PhaseInterface} — the fields a `pending`
|
|
1688
2128
|
* phase's {@link PhaseInterface.patch} (and the owning {@link PhaseManagerInterface.update})
|
|
1689
|
-
* accept, runtime-validated
|
|
2129
|
+
* accept, runtime-validated through {@link import('./shapers.js').phaseUpdateShape}.
|
|
1690
2130
|
*
|
|
1691
2131
|
* @remarks
|
|
1692
2132
|
* Mirrors the identity + throttle/policy fields of {@link PhaseDefinition} (`name` /
|
|
@@ -1707,13 +2147,13 @@ export declare interface PhaseUpdate {
|
|
|
1707
2147
|
}
|
|
1708
2148
|
|
|
1709
2149
|
/**
|
|
1710
|
-
*
|
|
2150
|
+
* Describes the shape of a {@link import('./types.js').PhaseUpdate} — a partial edit to a
|
|
1711
2151
|
* `pending` phase's `name` / `description` / `concurrency` / `bail`, all optional.
|
|
1712
2152
|
*
|
|
1713
2153
|
* @remarks
|
|
1714
2154
|
* Mirrors {@link phaseShape}'s corresponding field constraints exactly; never `id` /
|
|
1715
2155
|
* `tasks` (structural children change through the phase's own `add` / `remove` /
|
|
1716
|
-
* `move`, not a patch
|
|
2156
|
+
* `move`, not a patch).
|
|
1717
2157
|
*/
|
|
1718
2158
|
export declare const phaseUpdateShape: ObjectShape<{
|
|
1719
2159
|
name: OptionalShape<StringShape>;
|
|
@@ -1723,7 +2163,7 @@ export declare const phaseUpdateShape: ObjectShape<{
|
|
|
1723
2163
|
}, false>;
|
|
1724
2164
|
|
|
1725
2165
|
/**
|
|
1726
|
-
*
|
|
2166
|
+
* Converts interrupted running work into a recoverable pending suffix or an
|
|
1727
2167
|
* exhausted recovery failure without replenishing attempts.
|
|
1728
2168
|
*
|
|
1729
2169
|
* @param snapshot - A fully validated owned snapshot with no terminal overrides
|
|
@@ -1732,7 +2172,7 @@ export declare const phaseUpdateShape: ObjectShape<{
|
|
|
1732
2172
|
export declare function recoverWorkflowSnapshot(snapshot: WorkflowSnapshot): WorkflowSnapshot;
|
|
1733
2173
|
|
|
1734
2174
|
/**
|
|
1735
|
-
*
|
|
2175
|
+
* Resolves a task's runtime silence window against its workflow default.
|
|
1736
2176
|
*
|
|
1737
2177
|
* @param value - The task-level override; any present non-positive or non-finite value disables
|
|
1738
2178
|
* @param fallback - The workflow-level default
|
|
@@ -1741,7 +2181,67 @@ export declare function recoverWorkflowSnapshot(snapshot: WorkflowSnapshot): Wor
|
|
|
1741
2181
|
export declare function resolveTaskSilence(value: number | undefined, fallback: number | undefined): number | undefined;
|
|
1742
2182
|
|
|
1743
2183
|
/**
|
|
1744
|
-
*
|
|
2184
|
+
* Holds the active phase {@link RunnerInterface} for one
|
|
2185
|
+
* {@link import('./types.js').WorkflowRunnerInterface.execute} call, for the lifetime of that run.
|
|
2186
|
+
*
|
|
2187
|
+
* @remarks
|
|
2188
|
+
* - **One holder per run.** The engine mints a holder as a run begins and threads that one
|
|
2189
|
+
* instance through every phase of the run, so a nested `execute` reached through application
|
|
2190
|
+
* composition gets its own holder and can never clobber the suspended outer run's.
|
|
2191
|
+
* - **`hold` is the only mutation.** A phase takes the substrate runner with `hold(runner)` as it
|
|
2192
|
+
* starts and releases it with `hold()` as it settles; `runner` reads the held value back and is
|
|
2193
|
+
* `undefined` between phases and after the last one.
|
|
2194
|
+
* - **A cancel closes over the holder.** The run-level abort listener reads `runner` when it
|
|
2195
|
+
* fires, so it reaches whichever phase runner is live at that moment rather than the one that
|
|
2196
|
+
* was live when the listener was armed.
|
|
2197
|
+
* - **Event-free.** A plain cell — no emitter, no lifecycle of its own.
|
|
2198
|
+
*/
|
|
2199
|
+
export declare class RunHolder implements RunHolderInterface {
|
|
2200
|
+
#private;
|
|
2201
|
+
get runner(): RunnerInterface<TaskInterface, void> | undefined;
|
|
2202
|
+
/**
|
|
2203
|
+
* Takes the phase runner a starting phase hands this run, or releases the held one.
|
|
2204
|
+
*
|
|
2205
|
+
* @param runner - The phase runner to hold; omitted releases the held runner
|
|
2206
|
+
* @example
|
|
2207
|
+
* ```ts
|
|
2208
|
+
* import type { TaskInterface } from '@orkestrel/workflow'
|
|
2209
|
+
* import { createRunner, RunHolder } from '@orkestrel/workflow'
|
|
2210
|
+
*
|
|
2211
|
+
* const holder = new RunHolder()
|
|
2212
|
+
* holder.hold(createRunner<TaskInterface, void>({ handler: () => undefined }))
|
|
2213
|
+
* holder.hold() // released — `runner` reads `undefined` again
|
|
2214
|
+
* ```
|
|
2215
|
+
*/
|
|
2216
|
+
hold(runner?: RunnerInterface<TaskInterface, void>): void;
|
|
2217
|
+
}
|
|
2218
|
+
|
|
2219
|
+
/**
|
|
2220
|
+
* Holds the phase {@link RunnerInterface} one {@link WorkflowRunnerInterface.execute} call is
|
|
2221
|
+
* driving, for the lifetime of that run.
|
|
2222
|
+
*
|
|
2223
|
+
* @remarks
|
|
2224
|
+
* Phases run sequentially, so one run drives at most one phase runner at a time: `hold(runner)`
|
|
2225
|
+
* takes the runner as a phase starts and `hold()` releases it as that phase settles, leaving
|
|
2226
|
+
* `runner` `undefined` between phases and after the last one. `runner` is a readonly projection
|
|
2227
|
+
* of the held state, so the swap goes through `hold` alone. A run-level cancel closes over the
|
|
2228
|
+
* holder rather than over a runner, so it aborts whichever phase runner is live when the cancel
|
|
2229
|
+
* fires rather than the one that was live when the listener was armed, and a fresh holder per
|
|
2230
|
+
* `execute` keeps a nested run from clobbering the suspended outer run's.
|
|
2231
|
+
*/
|
|
2232
|
+
export declare interface RunHolderInterface {
|
|
2233
|
+
/** Reports the phase runner this cell holds, or `undefined` between phases. */
|
|
2234
|
+
readonly runner: RunnerInterface<TaskInterface, void> | undefined;
|
|
2235
|
+
/**
|
|
2236
|
+
* Takes a phase runner for the phase that is starting, or releases the held one.
|
|
2237
|
+
*
|
|
2238
|
+
* @param runner - The phase runner to hold; omitted releases the held runner
|
|
2239
|
+
*/
|
|
2240
|
+
hold(runner?: RunnerInterface<TaskInterface, void>): void;
|
|
2241
|
+
}
|
|
2242
|
+
|
|
2243
|
+
/**
|
|
2244
|
+
* Implements a thin generic orchestrator that drives declared units — and any they `spawn` —
|
|
1745
2245
|
* through a bounded-concurrency {@link createQueue}, collecting ordered results.
|
|
1746
2246
|
*
|
|
1747
2247
|
* @remarks
|
|
@@ -1755,12 +2255,12 @@ export declare function resolveTaskSilence(value: number | undefined, fallback:
|
|
|
1755
2255
|
* Results are read back as `#order.map(id => #values.get(id))` — declared first (in
|
|
1756
2256
|
* input order), then spawns (in spawn order). There is no one-time task snapshot,
|
|
1757
2257
|
* so a unit spawned mid-handler is run and ordered like any other.
|
|
1758
|
-
* - **`execute` awaits the full spawn closure
|
|
2258
|
+
* - **`execute` awaits the full spawn closure through a count gate.** `#launch` increments
|
|
1759
2259
|
* an outstanding-unit `#count` BEFORE enqueuing and every settle decrements it,
|
|
1760
2260
|
* resolving the `#drained` deferred at zero. Because `spawn` calls `#launch` (so
|
|
1761
2261
|
* `#count += 1`) before the parent handler returns, the count never reaches zero
|
|
1762
2262
|
* mid-run — `execute` parks on `#drained` and so awaits the entire transitive
|
|
1763
|
-
* closure, not
|
|
2263
|
+
* closure, not only the declared units.
|
|
1764
2264
|
* - **`spawn` is fire-and-track.** A spawned unit runs through the queue regardless of
|
|
1765
2265
|
* whether its promise is awaited; the Runner never awaits a spawned promise from
|
|
1766
2266
|
* within a handler's slot (it awaits the count gate instead), so a slot-holding
|
|
@@ -1774,16 +2274,16 @@ export declare function resolveTaskSilence(value: number | undefined, fallback:
|
|
|
1774
2274
|
* unit failure (after its retries) records the error and `abort()`s the run, so every
|
|
1775
2275
|
* sibling's signal fires; later failures are ignored and `execute` rejects with the
|
|
1776
2276
|
* first error. A user `abort(reason)` likewise rejects a running `execute`.
|
|
1777
|
-
* - **`pause` / `resume` / `stop`
|
|
2277
|
+
* - **`pause` / `resume` / `stop` ride the backing Queue.** `pause` / `resume`
|
|
1778
2278
|
* delegate straight to the Queue's own pause/resume (holding/releasing the NEXT
|
|
1779
2279
|
* dispatch while an in-flight unit finishes); `paused` mirrors the Queue's. `stop` is a
|
|
1780
2280
|
* GRACEFUL permanent end, distinct from `abort`: still-pending (never-dispatched)
|
|
1781
2281
|
* units are rejected by the Queue's own stop WITHOUT their handler ever running, and
|
|
1782
2282
|
* `#settle` reads that fact (`#dispatched`) to treat the rejection as a stop artifact —
|
|
1783
2283
|
* not a failure, never tripping fail-fast — while an in-flight unit still runs to
|
|
1784
|
-
* completion and settles normally. `execute` RESOLVES (never rejects)
|
|
2284
|
+
* completion and settles normally. `execute` RESOLVES (never rejects) after every unit
|
|
1785
2285
|
* has settled, with whatever results actually completed.
|
|
1786
|
-
* - **Observable
|
|
2286
|
+
* - **Observable.** The owned {@link emitter} ({@link RunnerEventMap}) carries the run
|
|
1787
2287
|
* lifecycle — `start` / `unit` / `spawn` / `settle` / `fail` / `finish` / `abort` — for
|
|
1788
2288
|
* fire-and-forget observers. Every event is emitted directly, strictly AFTER the relevant
|
|
1789
2289
|
* launch / settle / drain transition; the emitter isolates a listener throw and routes it
|
|
@@ -1800,20 +2300,20 @@ export declare class Runner<TInput, TResult> implements RunnerInterface<TInput,
|
|
|
1800
2300
|
get stopped(): boolean;
|
|
1801
2301
|
get paused(): boolean;
|
|
1802
2302
|
/**
|
|
1803
|
-
*
|
|
2303
|
+
* Injects one more unit into an IN-FLIGHT `execute` run — a LIVE counterpart to a
|
|
1804
2304
|
* `Controller.spawn`, called from OUTSIDE any unit's handler.
|
|
1805
2305
|
*
|
|
1806
2306
|
* @remarks
|
|
1807
|
-
* Returns `undefined` synchronously (graceful, non-throwing
|
|
1808
|
-
* runner is
|
|
2307
|
+
* Returns `undefined` synchronously (graceful, non-throwing) unless the
|
|
2308
|
+
* runner is mid-`execute` and not yet stopped — covering "never started",
|
|
1809
2309
|
* "already drained", "aborted", and "destroyed". Otherwise the unit is routed through
|
|
1810
|
-
* the SAME backing queue as a declared/`spawn`ed unit
|
|
2310
|
+
* the SAME backing queue as a declared/`spawn`ed unit through `#launch` — the outstanding-
|
|
1811
2311
|
* unit count gate increments BEFORE this call returns, so an in-flight `execute`
|
|
1812
2312
|
* keeps awaiting it (the drain race: `#running` flips to `false` as the very first
|
|
1813
2313
|
* step after `execute`'s `await drained.promise` settles, so a `spawn` reaching this
|
|
1814
2314
|
* method after the run has fully drained is cleanly rejected with `undefined` —
|
|
1815
2315
|
* never silently dropped, never hangs `execute`). Emits {@link RunnerEventMap.spawn}
|
|
1816
|
-
* with a `parent` of `undefined` (this call has no spawning unit)
|
|
2316
|
+
* with a `parent` of `undefined` (this call has no spawning unit) after acceptance.
|
|
1817
2317
|
*
|
|
1818
2318
|
* @param input - The unit's work payload
|
|
1819
2319
|
* @returns The unit's result promise, or `undefined` when no in-flight run can accept it
|
|
@@ -1829,26 +2329,26 @@ export declare class Runner<TInput, TResult> implements RunnerInterface<TInput,
|
|
|
1829
2329
|
execute(inputs: readonly TInput[]): Promise<readonly TResult[]>;
|
|
1830
2330
|
abort(reason?: unknown): Promise<void>;
|
|
1831
2331
|
/**
|
|
1832
|
-
*
|
|
2332
|
+
* Suspends dispatch (resumable): delegates to the backing queue's own
|
|
1833
2333
|
* `pause`, which holds the NEXT dispatch while any in-flight unit finishes.
|
|
1834
2334
|
*
|
|
1835
2335
|
* @remarks
|
|
1836
|
-
* A no-op
|
|
2336
|
+
* A no-op after the runner is `stopped` — a stopped runner has no dispatch left to
|
|
1837
2337
|
* suspend, mirroring the guard `stop()` itself applies. Also a no-op when already
|
|
1838
2338
|
* `paused` (the queue's own `pause` is idempotent), so calling it repeatedly is safe.
|
|
1839
2339
|
*/
|
|
1840
2340
|
pause(): void;
|
|
1841
2341
|
/**
|
|
1842
|
-
*
|
|
2342
|
+
* Continues a paused runner; delegates to the backing queue's `resume`.
|
|
1843
2343
|
*
|
|
1844
2344
|
* @remarks
|
|
1845
|
-
* A no-op
|
|
1846
|
-
* runner is not
|
|
2345
|
+
* A no-op after the runner is `stopped` (nothing left to resume) and a no-op when the
|
|
2346
|
+
* runner is not `paused`, so calling it repeatedly or on a never-paused
|
|
1847
2347
|
* runner is safe.
|
|
1848
2348
|
*/
|
|
1849
2349
|
resume(): void;
|
|
1850
2350
|
/**
|
|
1851
|
-
*
|
|
2351
|
+
* Ends the runner permanently — a GRACEFUL stop, distinct from `abort`.
|
|
1852
2352
|
* Marks the runner `stopping` + `stopped`, then stops the backing queue: every
|
|
1853
2353
|
* still-PENDING (never-dispatched) unit is rejected by the queue with its own
|
|
1854
2354
|
* "queue is stopped" error, WITHOUT running its handler; every already-in-flight unit
|
|
@@ -1862,8 +2362,8 @@ export declare class Runner<TInput, TResult> implements RunnerInterface<TInput,
|
|
|
1862
2362
|
}
|
|
1863
2363
|
|
|
1864
2364
|
/**
|
|
1865
|
-
*
|
|
1866
|
-
* per-attempt deadline, resolved from the unit's input
|
|
2365
|
+
* Declares the per-entry reliability OVERRIDES for one unit — its extra attempts on failure and its
|
|
2366
|
+
* per-attempt deadline, resolved from the unit's input through {@link RunnerOptions.entries}.
|
|
1867
2367
|
*
|
|
1868
2368
|
* @remarks
|
|
1869
2369
|
* The unit's `id` and `signal` stay Runner-managed (it mints the id and owns the per-unit
|
|
@@ -1879,7 +2379,7 @@ export declare interface RunnerEntryOptions {
|
|
|
1879
2379
|
}
|
|
1880
2380
|
|
|
1881
2381
|
/**
|
|
1882
|
-
*
|
|
2382
|
+
* Declares the push observation surface of a {@link RunnerInterface} — the run
|
|
1883
2383
|
* lifecycle a fire-and-forget observer (logging, metrics, tracing) subscribes to,
|
|
1884
2384
|
* ALONGSIDE the eventual `execute` result.
|
|
1885
2385
|
*
|
|
@@ -1888,32 +2388,32 @@ export declare interface RunnerEntryOptions {
|
|
|
1888
2388
|
* {@link RunnerInterface} is generic.
|
|
1889
2389
|
*
|
|
1890
2390
|
* @remarks
|
|
1891
|
-
* Listener isolation is the emitter's
|
|
2391
|
+
* Listener isolation is the emitter's: every event is emitted directly and a
|
|
1892
2392
|
* listener throw is routed to the emitter's OWN `error` handler (the `error` option), never
|
|
1893
2393
|
* onto this domain map and never into the one-shot / fail-fast / spawn-tracking engine — so a
|
|
1894
2394
|
* buggy observer can never reorder, throw into, or corrupt the run. Every emit sits AFTER the
|
|
1895
2395
|
* relevant unit-launch / settle / drain transition, so a throwing observer cannot unbalance
|
|
1896
|
-
* the outstanding-unit count gate or break fail-fast. Subscribe
|
|
2396
|
+
* the outstanding-unit count gate or break fail-fast. Subscribe through `runner.emitter.on(...)`.
|
|
1897
2397
|
*
|
|
1898
|
-
* Declared as a `type` alias (not `interface extends EventMap
|
|
2398
|
+
* Declared as a `type` alias (not `interface extends EventMap` — `EventMap` is a
|
|
1899
2399
|
* `type` kind): a type-literal satisfies the `EventMap` constraint
|
|
1900
2400
|
* (`Record<string, readonly unknown[]>`) structurally, whereas an interface lacks the
|
|
1901
2401
|
* required index signature.
|
|
1902
2402
|
*/
|
|
1903
2403
|
export declare type RunnerEventMap<TResult> = {
|
|
1904
|
-
/** `execute` began — emitted once at the top of a non-empty run. */
|
|
2404
|
+
/** Signals that `execute` began — emitted once at the top of a non-empty run. */
|
|
1905
2405
|
readonly start: readonly [];
|
|
1906
|
-
/**
|
|
2406
|
+
/** Signals that a unit's handler began running — the unit's id (declared or spawned). */
|
|
1907
2407
|
readonly unit: readonly [id: string];
|
|
1908
|
-
/**
|
|
2408
|
+
/** Signals that a sub-unit was spawned — its id + the spawning parent's id (when known). */
|
|
1909
2409
|
readonly spawn: readonly [id: string, parent: string | undefined];
|
|
1910
|
-
/**
|
|
2410
|
+
/** Signals that a unit completed successfully — its id (after its outcome was recorded). */
|
|
1911
2411
|
readonly settle: readonly [id: string];
|
|
1912
|
-
/**
|
|
2412
|
+
/** Signals that a unit failed — its id + the error (always `unknown`). */
|
|
1913
2413
|
readonly fail: readonly [id: string, error: unknown];
|
|
1914
|
-
/**
|
|
2414
|
+
/** Signals that the batch settled — the run's ordered results (the same array `execute` resolves). */
|
|
1915
2415
|
readonly finish: readonly [results: readonly TResult[]];
|
|
1916
|
-
/**
|
|
2416
|
+
/** Signals that the run was aborted (fail-fast, a user `abort`, or `destroy`) — the cancel reason. */
|
|
1917
2417
|
readonly abort: readonly [reason: unknown];
|
|
1918
2418
|
};
|
|
1919
2419
|
|
|
@@ -1926,7 +2426,7 @@ export declare type RunnerEventMap<TResult> = {
|
|
|
1926
2426
|
export declare type RunnerHandler<TInput, TResult> = (controller: ControllerInterface<TInput, TResult>) => Promise<TResult> | TResult;
|
|
1927
2427
|
|
|
1928
2428
|
/**
|
|
1929
|
-
*
|
|
2429
|
+
* Declares a thin generic orchestrator that drives declared units — plus any they `spawn` —
|
|
1930
2430
|
* through a bounded-concurrency queue, collecting their results in order.
|
|
1931
2431
|
*
|
|
1932
2432
|
* @remarks
|
|
@@ -1935,12 +2435,12 @@ export declare type RunnerHandler<TInput, TResult> = (controller: ControllerInte
|
|
|
1935
2435
|
* (the backpressure + retry + timeout engine), routing every unit (declared and
|
|
1936
2436
|
* spawned) through it so spawned work actually runs.
|
|
1937
2437
|
*
|
|
1938
|
-
* Exposes a typed {@link emitter}
|
|
2438
|
+
* Exposes a typed {@link emitter} carrying its run lifecycle moments
|
|
1939
2439
|
* ({@link RunnerEventMap}) for fire-and-forget observers, ALONGSIDE the eventual `execute`
|
|
1940
2440
|
* result. Emitting is observation-only — every event fires AFTER the relevant unit-launch /
|
|
1941
2441
|
* settle / drain transition, so a buggy observer can never reorder or corrupt the one-shot /
|
|
1942
2442
|
* fail-fast / spawn-tracking engine: the emitter isolates a listener throw and routes it to
|
|
1943
|
-
* its `error` handler (the `error` option), never the run. Subscribe
|
|
2443
|
+
* its `error` handler (the `error` option), never the run. Subscribe through
|
|
1944
2444
|
* `runner.emitter.on(...)`.
|
|
1945
2445
|
*
|
|
1946
2446
|
* @typeParam TInput - The unit's work input
|
|
@@ -1950,10 +2450,10 @@ export declare interface RunnerInterface<TInput, TResult> {
|
|
|
1950
2450
|
readonly emitter: EmitterInterface<RunnerEventMap<TResult>>;
|
|
1951
2451
|
readonly active: number;
|
|
1952
2452
|
readonly stopped: boolean;
|
|
1953
|
-
/**
|
|
2453
|
+
/** Reports whether the runner is paused (resumable, no new dispatch); rides the backing queue's own `paused`. */
|
|
1954
2454
|
readonly paused: boolean;
|
|
1955
2455
|
/**
|
|
1956
|
-
*
|
|
2456
|
+
* Runs all `inputs` — and anything they `spawn` — to completion; resolves their
|
|
1957
2457
|
* results in order: the declared inputs first (in input order), then the spawned
|
|
1958
2458
|
* units (in spawn order).
|
|
1959
2459
|
*
|
|
@@ -1967,18 +2467,18 @@ export declare interface RunnerInterface<TInput, TResult> {
|
|
|
1967
2467
|
*/
|
|
1968
2468
|
execute(inputs: readonly TInput[]): Promise<readonly TResult[]>;
|
|
1969
2469
|
/**
|
|
1970
|
-
*
|
|
2470
|
+
* Injects one more unit into an IN-FLIGHT `execute` run — a LIVE counterpart to a
|
|
1971
2471
|
* `Controller.spawn`, called from OUTSIDE any unit's handler (the seam a live
|
|
1972
2472
|
* `running` {@link PhaseInterface}'s `add` event lets a subscribed run offer a newly
|
|
1973
2473
|
* added task to the SAME execution substrate).
|
|
1974
2474
|
*
|
|
1975
2475
|
* @remarks
|
|
1976
|
-
* Returns `undefined` synchronously (graceful, non-throwing
|
|
1977
|
-
* runner is not
|
|
2476
|
+
* Returns `undefined` synchronously (graceful, non-throwing) when the
|
|
2477
|
+
* runner is not mid-`execute`, or the run has already fully drained — the
|
|
1978
2478
|
* caller reads `undefined` as "not accepted". Otherwise the unit is routed through
|
|
1979
2479
|
* the SAME backing queue as a declared/`spawn`ed unit (the runner's
|
|
1980
2480
|
* outstanding-unit count gate keeps the in-flight `execute` awaiting it) and emits
|
|
1981
|
-
* the {@link RunnerEventMap.spawn} event; its result promise resolves
|
|
2481
|
+
* the {@link RunnerEventMap.spawn} event; its result promise resolves after the unit
|
|
1982
2482
|
* settles.
|
|
1983
2483
|
*
|
|
1984
2484
|
* @param input - The unit's work payload
|
|
@@ -1986,7 +2486,7 @@ export declare interface RunnerInterface<TInput, TResult> {
|
|
|
1986
2486
|
*/
|
|
1987
2487
|
spawn(input: TInput): Promise<TResult> | undefined;
|
|
1988
2488
|
/**
|
|
1989
|
-
*
|
|
2489
|
+
* Cancels every in-flight + pending unit (and the backing queue), making a running
|
|
1990
2490
|
* `execute` reject.
|
|
1991
2491
|
*
|
|
1992
2492
|
* @param reason - An optional cancellation reason propagated to every unit's signal
|
|
@@ -1994,7 +2494,7 @@ export declare interface RunnerInterface<TInput, TResult> {
|
|
|
1994
2494
|
*/
|
|
1995
2495
|
abort(reason?: unknown): Promise<void>;
|
|
1996
2496
|
/**
|
|
1997
|
-
*
|
|
2497
|
+
* Suspends dispatch (resumable): the backing queue holds the NEXT dispatch
|
|
1998
2498
|
* while any in-flight unit finishes; idempotent.
|
|
1999
2499
|
*
|
|
2000
2500
|
* @example
|
|
@@ -2005,7 +2505,7 @@ export declare interface RunnerInterface<TInput, TResult> {
|
|
|
2005
2505
|
*/
|
|
2006
2506
|
pause(): void;
|
|
2007
2507
|
/**
|
|
2008
|
-
*
|
|
2508
|
+
* Continues a paused runner; idempotent.
|
|
2009
2509
|
*
|
|
2010
2510
|
* @example
|
|
2011
2511
|
* ```ts
|
|
@@ -2015,11 +2515,11 @@ export declare interface RunnerInterface<TInput, TResult> {
|
|
|
2015
2515
|
*/
|
|
2016
2516
|
resume(): void;
|
|
2017
2517
|
/**
|
|
2018
|
-
*
|
|
2518
|
+
* Ends the runner permanently — a GRACEFUL stop: no further unit is
|
|
2019
2519
|
* dispatched, but every already-in-flight unit runs to completion and settles
|
|
2020
2520
|
* normally. A never-dispatched (still-pending) unit is rejected by the backing queue
|
|
2021
2521
|
* and is NOT recorded as a failure (it never trips fail-fast); a genuine in-flight
|
|
2022
|
-
* failure still is. `execute`'s promise RESOLVES (never rejects)
|
|
2522
|
+
* failure still is. `execute`'s promise RESOLVES (never rejects) after every unit has
|
|
2023
2523
|
* settled, with whatever results actually completed. Idempotent.
|
|
2024
2524
|
*
|
|
2025
2525
|
* @example
|
|
@@ -2033,7 +2533,7 @@ export declare interface RunnerInterface<TInput, TResult> {
|
|
|
2033
2533
|
*/
|
|
2034
2534
|
stop(): Promise<void>;
|
|
2035
2535
|
/**
|
|
2036
|
-
*
|
|
2536
|
+
* Tears the runner down, awaiting backing-queue cleanup before destroying the emitter last.
|
|
2037
2537
|
*
|
|
2038
2538
|
* @returns The stable teardown barrier
|
|
2039
2539
|
*/
|
|
@@ -2041,7 +2541,7 @@ export declare interface RunnerInterface<TInput, TResult> {
|
|
|
2041
2541
|
}
|
|
2042
2542
|
|
|
2043
2543
|
/**
|
|
2044
|
-
*
|
|
2544
|
+
* Declares the options for `createRunner`.
|
|
2045
2545
|
*
|
|
2046
2546
|
* @remarks
|
|
2047
2547
|
* - `handler` — runs each unit's work against its {@link ControllerInterface};
|
|
@@ -2054,29 +2554,30 @@ export declare interface RunnerInterface<TInput, TResult> {
|
|
|
2054
2554
|
* an integer in `0..2_147_483_647`, and `0` disables the deadline.
|
|
2055
2555
|
* - `entries` — per-entry `retries` / `timeout` overrides, resolved from each
|
|
2056
2556
|
* input; falls back to the runner-level `retries` / `timeout` defaults.
|
|
2057
|
-
* - `on` — the reserved {@link EmitterHooks} key
|
|
2058
|
-
* {@link RunnerEventMap}, wired at construction (
|
|
2557
|
+
* - `on` — the reserved {@link EmitterHooks} key: initial listeners for the runner's
|
|
2558
|
+
* {@link RunnerEventMap}, wired at construction (for example, `{ finish: (r) => log(r) }`).
|
|
2059
2559
|
*/
|
|
2060
2560
|
export declare interface RunnerOptions<TInput, TResult> {
|
|
2061
2561
|
readonly on?: EmitterHooks<RunnerEventMap<TResult>>;
|
|
2062
|
-
/**
|
|
2562
|
+
/** Holds the emitter's listener-error handler — a listener throw routes here, not to a domain event. */
|
|
2063
2563
|
readonly error?: EmitterErrorHandler;
|
|
2064
2564
|
readonly handler: RunnerHandler<TInput, TResult>;
|
|
2065
2565
|
readonly concurrency?: number;
|
|
2066
2566
|
readonly retries?: number;
|
|
2067
2567
|
readonly timeout?: number;
|
|
2068
|
-
/**
|
|
2568
|
+
/** Resolves per-entry `retries` / `timeout` overrides from each input; falls back to the runner-level defaults. */
|
|
2069
2569
|
readonly entries?: (input: TInput) => RunnerEntryOptions;
|
|
2070
2570
|
}
|
|
2071
2571
|
|
|
2072
2572
|
/**
|
|
2073
|
-
*
|
|
2573
|
+
* Represents one unit the {@link RunnerInterface} is tracking: the queue payload it was enqueued
|
|
2074
2574
|
* with — its `id` (a random UUID) keys it in the runner's ordered launch list and value
|
|
2075
2575
|
* map, and `input` is the unit's work payload handed to the handler's `Controller`.
|
|
2076
2576
|
*
|
|
2077
2577
|
* @remarks
|
|
2078
|
-
* The runner's internal bookkeeping shape, published through the barrel because
|
|
2079
|
-
* centralizes every file-local type —
|
|
2578
|
+
* The runner's internal bookkeeping shape, published through the barrel because
|
|
2579
|
+
* `.claude/rules/architecture.md` § Centralized-file pattern centralizes every file-local type —
|
|
2580
|
+
* declared or spawned, every unit flows through the
|
|
2080
2581
|
* one queue as a `RunnerUnit`, so backpressure / ordering / retries / timeout stay the
|
|
2081
2582
|
* Queue's behavior and the runner adds only orchestration.
|
|
2082
2583
|
*
|
|
@@ -2088,7 +2589,21 @@ export declare interface RunnerUnit<TInput> {
|
|
|
2088
2589
|
}
|
|
2089
2590
|
|
|
2090
2591
|
/**
|
|
2091
|
-
*
|
|
2592
|
+
* Locates the nearest identifiable node for an inconsistent owned snapshot.
|
|
2593
|
+
*
|
|
2594
|
+
* @remarks
|
|
2595
|
+
* The walk stops at the first phase or task whose persisted fields are inconsistent and returns
|
|
2596
|
+
* the identifiers it could read there, so a diagnostic can name the offending node even when part
|
|
2597
|
+
* of its identity is unreadable.
|
|
2598
|
+
*
|
|
2599
|
+
* @param value - The candidate snapshot, which may be any unknown value
|
|
2600
|
+
* @returns The nearest identifying record naming the offending `phase` and `task`, or `undefined`
|
|
2601
|
+
* when no inconsistent node is identifiable
|
|
2602
|
+
*/
|
|
2603
|
+
export declare function scanSnapshotContext(value: unknown): Readonly<Record<string, unknown>> | undefined;
|
|
2604
|
+
|
|
2605
|
+
/**
|
|
2606
|
+
* Schedules one cancellable host operation behind an owned settlement signal.
|
|
2092
2607
|
*
|
|
2093
2608
|
* @remarks
|
|
2094
2609
|
* A defined `signal` that is not a native `AbortSignal` is refused before anything is armed, as a
|
|
@@ -2118,7 +2633,7 @@ export declare interface RunnerUnit<TInput> {
|
|
|
2118
2633
|
export declare function scheduleHost(start: (complete: () => void, failure: (error: unknown) => void) => () => void, signal?: AbortSignal): Promise<void>;
|
|
2119
2634
|
|
|
2120
2635
|
/**
|
|
2121
|
-
*
|
|
2636
|
+
* Implements the safe cross-environment cooperative-yield default — a {@link SchedulerInterface}
|
|
2122
2637
|
* built on `setTimeout` / `clearTimeout` alone, so it runs unchanged in both the
|
|
2123
2638
|
* browser and Node.
|
|
2124
2639
|
*
|
|
@@ -2134,7 +2649,7 @@ export declare function scheduleHost(start: (complete: () => void, failure: (err
|
|
|
2134
2649
|
* rendering run — it only defers within the current task. A zero-delay timer is
|
|
2135
2650
|
* the correct cross-environment "give the host a turn".
|
|
2136
2651
|
* - **Abort-aware.** A pending `yield` / `delay` rejects with `signal.reason` exactly.
|
|
2137
|
-
* {@link
|
|
2652
|
+
* {@link delayHost} links an owned settlement composite to the caller before arming
|
|
2138
2653
|
* the timer, so pre-abort schedules nothing, caller signal method mutation is harmless,
|
|
2139
2654
|
* cancellation clears the handle, and native first-settlement wins exactly once.
|
|
2140
2655
|
* - **Priority is accepted but uniform.** `options.priority` is part of the
|
|
@@ -2152,60 +2667,59 @@ export declare function scheduleHost(start: (complete: () => void, failure: (err
|
|
|
2152
2667
|
* ```
|
|
2153
2668
|
*/
|
|
2154
2669
|
declare class Scheduler_2 implements SchedulerInterface {
|
|
2155
|
-
#private;
|
|
2156
2670
|
/**
|
|
2157
|
-
*
|
|
2158
|
-
* run, then
|
|
2671
|
+
* Yields control back to the host so other tasks (I/O, timers, rendering) can
|
|
2672
|
+
* run, then resumes — a macrotask turn through `setTimeout(0)` (NOT a microtask,
|
|
2159
2673
|
* which would resume before the host regains control).
|
|
2160
2674
|
*/
|
|
2161
2675
|
yield(options?: SchedulerOptions): Promise<void>;
|
|
2162
2676
|
/**
|
|
2163
|
-
*
|
|
2677
|
+
* Resumes after at least `ms` milliseconds; abort rejects with `signal.reason`.
|
|
2164
2678
|
*
|
|
2165
2679
|
* @remarks
|
|
2166
|
-
*
|
|
2167
|
-
*
|
|
2168
|
-
*
|
|
2169
|
-
*
|
|
2680
|
+
* Pass a non-negative finite `ms`. The primitive stays minimal and does no
|
|
2681
|
+
* validation: it passes `ms` straight to the host `setTimeout`, which clamps a
|
|
2682
|
+
* negative value or `NaN` to ~0 — so an out-of-domain `ms` resolves on the next
|
|
2683
|
+
* host turn rather than throwing.
|
|
2170
2684
|
*/
|
|
2171
2685
|
delay(ms: number, options?: SchedulerOptions): Promise<void>;
|
|
2172
2686
|
}
|
|
2173
2687
|
export { Scheduler_2 as Scheduler }
|
|
2174
2688
|
|
|
2175
2689
|
/**
|
|
2176
|
-
*
|
|
2690
|
+
* Declares a cooperative host-yield primitive: a loop decides WHAT to do; the scheduler
|
|
2177
2691
|
* decides WHEN the host regains control. Abort-aware — a pending yield/delay
|
|
2178
2692
|
* rejects with the signal's reason when aborted.
|
|
2179
2693
|
*/
|
|
2180
2694
|
export declare interface SchedulerInterface {
|
|
2181
2695
|
/**
|
|
2182
|
-
*
|
|
2183
|
-
* run, then
|
|
2696
|
+
* Yields control back to the host so other tasks (I/O, timers, rendering) can
|
|
2697
|
+
* run, then resumes.
|
|
2184
2698
|
*/
|
|
2185
2699
|
yield(options?: SchedulerOptions): Promise<void>;
|
|
2186
|
-
/**
|
|
2700
|
+
/** Resumes after at least `ms` milliseconds. */
|
|
2187
2701
|
delay(ms: number, options?: SchedulerOptions): Promise<void>;
|
|
2188
2702
|
}
|
|
2189
2703
|
|
|
2190
|
-
/**
|
|
2704
|
+
/** Declares the options for a single cooperative yield/delay. */
|
|
2191
2705
|
export declare interface SchedulerOptions {
|
|
2192
2706
|
/**
|
|
2193
|
-
*
|
|
2707
|
+
* Carries a relative urgency hint. Honoured by environment backends; the
|
|
2194
2708
|
* cross-environment default treats all priorities the same.
|
|
2195
2709
|
*/
|
|
2196
2710
|
readonly priority?: SchedulerPriority;
|
|
2197
|
-
/**
|
|
2711
|
+
/** Carries a signal whose abort rejects a pending yield/delay with its `reason`. */
|
|
2198
2712
|
readonly signal?: AbortSignal;
|
|
2199
2713
|
}
|
|
2200
2714
|
|
|
2201
2715
|
/**
|
|
2202
|
-
*
|
|
2716
|
+
* Names the relative urgency hint for cooperative scheduling. Honoured by environment
|
|
2203
2717
|
* backends; the cross-environment default treats all priorities uniformly.
|
|
2204
2718
|
*/
|
|
2205
2719
|
export declare type SchedulerPriority = 'user' | 'normal' | 'background';
|
|
2206
2720
|
|
|
2207
2721
|
/**
|
|
2208
|
-
*
|
|
2722
|
+
* Boxes a value as a {@link Success} — the graceful outcome half of a {@link Result}.
|
|
2209
2723
|
*
|
|
2210
2724
|
* @typeParam T - The boxed value's type
|
|
2211
2725
|
* @param value - The value to box
|
|
@@ -2219,99 +2733,7 @@ export declare type SchedulerPriority = 'user' | 'normal' | 'background';
|
|
|
2219
2733
|
export declare function success<T>(value: T): Success<T>;
|
|
2220
2734
|
|
|
2221
2735
|
/**
|
|
2222
|
-
*
|
|
2223
|
-
* synchronous task whose explicit {@link TaskStatus} advances through the AGENTS §10
|
|
2224
|
-
* transitions, recording a {@link TaskResult} on a terminal outcome.
|
|
2225
|
-
*
|
|
2226
|
-
* @remarks
|
|
2227
|
-
* - **Guarded transitions (AGENTS §10).** `start` (→ `running`), then `complete(value)`
|
|
2228
|
-
* (→ `completed`, records a {@link import('@orkestrel/contract').Success}), `fail(error)`
|
|
2229
|
-
* (→ `failed`, records a {@link import('@orkestrel/contract').Failure}), `skip` (→ `skipped`),
|
|
2230
|
-
* `stop` (→ `stopped`). Each consults {@link canTransitionTask} FIRST and throws a
|
|
2231
|
-
* `TRANSITION` {@link WorkflowError} on an illegal move (e.g. completing a non-`running`
|
|
2232
|
-
* task) — the legal graph is the single source of truth, so the leaf can never reach an
|
|
2233
|
-
* impossible state.
|
|
2234
|
-
* - **Snapshot fidelity.** A leaf needs no override: `skipped` / `stopped` are explicit terminal
|
|
2235
|
-
* statuses, and restore reinstates the leaf directly from {@link TaskSnapshot.status}.
|
|
2236
|
-
* - **The cascade.** Every status change records its boxed result (when any), fires the leaf's
|
|
2237
|
-
* OWN event, THEN calls the parent phase's `#recompute` (injected at construction) so the
|
|
2238
|
-
* transition propagates UP (Task → Phase → Workflow re-derive). The own-event-before-cascade
|
|
2239
|
-
* order means an observer sees the CAUSE (this leaf changed) before the EFFECT (the parents
|
|
2240
|
-
* re-derive) — the project precedent (`Runner.#settle` emits its own `fail` before propagating).
|
|
2241
|
-
* - **Observable (AGENTS §13).** The owned {@link emitter} ({@link TaskEventMap}) fires the
|
|
2242
|
-
* matching event strictly AFTER the state change, BEFORE the cascade; the emitter isolates
|
|
2243
|
-
* a listener throw and routes it to its `error` handler (the `error` option), so a buggy
|
|
2244
|
-
* observer can never corrupt a transition.
|
|
2245
|
-
* - **Declarative config (AGENTS §12).** `run` / `retries` / `timeout` PERSIST in a
|
|
2246
|
-
* {@link TaskSnapshot} (like a phase's `bail` / `concurrency`), carried verbatim from the
|
|
2247
|
-
* matching {@link import('../types.js').TaskDefinition} / {@link TaskSnapshot} field. `handler`
|
|
2248
|
-
* is the RUNTIME-ONLY counterpart — `run` resolved ONCE at construction against the
|
|
2249
|
-
* workflow-level {@link import('../types.js').WorkflowOptions.functions} registry — and is
|
|
2250
|
-
* NEVER persisted; `undefined` when `run` is omitted or unregistered. Only omission is a
|
|
2251
|
-
* deliberate no-op; unresolved named work is rejected before dispatch.
|
|
2252
|
-
*/
|
|
2253
|
-
export declare class Task implements TaskInterface {
|
|
2254
|
-
#private;
|
|
2255
|
-
readonly description?: string;
|
|
2256
|
-
constructor(context: TaskContext, phase: PhaseInterface, workflow: WorkflowInterface, recompute: () => void, options?: TaskOptions, status?: TaskStatus, result?: TaskResult, run?: string, retries?: number, timeout?: number, metadata?: JSONRecord, attempts?: number, activity?: TaskActivity, handler?: WorkflowFunction, silence?: number);
|
|
2257
|
-
get emitter(): EmitterInterface<TaskEventMap>;
|
|
2258
|
-
get id(): string;
|
|
2259
|
-
get name(): string;
|
|
2260
|
-
get context(): TaskContext;
|
|
2261
|
-
get phase(): PhaseInterface;
|
|
2262
|
-
get workflow(): WorkflowInterface;
|
|
2263
|
-
get status(): TaskStatus;
|
|
2264
|
-
get result(): TaskResult | undefined;
|
|
2265
|
-
get attempts(): number;
|
|
2266
|
-
get run(): string | undefined;
|
|
2267
|
-
get handler(): WorkflowFunction | undefined;
|
|
2268
|
-
get retries(): number | undefined;
|
|
2269
|
-
get timeout(): number | undefined;
|
|
2270
|
-
get activity(): TaskActivity | undefined;
|
|
2271
|
-
get silence(): number | undefined;
|
|
2272
|
-
get silent(): boolean;
|
|
2273
|
-
get paused(): boolean;
|
|
2274
|
-
get signal(): AbortSignal;
|
|
2275
|
-
start(): void;
|
|
2276
|
-
complete(value: JSONValue): void;
|
|
2277
|
-
fail(error: TaskFailure): void;
|
|
2278
|
-
skip(): void;
|
|
2279
|
-
stop(): void;
|
|
2280
|
-
report(input: TaskActivityInput): Result<TaskActivity, WorkflowError>;
|
|
2281
|
-
pulse(): boolean;
|
|
2282
|
-
pause(): void;
|
|
2283
|
-
resume(): void;
|
|
2284
|
-
wait(): Promise<void>;
|
|
2285
|
-
/**
|
|
2286
|
-
* Apply a validated declarative patch to SELF (`name` / `description`).
|
|
2287
|
-
*
|
|
2288
|
-
* @remarks
|
|
2289
|
-
* Defense-in-depth (AGENTS §12): the owning
|
|
2290
|
-
* {@link import('../types.js').TaskManagerInterface.update} gates FIRST (target
|
|
2291
|
-
* exists + `pending`), so this is the second, redundant check — it THROWS a
|
|
2292
|
-
* `MUTATION` {@link WorkflowError} unless this task's own `status` is `pending`.
|
|
2293
|
-
*
|
|
2294
|
-
* @param value - The {@link TaskUpdate} fields to apply
|
|
2295
|
-
* @example
|
|
2296
|
-
* ```ts
|
|
2297
|
-
* task.patch({ name: 'Renamed task' })
|
|
2298
|
-
* ```
|
|
2299
|
-
*/
|
|
2300
|
-
patch(value: TaskUpdate): void;
|
|
2301
|
-
snapshot(): TaskSnapshot;
|
|
2302
|
-
}
|
|
2303
|
-
|
|
2304
|
-
/**
|
|
2305
|
-
* Every {@link TaskStatus} value, frozen — the lifecycle vocabulary of a task.
|
|
2306
|
-
*
|
|
2307
|
-
* @remarks
|
|
2308
|
-
* Ordered pending → running → terminal (`completed` / `failed` / `skipped` /
|
|
2309
|
-
* `stopped`). The source of truth for the union; compose guards / shapes from it.
|
|
2310
|
-
*/
|
|
2311
|
-
export declare const TASK_STATUSES: readonly TaskStatus[];
|
|
2312
|
-
|
|
2313
|
-
/**
|
|
2314
|
-
* The legal {@link TaskStatus} transition graph of the live W-b task state machine —
|
|
2736
|
+
* Declares the legal {@link LifecycleStatus} transition graph of the live W-b task state machine —
|
|
2315
2737
|
* each current status mapped to the statuses it may move to directly, frozen.
|
|
2316
2738
|
*
|
|
2317
2739
|
* @remarks
|
|
@@ -2323,10 +2745,10 @@ export declare const TASK_STATUSES: readonly TaskStatus[];
|
|
|
2323
2745
|
* transitions again. So completing a non-`running` task, or starting a settled one, is
|
|
2324
2746
|
* rejected.
|
|
2325
2747
|
*/
|
|
2326
|
-
export declare const TASK_TRANSITIONS: Readonly<Record<
|
|
2748
|
+
export declare const TASK_TRANSITIONS: Readonly<Record<LifecycleStatus, readonly LifecycleStatus[]>>;
|
|
2327
2749
|
|
|
2328
2750
|
/**
|
|
2329
|
-
*
|
|
2751
|
+
* Represents the bounded, JSON-serializable activity most recently accepted from a task reporter.
|
|
2330
2752
|
*/
|
|
2331
2753
|
export declare interface TaskActivity {
|
|
2332
2754
|
readonly note?: string;
|
|
@@ -2337,7 +2759,7 @@ export declare interface TaskActivity {
|
|
|
2337
2759
|
}
|
|
2338
2760
|
|
|
2339
2761
|
/**
|
|
2340
|
-
*
|
|
2762
|
+
* Represents one complete replacement of a running task's observable activity.
|
|
2341
2763
|
*
|
|
2342
2764
|
* @remarks
|
|
2343
2765
|
* `note` describes the frame while `progress.message` describes the progress value.
|
|
@@ -2352,20 +2774,35 @@ export declare interface TaskActivityInput {
|
|
|
2352
2774
|
}
|
|
2353
2775
|
|
|
2354
2776
|
/**
|
|
2355
|
-
*
|
|
2777
|
+
* Represents one identified thing a running task claims active, with the moment the claim began.
|
|
2356
2778
|
*
|
|
2357
2779
|
* @remarks
|
|
2358
|
-
*
|
|
2359
|
-
*
|
|
2780
|
+
* The shape {@link TaskOperation} and {@link TaskConstraint} share: `id` is unique within one
|
|
2781
|
+
* complete activity report, `name` is the human-readable label, and `started` is a finite
|
|
2782
|
+
* non-negative reporter timestamp. The two claim lists are validated by one guard
|
|
2783
|
+
* ({@link import('./validators.js').isTaskClaimList}) and owned by one cloner
|
|
2784
|
+
* ({@link import('./cloners.js').cloneTaskClaims}) over this type, while each list keeps its own
|
|
2785
|
+
* published member name so a later member can distinguish them.
|
|
2360
2786
|
*/
|
|
2361
|
-
export declare interface
|
|
2787
|
+
export declare interface TaskClaim {
|
|
2362
2788
|
readonly id: string;
|
|
2363
2789
|
readonly name: string;
|
|
2364
2790
|
readonly started: number;
|
|
2365
2791
|
}
|
|
2366
2792
|
|
|
2367
2793
|
/**
|
|
2368
|
-
*
|
|
2794
|
+
* Represents one constraint claimed active when a running task's complete frame was accepted.
|
|
2795
|
+
*
|
|
2796
|
+
* @remarks
|
|
2797
|
+
* A {@link TaskClaim}. Constraints describe active limits or requirements without embedding
|
|
2798
|
+
* provider policy in core. `id` is unique within one complete report and `started` is finite and
|
|
2799
|
+
* non-negative.
|
|
2800
|
+
*/
|
|
2801
|
+
export declare interface TaskConstraint extends TaskClaim {
|
|
2802
|
+
}
|
|
2803
|
+
|
|
2804
|
+
/**
|
|
2805
|
+
* Represents the ambient context of a task — its own identity plus a back-reference to the
|
|
2369
2806
|
* phase (and, transitively, the workflow) it belongs to.
|
|
2370
2807
|
*
|
|
2371
2808
|
* @remarks
|
|
@@ -2378,50 +2815,11 @@ export declare interface TaskContext extends WorkflowContext {
|
|
|
2378
2815
|
}
|
|
2379
2816
|
|
|
2380
2817
|
/**
|
|
2381
|
-
*
|
|
2382
|
-
*
|
|
2383
|
-
* @remarks
|
|
2384
|
-
* - **A leaf handle, NOT the runner `Controller`.** A workflow task is a leaf of the
|
|
2385
|
-
* declarative W-b tree, not a fan-out unit, so it has no `spawn`; its `wait` instead
|
|
2386
|
-
* checkpoints the workflow, phase, and task cooperative gates.
|
|
2387
|
-
* - **Folded signal.** `signal` is the cancellation folded for THIS attempt: its per-attempt
|
|
2388
|
-
* deadline, task stop/skip, workflow abort/timeout/budget/destroy, or a sibling fail-fast.
|
|
2389
|
-
* A handler races its work against it; `aborted` reads it.
|
|
2390
|
-
* - **Attempt ownership.** `report` / `pulse` are closures supplied by the runner and refuse
|
|
2391
|
-
* after this signal aborts or a retry token supersedes this handle.
|
|
2392
|
-
* - **Input + lineage.** `input` is the task's open `metadata` bag (its
|
|
2393
|
-
* {@link import('./types.js').TaskInput} payload, `{}` when none); `task` is the full
|
|
2394
|
-
* {@link TaskContext}, so `task.phase` / `task.phase.workflow` navigate UP the lineage.
|
|
2395
|
-
* - **Read-up results.** `results()` returns every settled task's {@link TaskResult} across
|
|
2396
|
-
* the phases that have already finished (a closure over the live
|
|
2397
|
-
* {@link import('./types.js').WorkflowInterface}), so a `function` task can read an earlier
|
|
2398
|
-
* phase's output. Read-only — a task records its OWN outcome by returning / throwing, not
|
|
2399
|
-
* by mutating the tree.
|
|
2400
|
-
* - **Event-free.** Like the runner `Controller`, the per-task handle carries no Emitter;
|
|
2401
|
-
* observe the W-b entities' own emitters (`task.emitter` / `phase.emitter`) instead.
|
|
2402
|
-
*/
|
|
2403
|
-
declare class TaskController_2 implements TaskControllerInterface {
|
|
2404
|
-
#private;
|
|
2405
|
-
readonly signal: AbortSignal;
|
|
2406
|
-
readonly input: JSONRecord;
|
|
2407
|
-
readonly task: TaskContext;
|
|
2408
|
-
readonly attempt: number;
|
|
2409
|
-
constructor(signal: AbortSignal, input: JSONRecord, task: TaskInterface, attempt: number, results: () => readonly TaskResult[], report: (input: TaskActivityInput) => Result<TaskActivity, WorkflowError>, pulse: () => boolean);
|
|
2410
|
-
get aborted(): boolean;
|
|
2411
|
-
get paused(): boolean;
|
|
2412
|
-
report(input: TaskActivityInput): Result<TaskActivity, WorkflowError>;
|
|
2413
|
-
pulse(): boolean;
|
|
2414
|
-
wait(): Promise<void>;
|
|
2415
|
-
results(): readonly TaskResult[];
|
|
2416
|
-
}
|
|
2417
|
-
export { TaskController_2 as TaskController }
|
|
2418
|
-
|
|
2419
|
-
/**
|
|
2420
|
-
* The per-task handle a {@link WorkflowFunction} receives — the running task's
|
|
2818
|
+
* Declares the per-task handle a {@link WorkflowFunction} receives — the running task's
|
|
2421
2819
|
* cancellation, its input, its lineage, and read-UP access to the result tree.
|
|
2422
2820
|
*
|
|
2423
2821
|
* @remarks
|
|
2424
|
-
* A
|
|
2822
|
+
* A lean handle (NOT the runner `Controller` — it carries no `spawn`; a workflow task
|
|
2425
2823
|
* is a leaf of the declarative tree, not a fan-out unit). It exposes:
|
|
2426
2824
|
* - `signal` — this attempt's folded cancellation: its per-attempt deadline, task
|
|
2427
2825
|
* stop/skip, workflow abort/timeout/budget/destroy, or a sibling fail-fast.
|
|
@@ -2438,55 +2836,57 @@ export declare interface TaskControllerInterface {
|
|
|
2438
2836
|
/** Fires on this attempt's deadline, task stop/skip, run cancellation, or sibling fail-fast. */
|
|
2439
2837
|
readonly signal: AbortSignal;
|
|
2440
2838
|
readonly aborted: boolean;
|
|
2441
|
-
/**
|
|
2839
|
+
/** Holds the task's open `metadata` bag (its {@link TaskInput} payload); `{}` when none. */
|
|
2442
2840
|
readonly input: JSONRecord;
|
|
2443
2841
|
readonly task: TaskContext;
|
|
2444
|
-
/**
|
|
2842
|
+
/** Reports the one-based persisted launch represented by this handle. */
|
|
2445
2843
|
readonly attempt: number;
|
|
2446
|
-
/**
|
|
2844
|
+
/** Reports whether the workflow, phase, or task cooperative gate is paused. */
|
|
2447
2845
|
readonly paused: boolean;
|
|
2448
2846
|
/**
|
|
2449
|
-
*
|
|
2847
|
+
* Replaces this running task's complete observable activity.
|
|
2450
2848
|
*
|
|
2451
2849
|
* @param input - The complete operations, progress, and constraints replacement
|
|
2452
2850
|
* @returns The accepted frame, or a `TRANSITION` failure after ownership is lost or this attempt aborts
|
|
2453
2851
|
*/
|
|
2454
2852
|
report(input: TaskActivityInput): Result<TaskActivity, WorkflowError>;
|
|
2455
2853
|
/**
|
|
2456
|
-
*
|
|
2854
|
+
* Confirms liveness without replacing current activity.
|
|
2457
2855
|
*
|
|
2458
|
-
* @returns
|
|
2856
|
+
* @returns True if the pulse was committed before ownership is lost or this attempt aborts; false otherwise
|
|
2459
2857
|
*/
|
|
2460
2858
|
pulse(): boolean;
|
|
2461
2859
|
/**
|
|
2462
|
-
*
|
|
2860
|
+
* Parks cooperatively while any workflow, phase, or task gate is paused, or until cancelled.
|
|
2463
2861
|
*
|
|
2464
2862
|
* @returns A promise that resolves when every applicable gate is open or the signal aborts
|
|
2465
2863
|
*/
|
|
2466
2864
|
wait(): Promise<void>;
|
|
2467
|
-
/**
|
|
2865
|
+
/** Lists every settled task's result across already-finished phases — the result tree, read-only. */
|
|
2468
2866
|
results(): readonly TaskResult[];
|
|
2469
2867
|
}
|
|
2470
2868
|
|
|
2471
2869
|
/**
|
|
2472
|
-
*
|
|
2870
|
+
* Represents the serializable definition of one task — its identity plus an optional reference to
|
|
2473
2871
|
* the behavior it runs.
|
|
2474
2872
|
*
|
|
2475
2873
|
* @remarks
|
|
2476
2874
|
* Pure JSON DATA: a UI or an LLM authors it, it round-trips through the contract
|
|
2477
2875
|
* (factories.ts), and it carries NO functions. `id` is the positional identity within
|
|
2478
|
-
* its phase; `name` is the human label; `description` is optional prose. `
|
|
2876
|
+
* its phase; `name` is the human label; `description` is optional prose. `behavior` is a
|
|
2479
2877
|
* PLAIN NAME — a key resolved ONCE at construction against a workflow-level
|
|
2480
|
-
* {@link
|
|
2481
|
-
* carried on the live task. An omitted `
|
|
2878
|
+
* {@link WorkflowRegistry} registry into a runtime {@link TaskInterface.handler}
|
|
2879
|
+
* carried on the live task. An omitted `behavior` is the deliberate no-op form and completes
|
|
2482
2880
|
* with JSON `null`; an unresolved present name remains inspectable but is not executable.
|
|
2483
2881
|
*/
|
|
2484
2882
|
export declare interface TaskDefinition {
|
|
2485
2883
|
readonly id: string;
|
|
2486
2884
|
readonly name: string;
|
|
2487
2885
|
readonly description?: string;
|
|
2488
|
-
readonly
|
|
2886
|
+
readonly behavior?: string;
|
|
2489
2887
|
/**
|
|
2888
|
+
* Sets the extra attempts after the first on failure.
|
|
2889
|
+
*
|
|
2490
2890
|
* @remarks
|
|
2491
2891
|
* Extra attempts after the first on failure (a non-negative integer); the runner threads it
|
|
2492
2892
|
* to this task's substrate unit, OVERRIDING the phase Runner's `retries` default. Omitted ⇒
|
|
@@ -2496,6 +2896,8 @@ export declare interface TaskDefinition {
|
|
|
2496
2896
|
*/
|
|
2497
2897
|
readonly retries?: number;
|
|
2498
2898
|
/**
|
|
2899
|
+
* Sets the per-attempt deadline in milliseconds.
|
|
2900
|
+
*
|
|
2499
2901
|
* @remarks
|
|
2500
2902
|
* The workflow-owned per-attempt deadline in milliseconds, an integer from `0` through
|
|
2501
2903
|
* `MAX_TIMER_MS`. Zero or omission means no deadline. PERSISTED in a {@link TaskSnapshot},
|
|
@@ -2506,14 +2908,14 @@ export declare interface TaskDefinition {
|
|
|
2506
2908
|
}
|
|
2507
2909
|
|
|
2508
2910
|
/**
|
|
2509
|
-
*
|
|
2911
|
+
* Converts one {@link import('./types.js').TaskDefinition} into an initial, `pending`
|
|
2510
2912
|
* {@link TaskSnapshot} — the per-task leaf step of {@link definitionToSnapshot} (no
|
|
2511
2913
|
* result yet, empty metadata).
|
|
2512
2914
|
*
|
|
2513
2915
|
* @remarks
|
|
2514
|
-
* `
|
|
2916
|
+
* `behavior` / `retries` / `timeout` carry over verbatim (persisted declarative config, like a
|
|
2515
2917
|
* phase's `bail` / `concurrency`) — a restore reinstates the same behavior reference and
|
|
2516
|
-
* reliability overrides
|
|
2918
|
+
* reliability overrides after pairing with a {@link import('./types.js').WorkflowOptions.functions}
|
|
2517
2919
|
* registry.
|
|
2518
2920
|
*
|
|
2519
2921
|
* @param task - The task definition to seed from
|
|
@@ -2522,7 +2924,7 @@ export declare interface TaskDefinition {
|
|
|
2522
2924
|
export declare function taskDefinitionToSnapshot(task: WorkflowDefinition['phases'][number]['tasks'][number]): TaskSnapshot;
|
|
2523
2925
|
|
|
2524
2926
|
/**
|
|
2525
|
-
*
|
|
2927
|
+
* Declares the push observation surface of the task entity (W-b) — the
|
|
2526
2928
|
* lifecycle moments of one task.
|
|
2527
2929
|
*
|
|
2528
2930
|
* @remarks
|
|
@@ -2531,61 +2933,53 @@ export declare function taskDefinitionToSnapshot(task: WorkflowDefinition['phase
|
|
|
2531
2933
|
* `pause` / `resume` when its runtime gate closes / opens; `skip` when it is
|
|
2532
2934
|
* intentionally not executed; `stop` when it is ended early. A
|
|
2533
2935
|
* throwing listener is isolated by the emitter and routed to its `error` handler,
|
|
2534
|
-
* not the domain surface
|
|
2936
|
+
* not the domain surface. A `type` alias so it satisfies
|
|
2535
2937
|
* `EventMap`.
|
|
2536
2938
|
*/
|
|
2537
2939
|
export declare type TaskEventMap = {
|
|
2538
|
-
/**
|
|
2940
|
+
/** Signals that the task began — its `id`. */
|
|
2539
2941
|
readonly start: readonly [id: string];
|
|
2540
|
-
/**
|
|
2942
|
+
/** Signals that the task finished successfully — its result. */
|
|
2541
2943
|
readonly complete: readonly [result: TaskResult];
|
|
2542
|
-
/**
|
|
2944
|
+
/** Signals that the task failed — its result. */
|
|
2543
2945
|
readonly fail: readonly [result: TaskResult];
|
|
2544
|
-
/**
|
|
2946
|
+
/** Signals that the task's runtime gate closed. */
|
|
2545
2947
|
readonly pause: readonly [];
|
|
2546
|
-
/**
|
|
2948
|
+
/** Signals that the task's runtime gate opened. */
|
|
2547
2949
|
readonly resume: readonly [];
|
|
2548
|
-
/**
|
|
2950
|
+
/** Signals that the task was intentionally skipped. */
|
|
2549
2951
|
readonly skip: readonly [];
|
|
2550
|
-
/**
|
|
2952
|
+
/** Signals that the task was permanently stopped. */
|
|
2551
2953
|
readonly stop: readonly [];
|
|
2552
|
-
/**
|
|
2954
|
+
/** Signals that a complete activity replacement was committed. */
|
|
2553
2955
|
readonly report: readonly [activity: TaskActivity];
|
|
2554
|
-
/**
|
|
2956
|
+
/** Signals that the task confirmed liveness without replacing its current activity. */
|
|
2555
2957
|
readonly pulse: readonly [activity: TaskActivity];
|
|
2556
|
-
/**
|
|
2958
|
+
/** Signals that no report or pulse was accepted during the effective silence window. */
|
|
2557
2959
|
readonly silence: readonly [];
|
|
2558
2960
|
};
|
|
2559
2961
|
|
|
2560
|
-
/**
|
|
2962
|
+
/** Represents a normalized JSON-safe task failure persisted without a stack or cause. */
|
|
2561
2963
|
export declare interface TaskFailure {
|
|
2562
2964
|
readonly origin: TaskFailureOrigin;
|
|
2563
2965
|
readonly message: string;
|
|
2564
2966
|
}
|
|
2565
2967
|
|
|
2566
2968
|
/**
|
|
2567
|
-
*
|
|
2568
|
-
* status, the moment it settled, and its boxed produced outcome.
|
|
2969
|
+
* Names where a task failure arose — the axis a persisted {@link TaskFailure} records.
|
|
2569
2970
|
*
|
|
2570
2971
|
* @remarks
|
|
2571
|
-
*
|
|
2572
|
-
*
|
|
2573
|
-
*
|
|
2574
|
-
*
|
|
2575
|
-
*
|
|
2576
|
-
*
|
|
2577
|
-
* task has no result at all (a non-terminal status, per
|
|
2578
|
-
* {@link import('./helpers.js').isTerminalStatus}). This boxed `result` REPLACES separate
|
|
2579
|
-
* `value?` / `error?` fields: a success's payload is `result.value`, a failure's reason is `result.error`.
|
|
2580
|
-
* `timestamp` is when the result was created (ms since epoch).
|
|
2972
|
+
* - `handler` — the task's own {@link WorkflowFunction} threw or rejected, or its `behavior` name had
|
|
2973
|
+
* no registered handler to dispatch.
|
|
2974
|
+
* - `timeout` — the task's per-attempt deadline expired on its final attempt.
|
|
2975
|
+
* - `recovery` — an interrupted `running` task was rebuilt by
|
|
2976
|
+
* {@link import('./factories.js').createRecoveredWorkflow} with no attempts left in its retry
|
|
2977
|
+
* budget, so the recovery settled it rather than replenishing it.
|
|
2581
2978
|
*/
|
|
2582
2979
|
export declare type TaskFailureOrigin = 'handler' | 'timeout' | 'recovery';
|
|
2583
2980
|
|
|
2584
|
-
/** Initial {@link TaskEventMap} listeners — the reserved `on` option (AGENTS §8). */
|
|
2585
|
-
export declare type TaskHooks = EmitterHooks<TaskEventMap>;
|
|
2586
|
-
|
|
2587
2981
|
/**
|
|
2588
|
-
*
|
|
2982
|
+
* Represents the minimal data to create a task context — a partial {@link TaskContext} plus
|
|
2589
2983
|
* any creation-only fields.
|
|
2590
2984
|
*
|
|
2591
2985
|
* @remarks
|
|
@@ -2594,32 +2988,32 @@ export declare type TaskHooks = EmitterHooks<TaskEventMap>;
|
|
|
2594
2988
|
* layer fills identity / lineage).
|
|
2595
2989
|
*/
|
|
2596
2990
|
export declare interface TaskInput extends Partial<TaskContext> {
|
|
2597
|
-
/**
|
|
2991
|
+
/** Holds an open consumer bag — stored and snapshotted, never interpreted by the workflow. */
|
|
2598
2992
|
readonly metadata?: JSONRecord;
|
|
2599
2993
|
}
|
|
2600
2994
|
|
|
2601
2995
|
/**
|
|
2602
|
-
*
|
|
2603
|
-
*
|
|
2604
|
-
*
|
|
2996
|
+
* Declares the live leaf state machine (W-b) for one {@link TaskDefinition} — an observable,
|
|
2997
|
+
* guarded synchronous task whose explicit {@link LifecycleStatus} advances through the
|
|
2998
|
+
* declared transitions.
|
|
2605
2999
|
*
|
|
2606
3000
|
* @remarks
|
|
2607
3001
|
* - **Identity + lineage.** `id` / `name` / `description` mirror the definition;
|
|
2608
3002
|
* `context` is the task's full {@link TaskContext} (so `context.phase` /
|
|
2609
3003
|
* `context.phase.workflow` navigate UP the tree), and `phase` / `workflow` are the
|
|
2610
3004
|
* live parent entities for direct lineage navigation.
|
|
2611
|
-
* - **State machine
|
|
3005
|
+
* - **State machine.** `status` is the explicit current state. `start`
|
|
2612
3006
|
* moves `pending → running`; the terminal transitions are `complete(value)` (records
|
|
2613
3007
|
* a {@link import('@orkestrel/contract').Success}), `fail(error)` (records a
|
|
2614
|
-
* {@link import('@orkestrel/contract').Failure}), `skip` (
|
|
2615
|
-
* and `stop` (
|
|
3008
|
+
* {@link import('@orkestrel/contract').Failure}), `skip` (intentionally not run),
|
|
3009
|
+
* and `stop` (ended early). Each is GUARDED: an illegal transition (for example,
|
|
2616
3010
|
* completing a non-`running` task) throws a {@link import('./errors.js').WorkflowError}.
|
|
2617
3011
|
* A leaf needs no override: `skipped` / `stopped` are explicit terminal statuses and
|
|
2618
3012
|
* restore directly from {@link TaskSnapshot.status}.
|
|
2619
|
-
* - **Result.** `result` is the recorded {@link TaskResult}
|
|
3013
|
+
* - **Result.** `result` is the recorded {@link TaskResult} after the task settled with an
|
|
2620
3014
|
* outcome (`completed` / `failed`), else `undefined` — the lineage-navigable leaf of the
|
|
2621
3015
|
* result tree.
|
|
2622
|
-
* - **Observable
|
|
3016
|
+
* - **Observable.** The owned {@link emitter} ({@link TaskEventMap}) fires
|
|
2623
3017
|
* `start` / `complete` / `fail` / `pause` / `resume` / `skip` / `stop` strictly AFTER
|
|
2624
3018
|
* each state change; the emitter isolates a listener throw and routes it to its `error`
|
|
2625
3019
|
* handler (the `error` option).
|
|
@@ -2628,50 +3022,52 @@ export declare interface TaskInterface {
|
|
|
2628
3022
|
readonly emitter: EmitterInterface<TaskEventMap>;
|
|
2629
3023
|
readonly id: string;
|
|
2630
3024
|
readonly name: string;
|
|
2631
|
-
|
|
3025
|
+
/** Holds this task's prose, or `undefined` when the definition or snapshot declared none. */
|
|
3026
|
+
readonly description: string | undefined;
|
|
2632
3027
|
readonly context: TaskContext;
|
|
2633
3028
|
readonly phase: PhaseInterface;
|
|
2634
3029
|
readonly workflow: WorkflowInterface;
|
|
2635
|
-
|
|
2636
|
-
|
|
3030
|
+
/** Holds this task's explicit lifecycle status, set by its own transitions. */
|
|
3031
|
+
readonly status: LifecycleStatus;
|
|
3032
|
+
/** Counts total launches already consumed; zero while fresh and one-based after launch. */
|
|
2637
3033
|
readonly attempts: number;
|
|
2638
|
-
/**
|
|
3034
|
+
/** Holds the recorded outcome after the task settled with one (`completed` / `failed`), else `undefined`. */
|
|
2639
3035
|
readonly result: TaskResult | undefined;
|
|
2640
3036
|
/**
|
|
2641
|
-
*
|
|
2642
|
-
* {@link TaskDefinition.
|
|
3037
|
+
* Names the behavior reference — a plain registry key name, PERSISTED (mirrors
|
|
3038
|
+
* {@link TaskDefinition.behavior} / {@link TaskSnapshot.behavior}), like {@link PhaseInterface.bail}.
|
|
2643
3039
|
* `undefined` when this task has no behavior reference.
|
|
2644
3040
|
*/
|
|
2645
|
-
readonly
|
|
3041
|
+
readonly behavior: string | undefined;
|
|
2646
3042
|
/**
|
|
2647
|
-
*
|
|
2648
|
-
* Resolved ONCE at construction (build, restore, or a live mint) by looking `
|
|
2649
|
-
* workflow-level {@link WorkflowOptions.functions} registry: `functions?.[
|
|
2650
|
-
* is defined, else `undefined`. An omitted `
|
|
2651
|
-
* unresolved `
|
|
3043
|
+
* Holds the RESOLVED runtime handler — RUNTIME-ONLY, NEVER persisted in a {@link TaskSnapshot}.
|
|
3044
|
+
* Resolved ONCE at construction (build, restore, or a live mint) by looking `behavior` up in the
|
|
3045
|
+
* workflow-level {@link WorkflowOptions.functions} registry: `functions?.[behavior]` when `behavior`
|
|
3046
|
+
* is defined, else `undefined`. An omitted `behavior` is the deliberate no-op form. A present,
|
|
3047
|
+
* unresolved `behavior` remains visible on exact restore, but the runner rejects it before
|
|
2652
3048
|
* dispatch instead of falsely completing named work.
|
|
2653
3049
|
*/
|
|
2654
3050
|
readonly handler: WorkflowFunction | undefined;
|
|
2655
3051
|
/**
|
|
2656
|
-
*
|
|
3052
|
+
* Holds the extra attempts after the first on failure — PERSISTED (mirrors {@link TaskDefinition.retries}
|
|
2657
3053
|
* / {@link TaskSnapshot.retries}), like {@link PhaseInterface.concurrency}. `undefined` ⇒ none.
|
|
2658
3054
|
*/
|
|
2659
3055
|
readonly retries: number | undefined;
|
|
2660
3056
|
/**
|
|
2661
|
-
*
|
|
3057
|
+
* Holds the workflow-owned per-attempt deadline in milliseconds (`0..MAX_TIMER_MS`) — PERSISTED
|
|
2662
3058
|
* (mirrors {@link TaskDefinition.timeout} / {@link TaskSnapshot.timeout}). Zero or
|
|
2663
3059
|
* `undefined` means no deadline.
|
|
2664
3060
|
*/
|
|
2665
3061
|
readonly timeout: number | undefined;
|
|
2666
|
-
/**
|
|
3062
|
+
/** Holds the last accepted reporter claim, absent while pending. */
|
|
2667
3063
|
readonly activity: TaskActivity | undefined;
|
|
2668
|
-
/**
|
|
3064
|
+
/** Holds the effective host-safe silence window (`1..MAX_TIMER_MS`), or `undefined` when disabled. */
|
|
2669
3065
|
readonly silence: number | undefined;
|
|
2670
|
-
/**
|
|
3066
|
+
/** Reports whether no report or pulse was accepted during the current silence window. */
|
|
2671
3067
|
readonly silent: boolean;
|
|
2672
|
-
/**
|
|
3068
|
+
/** Reports whether this task's cooperative execution gate is paused. */
|
|
2673
3069
|
readonly paused: boolean;
|
|
2674
|
-
/**
|
|
3070
|
+
/** Holds this task's own cancellation signal; running/pending {@link stop} or {@link skip} fires it. */
|
|
2675
3071
|
readonly signal: AbortSignal;
|
|
2676
3072
|
start(): void;
|
|
2677
3073
|
complete(value: JSONValue): void;
|
|
@@ -2679,33 +3075,33 @@ export declare interface TaskInterface {
|
|
|
2679
3075
|
skip(): void;
|
|
2680
3076
|
stop(): void;
|
|
2681
3077
|
/**
|
|
2682
|
-
*
|
|
3078
|
+
* Replaces the complete observable activity of this running task.
|
|
2683
3079
|
*
|
|
2684
3080
|
* @param input - The complete operations, progress, and constraints replacement
|
|
2685
3081
|
* @returns The accepted immutable frame; `MUTATION` for invalid input or `TRANSITION` when not running
|
|
2686
3082
|
*/
|
|
2687
3083
|
report(input: TaskActivityInput): Result<TaskActivity, WorkflowError>;
|
|
2688
3084
|
/**
|
|
2689
|
-
*
|
|
3085
|
+
* Confirms liveness without replacing the current operations, progress, or constraints.
|
|
2690
3086
|
*
|
|
2691
|
-
* @returns
|
|
3087
|
+
* @returns True if the pulse was committed while the task is running; false otherwise
|
|
2692
3088
|
*/
|
|
2693
3089
|
pulse(): boolean;
|
|
2694
|
-
/**
|
|
3090
|
+
/** Suspends this task's cooperative gate while pending or running; idempotent. */
|
|
2695
3091
|
pause(): void;
|
|
2696
|
-
/**
|
|
3092
|
+
/** Continues this task's cooperative gate; idempotent. */
|
|
2697
3093
|
resume(): void;
|
|
2698
3094
|
/**
|
|
2699
|
-
*
|
|
3095
|
+
* Parks until this task is not paused.
|
|
2700
3096
|
*
|
|
2701
|
-
* @returns A promise that resolves
|
|
3097
|
+
* @returns A promise that resolves after the task gate is released
|
|
2702
3098
|
*/
|
|
2703
3099
|
wait(): Promise<void>;
|
|
2704
3100
|
/**
|
|
2705
|
-
*
|
|
3101
|
+
* Applies a validated declarative patch to SELF (`name` / `description`).
|
|
2706
3102
|
*
|
|
2707
3103
|
* @remarks
|
|
2708
|
-
* Defense-in-depth
|
|
3104
|
+
* Defense-in-depth: the owning {@link TaskManagerInterface.update} gates
|
|
2709
3105
|
* FIRST (target exists + `pending`), so a direct call here is the second, redundant
|
|
2710
3106
|
* check — it THROWS a `MUTATION` {@link import('./errors.js').WorkflowError} unless
|
|
2711
3107
|
* this task's own `status` is `pending`.
|
|
@@ -2721,25 +3117,30 @@ export declare interface TaskInterface {
|
|
|
2721
3117
|
}
|
|
2722
3118
|
|
|
2723
3119
|
/**
|
|
2724
|
-
*
|
|
2725
|
-
* tasks —
|
|
2726
|
-
* preserved across an interior `skip` / `remove`.
|
|
3120
|
+
* Implements the lean child manager of a {@link import('../phases/Phase.js').Phase}'s live
|
|
3121
|
+
* tasks — the task vocabulary over one insertion-ordered {@link Collection}, so positional order
|
|
3122
|
+
* is preserved across an interior `skip` / `remove`.
|
|
2727
3123
|
*
|
|
2728
3124
|
* @remarks
|
|
2729
|
-
* - **
|
|
2730
|
-
* `
|
|
2731
|
-
* `
|
|
2732
|
-
*
|
|
2733
|
-
*
|
|
2734
|
-
* - **
|
|
2735
|
-
*
|
|
2736
|
-
*
|
|
2737
|
-
*
|
|
2738
|
-
*
|
|
2739
|
-
*
|
|
2740
|
-
*
|
|
2741
|
-
*
|
|
2742
|
-
*
|
|
3125
|
+
* - **One shared store.** The insertion-ordered `Map`, the reorder step, the bounds checks, and
|
|
3126
|
+
* the gated `add` / `remove` / `move` / `update` all live in {@link Collection}, built with the
|
|
3127
|
+
* `task` noun its refusals name and the compiled {@link taskUpdateShape} guard. This class adds
|
|
3128
|
+
* the domain accessors `task` / `tasks` and nothing else, so the task and phase managers cannot
|
|
3129
|
+
* drift apart.
|
|
3130
|
+
* - **Positional store.** `append` adds one live {@link TaskInterface} at the end (the build-time
|
|
3131
|
+
* wiring path), `task(id)` looks one up, `tasks()` lists them in positional order, `count` is
|
|
3132
|
+
* the tally. A `skip` is a STATUS change on a stored task (never a removal), so order survives
|
|
3133
|
+
* it; a snapshot RESTORE re-`append`s in the snapshot's order, reproducing it exactly.
|
|
3134
|
+
* - **Gated mutation API.** `add` / `remove` / `move` / `update` are the graceful
|
|
3135
|
+
* `Result` counterparts to `append`, gating ONLY on the target's OWN existence/status/id/bounds
|
|
3136
|
+
* — a duplicate id, an absent/non-`pending` target, an out-of-bounds `index`, or a patch that
|
|
3137
|
+
* fails {@link taskUpdateShape} validation all fail gracefully with a `MUTATION`
|
|
3138
|
+
* {@link WorkflowError} instead of throwing.
|
|
3139
|
+
* - **No batch matrix.** A phase's tasks are a fixed positional set, so
|
|
3140
|
+
* `.claude/rules/patterns.md` § Batch operations (the bulk verb
|
|
3141
|
+
* overloads) is deliberately omitted — no `remove` family lives here.
|
|
3142
|
+
* - **Event-free.** A purely structural container — the live {@link TaskInterface}s own their own
|
|
3143
|
+
* emitters; the manager observes nothing.
|
|
2743
3144
|
*
|
|
2744
3145
|
* @example
|
|
2745
3146
|
* ```ts
|
|
@@ -2762,16 +3163,16 @@ export declare class TaskManager implements TaskManagerInterface {
|
|
|
2762
3163
|
}
|
|
2763
3164
|
|
|
2764
3165
|
/**
|
|
2765
|
-
*
|
|
3166
|
+
* Declares the lean child manager of a {@link PhaseInterface}'s live tasks —
|
|
2766
3167
|
* positional accessors plus `count`, backed by an insertion-ordered store so order
|
|
2767
3168
|
* is preserved across an interior `skip` / `remove`.
|
|
2768
3169
|
*
|
|
2769
3170
|
* @remarks
|
|
2770
3171
|
* `append` adds one live {@link TaskInterface} at the end (the build-time wiring path);
|
|
2771
3172
|
* `task(id)` looks one up; `tasks()` lists them in positional order; `count` is the
|
|
2772
|
-
* tally. No batch matrix (
|
|
2773
|
-
* fixed positional set, not a bulk-mutated collection). `add` / `remove` / `move` /
|
|
2774
|
-
* `update`
|
|
3173
|
+
* tally. No batch matrix (`.claude/rules/patterns.md` § Batch operations is deliberately omitted —
|
|
3174
|
+
* a phase's tasks are a fixed positional set, not a bulk-mutated collection). `add` / `remove` / `move` /
|
|
3175
|
+
* `update` are the GATED mutation counterparts a
|
|
2775
3176
|
* {@link PhaseInterface.add} / `remove` / `move` / `update` delegates to AFTER its own
|
|
2776
3177
|
* container-status/hook gating — the manager gates ONLY on the target's OWN
|
|
2777
3178
|
* existence/status/id/bounds and stays event-free (the entity emits on success).
|
|
@@ -2779,18 +3180,18 @@ export declare class TaskManager implements TaskManagerInterface {
|
|
|
2779
3180
|
export declare interface TaskManagerInterface {
|
|
2780
3181
|
readonly count: number;
|
|
2781
3182
|
/**
|
|
2782
|
-
*
|
|
3183
|
+
* Adds `task` at the end (the build-time wiring path).
|
|
2783
3184
|
*
|
|
2784
3185
|
* @remarks
|
|
2785
3186
|
* THROWS a `MUTATION` {@link import('./errors.js').WorkflowError} on a duplicate
|
|
2786
|
-
* `id` (a genuine programmer error — a build-time wiring bug
|
|
3187
|
+
* `id` (a genuine programmer error — a build-time wiring bug) instead of
|
|
2787
3188
|
* silently overwriting the existing entry.
|
|
2788
3189
|
*
|
|
2789
3190
|
* @param task - The live task to append
|
|
2790
3191
|
*/
|
|
2791
3192
|
append(task: TaskInterface): void;
|
|
2792
3193
|
/**
|
|
2793
|
-
*
|
|
3194
|
+
* Inserts `task` at `index` (default the end) — the GATED mutation counterpart to
|
|
2794
3195
|
* {@link append}: a duplicate `id` or an out-of-bounds `index` fails gracefully
|
|
2795
3196
|
* instead of throwing.
|
|
2796
3197
|
*
|
|
@@ -2800,7 +3201,7 @@ export declare interface TaskManagerInterface {
|
|
|
2800
3201
|
*/
|
|
2801
3202
|
add(task: TaskInterface, index?: number): Result<TaskInterface, WorkflowError>;
|
|
2802
3203
|
/**
|
|
2803
|
-
*
|
|
3204
|
+
* Removes the `pending` task `id`.
|
|
2804
3205
|
*
|
|
2805
3206
|
* @param id - The task id to remove
|
|
2806
3207
|
* @returns A {@link Result} boxing the removed task, or a `MUTATION` failure when
|
|
@@ -2808,7 +3209,7 @@ export declare interface TaskManagerInterface {
|
|
|
2808
3209
|
*/
|
|
2809
3210
|
remove(id: string): Result<TaskInterface, WorkflowError>;
|
|
2810
3211
|
/**
|
|
2811
|
-
*
|
|
3212
|
+
* Repositions the `pending` task `id` to `index`.
|
|
2812
3213
|
*
|
|
2813
3214
|
* @param id - The task id to move
|
|
2814
3215
|
* @param index - The destination position (`[0, count)`)
|
|
@@ -2817,7 +3218,7 @@ export declare interface TaskManagerInterface {
|
|
|
2817
3218
|
*/
|
|
2818
3219
|
move(id: string, index: number): Result<TaskInterface, WorkflowError>;
|
|
2819
3220
|
/**
|
|
2820
|
-
*
|
|
3221
|
+
* Applies a validated {@link TaskUpdate} patch to the `pending` task `id`.
|
|
2821
3222
|
*
|
|
2822
3223
|
* @param id - The task id to patch
|
|
2823
3224
|
* @param patch - The fields to update
|
|
@@ -2830,24 +3231,21 @@ export declare interface TaskManagerInterface {
|
|
|
2830
3231
|
}
|
|
2831
3232
|
|
|
2832
3233
|
/**
|
|
2833
|
-
*
|
|
3234
|
+
* Represents one operation claimed active when a running task's complete frame was accepted.
|
|
2834
3235
|
*
|
|
2835
3236
|
* @remarks
|
|
2836
|
-
* `id` is stable within one complete activity report, `name` is the
|
|
2837
|
-
* and `started` is a finite non-negative reporter timestamp.
|
|
3237
|
+
* A {@link TaskClaim}: `id` is stable within one complete activity report, `name` is the
|
|
3238
|
+
* human-readable label, and `started` is a finite non-negative reporter timestamp.
|
|
2838
3239
|
*/
|
|
2839
|
-
export declare interface TaskOperation {
|
|
2840
|
-
readonly id: string;
|
|
2841
|
-
readonly name: string;
|
|
2842
|
-
readonly started: number;
|
|
3240
|
+
export declare interface TaskOperation extends TaskClaim {
|
|
2843
3241
|
}
|
|
2844
3242
|
|
|
2845
3243
|
/**
|
|
2846
|
-
*
|
|
3244
|
+
* Declares the runtime options for a {@link TaskInterface} — the construction bag the live
|
|
2847
3245
|
* leaf state machine (W-b) carries that the W-a {@link TaskDefinition} did not.
|
|
2848
3246
|
*
|
|
2849
3247
|
* @remarks
|
|
2850
|
-
* The reserved `on`
|
|
3248
|
+
* The reserved `on` wires initial {@link TaskEventMap} listeners; a
|
|
2851
3249
|
* {@link import('./factories.js').createWorkflow}-built tree threads each level's `on`
|
|
2852
3250
|
* from its parent options, the same way a {@link WorkflowInterface.add} /
|
|
2853
3251
|
* {@link PhaseInterface.add} mint threads a leaf's `on` from ITS options. `metadata` is
|
|
@@ -2855,17 +3253,17 @@ export declare interface TaskOperation {
|
|
|
2855
3253
|
* {@link TaskInput.metadata}), never interpreted by the workflow.
|
|
2856
3254
|
*/
|
|
2857
3255
|
export declare interface TaskOptions {
|
|
2858
|
-
readonly on?:
|
|
2859
|
-
/**
|
|
3256
|
+
readonly on?: EmitterHooks<TaskEventMap>;
|
|
3257
|
+
/** Holds the emitter's listener-error handler — a listener throw routes here, not to a domain event. */
|
|
2860
3258
|
readonly error?: EmitterErrorHandler;
|
|
2861
|
-
/**
|
|
3259
|
+
/** Holds an open consumer bag — stored and snapshotted, never interpreted by the workflow. */
|
|
2862
3260
|
readonly metadata?: JSONRecord;
|
|
2863
|
-
/**
|
|
3261
|
+
/** Sets the runtime-only silence window; non-positive, non-finite, or over-`MAX_TIMER_MS` disables inheritance. */
|
|
2864
3262
|
readonly silence?: number;
|
|
2865
3263
|
}
|
|
2866
3264
|
|
|
2867
3265
|
/**
|
|
2868
|
-
*
|
|
3266
|
+
* Represents the aggregate progress most recently reported by a running task.
|
|
2869
3267
|
*
|
|
2870
3268
|
* @remarks
|
|
2871
3269
|
* `progress` and an optional `total` are finite non-negative numbers; when `total` is present
|
|
@@ -2878,41 +3276,58 @@ export declare interface TaskProgress {
|
|
|
2878
3276
|
readonly message?: string;
|
|
2879
3277
|
}
|
|
2880
3278
|
|
|
3279
|
+
/**
|
|
3280
|
+
* Represents the structured outcome of a task execution — its full lineage, its terminal
|
|
3281
|
+
* status, the moment it settled, and its boxed produced outcome.
|
|
3282
|
+
*
|
|
3283
|
+
* @remarks
|
|
3284
|
+
* Carries the complete lineage (`task` / `phase` / `workflow` contexts) so a result
|
|
3285
|
+
* is self-describing wherever it travels. `status` is the terminal state this
|
|
3286
|
+
* result records. `result` BOXES the produced outcome in a {@link Result}: it is
|
|
3287
|
+
* PRESENT exactly when `status` is `completed` (a {@link import('@orkestrel/contract').Success})
|
|
3288
|
+
* or `failed` (a {@link import('@orkestrel/contract').Failure}), and ABSENT when `status` is
|
|
3289
|
+
* `skipped` or `stopped` (terminal, but produced no outcome) — a pending/running
|
|
3290
|
+
* task has no result at all (a non-terminal status, per
|
|
3291
|
+
* {@link import('./helpers.js').isTerminalStatus}). This boxed `result` REPLACES separate
|
|
3292
|
+
* `value?` / `error?` fields: a success's payload is `result.value`, a failure's reason is `result.error`.
|
|
3293
|
+
* `timestamp` is when the result was created (ms since epoch).
|
|
3294
|
+
*/
|
|
2881
3295
|
export declare interface TaskResult {
|
|
2882
3296
|
readonly task: TaskContext;
|
|
2883
3297
|
readonly phase: PhaseContext;
|
|
2884
3298
|
readonly workflow: WorkflowContext;
|
|
2885
|
-
|
|
2886
|
-
|
|
3299
|
+
/** Holds the task's lifecycle status at the moment the result was recorded. */
|
|
3300
|
+
readonly status: LifecycleStatus;
|
|
3301
|
+
/** Holds the boxed outcome — present for `completed` (Success) / `failed` (Failure), absent otherwise. */
|
|
2887
3302
|
readonly result?: Result<JSONValue, TaskFailure>;
|
|
2888
3303
|
readonly timestamp: number;
|
|
2889
3304
|
}
|
|
2890
3305
|
|
|
2891
3306
|
/**
|
|
2892
|
-
*
|
|
2893
|
-
* `
|
|
3307
|
+
* Describes the shape of a {@link import('./types.js').TaskDefinition} — identity plus an optional
|
|
3308
|
+
* `behavior` behavior reference (a plain registry-key string, min length 1). `description` is
|
|
2894
3309
|
* optional prose.
|
|
2895
3310
|
*/
|
|
2896
3311
|
export declare const taskShape: ObjectShape<{
|
|
2897
3312
|
id: StringShape;
|
|
2898
3313
|
name: StringShape;
|
|
2899
3314
|
description: OptionalShape<StringShape>;
|
|
2900
|
-
|
|
3315
|
+
behavior: OptionalShape<StringShape>;
|
|
2901
3316
|
retries: OptionalShape<NumberShape>;
|
|
2902
3317
|
timeout: OptionalShape<NumberShape>;
|
|
2903
3318
|
}, false>;
|
|
2904
3319
|
|
|
2905
3320
|
/**
|
|
2906
|
-
*
|
|
3321
|
+
* Represents a JSON-serializable snapshot of one task's state — the leaf of the snapshot tree
|
|
2907
3322
|
* the durable store (W-d) persists.
|
|
2908
3323
|
*
|
|
2909
3324
|
* @remarks
|
|
2910
3325
|
* Pure JSON DATA (no class instances, no functions). `result` is the task's
|
|
2911
3326
|
* {@link TaskResult} when it has settled with an outcome, else `undefined`.
|
|
2912
3327
|
* `metadata` is the open consumer bag carried from the task's {@link TaskInput}.
|
|
2913
|
-
* `
|
|
3328
|
+
* `behavior` / `retries` / `timeout` are the DECLARATIVE config the task carries — persisted
|
|
2914
3329
|
* like a {@link PhaseSnapshot}'s `bail` / `concurrency`, so a restore reinstates the same
|
|
2915
|
-
* behavior reference and reliability overrides (`
|
|
3330
|
+
* behavior reference and reliability overrides (`behavior` re-resolves against the
|
|
2916
3331
|
* {@link WorkflowOptions.functions} registry supplied to
|
|
2917
3332
|
* {@link import('./factories.js').createRestoredWorkflow}); each omitted ⇒ the corresponding
|
|
2918
3333
|
* unset default.
|
|
@@ -2921,46 +3336,31 @@ export declare interface TaskSnapshot {
|
|
|
2921
3336
|
readonly id: string;
|
|
2922
3337
|
readonly name: string;
|
|
2923
3338
|
readonly description?: string;
|
|
2924
|
-
|
|
3339
|
+
/** Holds the task's persisted lifecycle status. */
|
|
3340
|
+
readonly status: LifecycleStatus;
|
|
2925
3341
|
readonly result?: TaskResult;
|
|
2926
3342
|
readonly metadata: JSONRecord;
|
|
2927
|
-
/**
|
|
3343
|
+
/** Counts total launches already consumed; zero while fresh and never reset by recovery. */
|
|
2928
3344
|
readonly attempts: number;
|
|
2929
|
-
/**
|
|
2930
|
-
readonly
|
|
2931
|
-
/**
|
|
3345
|
+
/** Names the behavior reference — a registry key resolved against {@link WorkflowRegistry} on restore/build. */
|
|
3346
|
+
readonly behavior?: string;
|
|
3347
|
+
/** Records the extra attempts after the first on failure (a non-negative integer); overrides the phase Runner default. */
|
|
2932
3348
|
readonly retries?: number;
|
|
2933
|
-
/**
|
|
3349
|
+
/** Records the workflow-owned per-attempt deadline (`0..MAX_TIMER_MS`); zero or omission means disabled. */
|
|
2934
3350
|
readonly timeout?: number;
|
|
2935
|
-
/**
|
|
3351
|
+
/** Holds the task's activity: pending omits it; running/completed/failed require it; skipped/stopped may retain it. */
|
|
2936
3352
|
readonly activity?: TaskActivity;
|
|
2937
3353
|
}
|
|
2938
3354
|
|
|
2939
3355
|
/**
|
|
2940
|
-
*
|
|
2941
|
-
* flight, then one of the terminal states: `completed` (a success), `failed` (a
|
|
2942
|
-
* genuine error), `skipped` (intentionally not executed, AGENTS §10 `skip`), or
|
|
2943
|
-
* `stopped` (permanently ended, AGENTS §10 `stop`).
|
|
2944
|
-
*
|
|
2945
|
-
* @remarks
|
|
2946
|
-
* A semantic tier of the shared {@link LifecycleStatus} vocabulary. Uses `running` /
|
|
2947
|
-
* `failed` (the project vocabulary), and keeps `skipped` and `stopped` DISTINCT — a
|
|
2948
|
-
* skip is "deliberately not run", a stop is "ended early". The terminal members are
|
|
2949
|
-
* exactly those for which a {@link TaskResult} is meaningful: `completed` / `failed`
|
|
2950
|
-
* box a {@link Result}, while `skipped` / `stopped` are terminal WITHOUT a boxed
|
|
2951
|
-
* outcome. See {@link import('./helpers.js').isTerminalStatus}.
|
|
2952
|
-
*/
|
|
2953
|
-
export declare type TaskStatus = LifecycleStatus;
|
|
2954
|
-
|
|
2955
|
-
/**
|
|
2956
|
-
* A declarative partial update to a {@link TaskInterface} — the fields a `pending`
|
|
3356
|
+
* Represents a declarative partial update to a {@link TaskInterface} — the fields a `pending`
|
|
2957
3357
|
* task's {@link TaskInterface.patch} (and the owning {@link TaskManagerInterface.update})
|
|
2958
|
-
* accept, runtime-validated
|
|
3358
|
+
* accept, runtime-validated through {@link import('./shapers.js').taskUpdateShape}.
|
|
2959
3359
|
*
|
|
2960
3360
|
* @remarks
|
|
2961
3361
|
* Mirrors the identity fields of {@link TaskDefinition} (`name` / `description`) —
|
|
2962
|
-
* never `
|
|
2963
|
-
* replace, not a patch) and never `id` (identity is immutable
|
|
3362
|
+
* never `behavior` / `retries` / `timeout` (a form/reliability change is a structural
|
|
3363
|
+
* replace, not a patch) and never `id` (identity is immutable after creation). Every
|
|
2964
3364
|
* field is optional; an omitted field is left unchanged.
|
|
2965
3365
|
*
|
|
2966
3366
|
* @example
|
|
@@ -2974,13 +3374,13 @@ export declare interface TaskUpdate {
|
|
|
2974
3374
|
}
|
|
2975
3375
|
|
|
2976
3376
|
/**
|
|
2977
|
-
*
|
|
3377
|
+
* Describes the shape of a {@link import('./types.js').TaskUpdate} — a partial edit to a
|
|
2978
3378
|
* `pending` task's `name` / `description`, both optional.
|
|
2979
3379
|
*
|
|
2980
3380
|
* @remarks
|
|
2981
3381
|
* Mirrors {@link taskShape}'s `name` / `description` constraints exactly (a provided
|
|
2982
|
-
* `name` still has `minLength: 1`); never `id` / `
|
|
2983
|
-
* are not patchable fields
|
|
3382
|
+
* `name` still has `minLength: 1`); never `id` / `behavior` / `retries` / `timeout` (those
|
|
3383
|
+
* are not patchable fields).
|
|
2984
3384
|
*/
|
|
2985
3385
|
export declare const taskUpdateShape: ObjectShape<{
|
|
2986
3386
|
name: OptionalShape<StringShape>;
|
|
@@ -2988,38 +3388,18 @@ export declare const taskUpdateShape: ObjectShape<{
|
|
|
2988
3388
|
}, false>;
|
|
2989
3389
|
|
|
2990
3390
|
/**
|
|
2991
|
-
*
|
|
3391
|
+
* Lists the {@link LifecycleStatus} values that are TERMINAL — a node in one of these will
|
|
2992
3392
|
* not transition further, frozen.
|
|
2993
3393
|
*
|
|
2994
3394
|
* @remarks
|
|
2995
3395
|
* The source of truth behind {@link import('./helpers.js').isTerminalStatus}.
|
|
2996
3396
|
* `pending` and `running` are the only non-terminal members.
|
|
2997
3397
|
*/
|
|
2998
|
-
export declare const
|
|
3398
|
+
export declare const TERMINAL_STATUSES: readonly LifecycleStatus[];
|
|
2999
3399
|
|
|
3000
3400
|
/**
|
|
3001
|
-
*
|
|
3002
|
-
*
|
|
3003
|
-
* absent result.
|
|
3004
|
-
*
|
|
3005
|
-
* @remarks
|
|
3006
|
-
* The runner records each settled unit's outcome through this shape: a success boxes the
|
|
3007
|
-
* resolved `value` (presence tracked by the union tag, so `undefined` is a valid result),
|
|
3008
|
-
* a failure carries the `error` (always `unknown`). The FIRST failure is fail-fast.
|
|
3009
|
-
*
|
|
3010
|
-
* @typeParam TResult - The value a unit resolves
|
|
3011
|
-
*/
|
|
3012
|
-
export declare type UnitOutcome<TResult> = {
|
|
3013
|
-
readonly ok: true;
|
|
3014
|
-
readonly value: TResult;
|
|
3015
|
-
} | {
|
|
3016
|
-
readonly ok: false;
|
|
3017
|
-
readonly error: unknown;
|
|
3018
|
-
};
|
|
3019
|
-
|
|
3020
|
-
/**
|
|
3021
|
-
* The live DERIVED state machine (W-b) for a whole workflow — the observable (AGENTS §13)
|
|
3022
|
-
* ROOT whose {@link WorkflowStatus} is computed from its phases under the `bail` policy and
|
|
3401
|
+
* Implements the live DERIVED state machine (W-b) for a whole workflow — the observable ROOT
|
|
3402
|
+
* whose {@link LifecycleStatus} is computed from its phases under the `bail` policy and
|
|
3023
3403
|
* recomputed reactively as the cascade propagates up from a task transition.
|
|
3024
3404
|
*
|
|
3025
3405
|
* @remarks
|
|
@@ -3032,7 +3412,7 @@ export declare type UnitOutcome<TResult> = {
|
|
|
3032
3412
|
* reachable ONLY under `bail: true` (a single failed task halts the workflow); under
|
|
3033
3413
|
* `bail: false` a failed phase folds into `completed`. `#recompute` diffs on each phase
|
|
3034
3414
|
* change; a CHANGE emits.
|
|
3035
|
-
* - **Override
|
|
3415
|
+
* - **Override.** `skip` / `stop` FORCE the status; an executed task-free pending tree
|
|
3036
3416
|
* may also be force-completed vacuously. The override is PERSISTED in the snapshot's own
|
|
3037
3417
|
* `override` field and restored DIRECTLY (no divergence guess). The snapshot also persists
|
|
3038
3418
|
* `bail`, so a restore re-derives status identically without a silent policy default.
|
|
@@ -3041,12 +3421,12 @@ export declare type UnitOutcome<TResult> = {
|
|
|
3041
3421
|
* navigate UP.
|
|
3042
3422
|
* - **Snapshot.** `snapshot()` serializes the whole live tree to a {@link WorkflowSnapshot} (pure
|
|
3043
3423
|
* JSON); {@link import('./factories.js').createRestoredWorkflow} rebuilds an equivalent live tree.
|
|
3044
|
-
* - **Observable
|
|
3424
|
+
* - **Observable.** The owned {@link emitter} ({@link WorkflowEventMap}) fires
|
|
3045
3425
|
* `start` / `complete` / `fail` / `pause` / `resume` / `skip` / `stop` after the
|
|
3046
3426
|
* corresponding status or runtime-gate change; the emitter isolates a listener throw and
|
|
3047
3427
|
* routes it to its `error` handler (the `error` option); `fail` carries the failing task's
|
|
3048
3428
|
* {@link TaskResult}.
|
|
3049
|
-
* - **Structural API
|
|
3429
|
+
* - **Structural API.** `add` / `remove` / `move` / `update` gate BEFORE
|
|
3050
3430
|
* delegating to {@link phases} (the manager gates the target's own existence/status/id/
|
|
3051
3431
|
* bounds), then emit the matching {@link WorkflowEventMap} event on success only. NATIVE,
|
|
3052
3432
|
* bottom-up gating (no runner-installed hook): refused outright while this workflow's own
|
|
@@ -3055,26 +3435,41 @@ export declare type UnitOutcome<TResult> = {
|
|
|
3055
3435
|
* {@link import('./helpers.js').deriveBoundary} over the live phases' statuses. A `pending`
|
|
3056
3436
|
* workflow's phases are all `pending`, so the boundary is `0` and every position is
|
|
3057
3437
|
* naturally accepted.
|
|
3058
|
-
* - **Runtime lifecycle
|
|
3438
|
+
* - **Runtime lifecycle.** `pause` / `resume` / `wait` gate execution at the runner's
|
|
3059
3439
|
* phase/task boundaries WITHOUT touching {@link status} — `paused` is runtime-only, never
|
|
3060
3440
|
* persisted. `destroy` is a terminal teardown: it `stop`s every non-terminal task and
|
|
3061
3441
|
* phase (releasing their gates and liveness resources), aborts {@link signal}, forces the
|
|
3062
3442
|
* workflow `stop` override when needed, releases its parked waiter, and marks
|
|
3063
3443
|
* {@link destroyed} — all idempotent.
|
|
3444
|
+
*
|
|
3445
|
+
* @example
|
|
3446
|
+
* ```ts
|
|
3447
|
+
* import { definitionToSnapshot, Workflow } from '@orkestrel/workflow'
|
|
3448
|
+
*
|
|
3449
|
+
* const definition = {
|
|
3450
|
+
* id: 'release',
|
|
3451
|
+
* name: 'Release',
|
|
3452
|
+
* phases: [{ id: 'build', name: 'Build', tasks: [{ id: 'compile', name: 'Compile' }] }],
|
|
3453
|
+
* }
|
|
3454
|
+
* const workflow = new Workflow(definitionToSnapshot(definition))
|
|
3455
|
+
* workflow.status // 'pending'
|
|
3456
|
+
* workflow.phase('build')?.task('compile')?.status // 'pending'
|
|
3457
|
+
* workflow.snapshot().id // 'release'
|
|
3458
|
+
* ```
|
|
3064
3459
|
*/
|
|
3065
3460
|
export declare class Workflow implements WorkflowInterface {
|
|
3066
3461
|
#private;
|
|
3067
|
-
readonly description?: string;
|
|
3068
3462
|
constructor(snapshot: WorkflowSnapshot, options?: WorkflowOptions);
|
|
3069
3463
|
get emitter(): EmitterInterface<WorkflowEventMap>;
|
|
3070
3464
|
get id(): string;
|
|
3071
3465
|
get name(): string;
|
|
3466
|
+
get description(): string | undefined;
|
|
3072
3467
|
get context(): WorkflowContext;
|
|
3073
3468
|
get bail(): boolean;
|
|
3074
3469
|
get paused(): boolean;
|
|
3075
3470
|
get destroyed(): boolean;
|
|
3076
3471
|
get signal(): AbortSignal;
|
|
3077
|
-
get status():
|
|
3472
|
+
get status(): LifecycleStatus;
|
|
3078
3473
|
get phases(): PhaseManagerInterface;
|
|
3079
3474
|
phase(id: string): PhaseInterface | undefined;
|
|
3080
3475
|
results(): readonly TaskResult[];
|
|
@@ -3092,14 +3487,11 @@ export declare class Workflow implements WorkflowInterface {
|
|
|
3092
3487
|
snapshot(): WorkflowSnapshot;
|
|
3093
3488
|
}
|
|
3094
3489
|
|
|
3095
|
-
/**
|
|
3096
|
-
export declare const WORKFLOW_STATUSES: readonly WorkflowStatus[];
|
|
3097
|
-
|
|
3098
|
-
/** A runner-owned durability boundary. */
|
|
3490
|
+
/** Names a runner-owned durability boundary. */
|
|
3099
3491
|
export declare type WorkflowCheckpoint = 'initial' | 'attempt' | 'settlement' | 'final';
|
|
3100
3492
|
|
|
3101
3493
|
/**
|
|
3102
|
-
*
|
|
3494
|
+
* Represents the ambient context of a workflow — the identity every level inherits.
|
|
3103
3495
|
*
|
|
3104
3496
|
* @remarks
|
|
3105
3497
|
* The root of the context chain: a {@link PhaseContext} and {@link TaskContext}
|
|
@@ -3113,13 +3505,13 @@ export declare interface WorkflowContext {
|
|
|
3113
3505
|
}
|
|
3114
3506
|
|
|
3115
3507
|
/**
|
|
3116
|
-
*
|
|
3508
|
+
* Represents the serializable definition of a whole workflow — its identity, its ordered
|
|
3117
3509
|
* phases, and the `bail` failure policy.
|
|
3118
3510
|
*
|
|
3119
3511
|
* @remarks
|
|
3120
3512
|
* Pure JSON DATA — the root a UI/LLM authors and the contract validates. `phases`
|
|
3121
3513
|
* are the workflow's phases, which run SEQUENTIALLY. `bail` is the failure policy
|
|
3122
|
-
* (a boolean behavioral toggle
|
|
3514
|
+
* (a boolean behavioral toggle): `false` (the default) is GRACEFUL —
|
|
3123
3515
|
* a failed leaf task is recorded as data and the workflow still completes; `true`
|
|
3124
3516
|
* is a database-transaction HALT — a single failed task propagates `failed` to the
|
|
3125
3517
|
* whole workflow. See {@link import('./helpers.js').deriveWorkflowStatus}.
|
|
@@ -3129,20 +3521,21 @@ export declare interface WorkflowDefinition {
|
|
|
3129
3521
|
readonly name: string;
|
|
3130
3522
|
readonly description?: string;
|
|
3131
3523
|
readonly phases: readonly PhaseDefinition[];
|
|
3132
|
-
/**
|
|
3524
|
+
/** Sets the failure policy: `false` (default) continues gracefully, `true` halts on the first failure. */
|
|
3133
3525
|
readonly bail?: boolean;
|
|
3134
3526
|
}
|
|
3135
3527
|
|
|
3136
3528
|
/**
|
|
3137
|
-
*
|
|
3529
|
+
* Represents an error raised by the workflow runtime.
|
|
3138
3530
|
*
|
|
3139
3531
|
* @remarks
|
|
3140
3532
|
* Carries a {@link WorkflowErrorCode} and an optional `context` bag naming the
|
|
3141
3533
|
* offending node id / status / parameter. Raised for an illegal lifecycle transition
|
|
3142
3534
|
* (`TRANSITION`), a structurally invalid {@link import('./types.js').WorkflowSnapshot}
|
|
3143
|
-
* boundary (`RESTORE`), a refused structural/activity edit (`MUTATION`),
|
|
3535
|
+
* boundary (`RESTORE`), a refused structural/activity edit (`MUTATION`), a host
|
|
3144
3536
|
* schedule refused before arming because the caller's `signal` is not a native
|
|
3145
|
-
* `AbortSignal` (`SCHEDULE`, delivered as a rejected promise)
|
|
3537
|
+
* `AbortSignal` (`SCHEDULE`, delivered as a rejected promise), or a broken internal
|
|
3538
|
+
* invariant (`INVARIANT`).
|
|
3146
3539
|
*/
|
|
3147
3540
|
export declare class WorkflowError extends Error {
|
|
3148
3541
|
readonly code: WorkflowErrorCode;
|
|
@@ -3151,12 +3544,12 @@ export declare class WorkflowError extends Error {
|
|
|
3151
3544
|
}
|
|
3152
3545
|
|
|
3153
3546
|
/**
|
|
3154
|
-
*
|
|
3155
|
-
* fault the live W-b state machine raises
|
|
3547
|
+
* Names the machine-readable code of a {@link import('./errors.js').WorkflowError} — the
|
|
3548
|
+
* fault the live W-b state machine raises.
|
|
3156
3549
|
*
|
|
3157
3550
|
* @remarks
|
|
3158
|
-
* - `TRANSITION` — an illegal state-machine transition (
|
|
3159
|
-
* not `pending`, or `complete`/`fail`ing one that is not `running`); the guard names
|
|
3551
|
+
* - `TRANSITION` — an illegal state-machine transition (for example, `start`ing a task
|
|
3552
|
+
* that is not `pending`, or `complete`/`fail`ing one that is not `running`); the guard names
|
|
3160
3553
|
* the offending current status + requested transition in the error `context`.
|
|
3161
3554
|
* - `RESTORE` — a {@link import('./factories.js').createRestoredWorkflow} given a structurally
|
|
3162
3555
|
* invalid {@link WorkflowSnapshot} (a status outside the lifecycle vocabulary).
|
|
@@ -3166,23 +3559,28 @@ export declare class WorkflowError extends Error {
|
|
|
3166
3559
|
* the NATIVE bottom-up gate — a terminal container, an edit targeting (or destined for)
|
|
3167
3560
|
* a position BEFORE the container's own pending-suffix boundary, or (a running phase)
|
|
3168
3561
|
* anything other than a pure append. The manager /
|
|
3169
|
-
* entity structural API
|
|
3562
|
+
* entity structural API returns it as a graceful `Result` `failure` —
|
|
3170
3563
|
* it NEVER throws for this code except {@link TaskInterface.patch} /
|
|
3171
3564
|
* {@link PhaseInterface.patch}'s defense-in-depth self-check and the build-time
|
|
3172
3565
|
* {@link TaskManagerInterface.append} / {@link PhaseManagerInterface.append} duplicate-id
|
|
3173
|
-
* guard (both genuine programmer-error paths
|
|
3566
|
+
* guard (both genuine programmer-error paths). The error `context` names
|
|
3174
3567
|
* the offending id / index / status.
|
|
3175
3568
|
* - `SCHEDULE` — {@link import('./helpers.js').scheduleHost} refused to arm host work
|
|
3176
3569
|
* because the caller passed a `signal` that is not a native `AbortSignal`. The refusal
|
|
3177
3570
|
* is a REJECTED promise, never a synchronous throw, so every scheduler backend settles
|
|
3178
3571
|
* the same way whatever the caller passed. The error `context` names the offending
|
|
3179
3572
|
* parameter (`signal`) and the `typeof` the caller supplied.
|
|
3573
|
+
* - `INVARIANT` — an internal invariant did not hold: a derived
|
|
3574
|
+
* `failed` node whose failing {@link TaskResult} is missing, or a tracked
|
|
3575
|
+
* {@link RunnerInterface} unit whose cancellation handle is absent. It is a programmer-error
|
|
3576
|
+
* guard on a path no input reaches, raised instead of fabricating a substitute value that
|
|
3577
|
+
* would type-check while masking the true cause. The error `context` names the offending node.
|
|
3180
3578
|
*/
|
|
3181
|
-
export declare type WorkflowErrorCode = 'TRANSITION' | 'RESTORE' | 'MUTATION' | 'SCHEDULE';
|
|
3579
|
+
export declare type WorkflowErrorCode = 'TRANSITION' | 'RESTORE' | 'MUTATION' | 'SCHEDULE' | 'INVARIANT';
|
|
3182
3580
|
|
|
3183
3581
|
/**
|
|
3184
|
-
*
|
|
3185
|
-
* lifecycle moments a fire-and-forget observer subscribes to
|
|
3582
|
+
* Declares the push observation surface of the workflow entity (W-b) — the
|
|
3583
|
+
* lifecycle moments a fire-and-forget observer subscribes to through
|
|
3186
3584
|
* `workflow.emitter.on`.
|
|
3187
3585
|
*
|
|
3188
3586
|
* @remarks
|
|
@@ -3193,40 +3591,39 @@ export declare type WorkflowErrorCode = 'TRANSITION' | 'RESTORE' | 'MUTATION' |
|
|
|
3193
3591
|
* `stop` when it was permanently ended. `add` / `remove`
|
|
3194
3592
|
* / `move` / `update` fire on a successful
|
|
3195
3593
|
* structural or patch edit through {@link WorkflowInterface.add} / `remove` / `move` /
|
|
3196
|
-
* `update`
|
|
3594
|
+
* `update` — never on a refused/gated one. A throwing listener never
|
|
3197
3595
|
* reaches the domain surface — the emitter isolates it and routes it to its OWN
|
|
3198
|
-
* `error` handler (the `error` option
|
|
3199
|
-
* `interface extends EventMap
|
|
3596
|
+
* `error` handler (the `error` option). Declared as a `type` alias (not
|
|
3597
|
+
* `interface extends EventMap`) so the type-literal satisfies `EventMap`
|
|
3200
3598
|
* structurally.
|
|
3201
3599
|
*/
|
|
3202
3600
|
export declare type WorkflowEventMap = {
|
|
3203
|
-
/**
|
|
3601
|
+
/** Signals that the workflow began — its `id`. */
|
|
3204
3602
|
readonly start: readonly [id: string];
|
|
3205
|
-
/**
|
|
3603
|
+
/** Signals that every phase settled successfully. */
|
|
3206
3604
|
readonly complete: readonly [];
|
|
3207
|
-
/**
|
|
3605
|
+
/** Signals that a phase failed under `bail` — the failing task's result. */
|
|
3208
3606
|
readonly fail: readonly [result: TaskResult];
|
|
3209
|
-
/**
|
|
3607
|
+
/** Signals that the workflow's runtime gate closed. */
|
|
3210
3608
|
readonly pause: readonly [];
|
|
3211
|
-
/**
|
|
3609
|
+
/** Signals that the workflow's runtime gate opened. */
|
|
3212
3610
|
readonly resume: readonly [];
|
|
3213
|
-
/**
|
|
3611
|
+
/** Signals that the workflow was intentionally skipped. */
|
|
3214
3612
|
readonly skip: readonly [];
|
|
3215
|
-
/**
|
|
3613
|
+
/** Signals that the workflow was permanently stopped. */
|
|
3216
3614
|
readonly stop: readonly [];
|
|
3217
|
-
/**
|
|
3615
|
+
/** Signals that a phase was inserted — the inserted phase + its final index. */
|
|
3218
3616
|
readonly add: readonly [phase: PhaseInterface, index: number];
|
|
3219
|
-
/**
|
|
3617
|
+
/** Signals that a phase was removed — the removed phase. */
|
|
3220
3618
|
readonly remove: readonly [phase: PhaseInterface];
|
|
3221
|
-
/**
|
|
3619
|
+
/** Signals that a phase was repositioned — the moved phase + its new index. */
|
|
3222
3620
|
readonly move: readonly [phase: PhaseInterface, index: number];
|
|
3223
|
-
/**
|
|
3621
|
+
/** Signals that a phase was patched — the patched phase. */
|
|
3224
3622
|
readonly update: readonly [phase: PhaseInterface];
|
|
3225
3623
|
};
|
|
3226
3624
|
|
|
3227
|
-
/**
|
|
3625
|
+
/** Represents a normalized persistence failure surfaced as workflow result data. */
|
|
3228
3626
|
export declare interface WorkflowFault {
|
|
3229
|
-
readonly origin: 'persistence';
|
|
3230
3627
|
readonly checkpoint: WorkflowCheckpoint;
|
|
3231
3628
|
readonly message: string;
|
|
3232
3629
|
readonly task?: string;
|
|
@@ -3234,9 +3631,9 @@ export declare interface WorkflowFault {
|
|
|
3234
3631
|
}
|
|
3235
3632
|
|
|
3236
3633
|
/**
|
|
3237
|
-
*
|
|
3238
|
-
* {@link TaskDefinition} runs, resolved BY NAME through the {@link
|
|
3239
|
-
* registry
|
|
3634
|
+
* Declares the registered behavior a `function`-form
|
|
3635
|
+
* {@link TaskDefinition} runs, resolved BY NAME through the {@link WorkflowRegistry}
|
|
3636
|
+
* registry — a function type the framework invokes.
|
|
3240
3637
|
*
|
|
3241
3638
|
* @remarks
|
|
3242
3639
|
* Receives a {@link TaskControllerInterface} — the running task's folded `signal`, its
|
|
@@ -3244,50 +3641,34 @@ export declare interface WorkflowFault {
|
|
|
3244
3641
|
* to earlier phases' {@link TaskResult}s. A returned value becomes the task's
|
|
3245
3642
|
* {@link import('@orkestrel/contract').Success} ({@link TaskInterface.complete}); a throw / rejection
|
|
3246
3643
|
* becomes its {@link import('@orkestrel/contract').Failure} ({@link TaskInterface.fail}). Long work
|
|
3247
|
-
*
|
|
3644
|
+
* must honour `controller.signal` (a workflow-level abort / timeout / budget, or — under
|
|
3248
3645
|
* `bail: true` — a sibling's failure, fires it) so a cancel stops it promptly.
|
|
3249
3646
|
*/
|
|
3250
3647
|
export declare type WorkflowFunction = (controller: TaskControllerInterface) => Promise<JSONValue> | JSONValue;
|
|
3251
3648
|
|
|
3252
|
-
/**
|
|
3253
|
-
* The `function`-task behavior registry — workflow function names mapped to their
|
|
3254
|
-
* {@link WorkflowFunction} handlers.
|
|
3255
|
-
*
|
|
3256
|
-
* @remarks
|
|
3257
|
-
* A live {@link TaskInterface} resolves its `run` name against this registry ONCE at
|
|
3258
|
-
* construction into its {@link TaskInterface.handler}. An omitted `run` is the deliberate
|
|
3259
|
-
* no-op case. A present name absent from the registry remains inspectable but makes the tree
|
|
3260
|
-
* non-drivable until restored with a matching handler. A plain record (not a manager) — the
|
|
3261
|
-
* registry is a lookup, with no lifecycle of its own.
|
|
3262
|
-
*/
|
|
3263
|
-
export declare type WorkflowFunctions = Readonly<Record<string, WorkflowFunction>>;
|
|
3264
|
-
|
|
3265
|
-
/** Initial {@link WorkflowEventMap} listeners — the reserved `on` option (AGENTS §8). */
|
|
3266
|
-
export declare type WorkflowHooks = EmitterHooks<WorkflowEventMap>;
|
|
3267
|
-
|
|
3268
|
-
/** The minimal data to create a workflow context — a partial {@link WorkflowContext}. */
|
|
3649
|
+
/** Represents the minimal data to create a workflow context — a partial {@link WorkflowContext}. */
|
|
3269
3650
|
export declare type WorkflowInput = Partial<WorkflowContext>;
|
|
3270
3651
|
|
|
3271
3652
|
/**
|
|
3272
|
-
*
|
|
3273
|
-
* observable
|
|
3653
|
+
* Declares the live derived state machine (W-b) for a whole {@link WorkflowDefinition} — the
|
|
3654
|
+
* observable root whose {@link LifecycleStatus} is DERIVED from its phases
|
|
3274
3655
|
* under the `bail` policy and recomputed reactively as the cascade propagates up.
|
|
3275
3656
|
*
|
|
3276
3657
|
* @remarks
|
|
3277
|
-
* - **Derived status.** `status` is computed
|
|
3658
|
+
* - **Derived status.** `status` is computed through
|
|
3278
3659
|
* {@link import('./helpers.js').deriveWorkflowStatus} over the live phases' statuses,
|
|
3279
3660
|
* feeding the definition's `bail`, UNLESS an override is in force. It recomputes when a
|
|
3280
3661
|
* phase's status changes (the top of the cascade); a CHANGE emits — `fail` carries the
|
|
3281
3662
|
* failing {@link TaskResult} (under `bail: true`).
|
|
3282
|
-
* - **Children.** `phases` is the lean {@link PhaseManagerInterface}
|
|
3663
|
+
* - **Children.** `phases` is the lean {@link PhaseManagerInterface};
|
|
3283
3664
|
* `phase(id)` / `phases().phases()` read in positional order. `results` collects ALL
|
|
3284
3665
|
* tasks' results across every phase (the workflow tier of the result tree).
|
|
3285
|
-
* - **Override.** `skip` / `stop`
|
|
3666
|
+
* - **Override.** `skip` / `stop` FORCE the workflow's status; `complete`
|
|
3286
3667
|
* may force only a task-free, otherwise-pending tree. The override survives a snapshot.
|
|
3287
3668
|
* - **Snapshot.** `snapshot()` serializes the whole live tree to a {@link WorkflowSnapshot}
|
|
3288
3669
|
* (pure JSON — structure + each node's status + recorded results + positional order);
|
|
3289
3670
|
* {@link createRestoredWorkflow} rebuilds an equivalent live tree.
|
|
3290
|
-
* - **Observable
|
|
3671
|
+
* - **Observable.** The owned {@link emitter} ({@link WorkflowEventMap}) fires
|
|
3291
3672
|
* `start` / `complete` / `fail` / `pause` / `resume` / `stop` after the corresponding
|
|
3292
3673
|
* status or runtime-gate change; the emitter isolates a listener throw and routes it to
|
|
3293
3674
|
* its `error` handler (the `error` option).
|
|
@@ -3296,48 +3677,50 @@ export declare interface WorkflowInterface {
|
|
|
3296
3677
|
readonly emitter: EmitterInterface<WorkflowEventMap>;
|
|
3297
3678
|
readonly id: string;
|
|
3298
3679
|
readonly name: string;
|
|
3299
|
-
|
|
3680
|
+
/** Holds this workflow's prose, or `undefined` when the definition or snapshot declared none. */
|
|
3681
|
+
readonly description: string | undefined;
|
|
3300
3682
|
readonly context: WorkflowContext;
|
|
3301
3683
|
readonly bail: boolean;
|
|
3302
|
-
|
|
3684
|
+
/** Holds this workflow's effective lifecycle status, derived from its phases unless an override is in force. */
|
|
3685
|
+
readonly status: LifecycleStatus;
|
|
3303
3686
|
readonly phases: PhaseManagerInterface;
|
|
3304
3687
|
/**
|
|
3305
|
-
*
|
|
3306
|
-
* never a {@link
|
|
3688
|
+
* Reports whether the workflow is paused (resumable); RUNTIME-ONLY —
|
|
3689
|
+
* never a {@link LifecycleStatus}, never persisted in a {@link WorkflowSnapshot} (a
|
|
3307
3690
|
* paused workflow's `status` still reports its ordinary `pending` / `running` value).
|
|
3308
3691
|
*/
|
|
3309
3692
|
readonly paused: boolean;
|
|
3310
|
-
/**
|
|
3693
|
+
/** Reports whether {@link destroy} has torn this workflow down; RUNTIME-ONLY, never persisted. */
|
|
3311
3694
|
readonly destroyed: boolean;
|
|
3312
3695
|
/**
|
|
3313
|
-
*
|
|
3696
|
+
* Holds this workflow's own cancellation signal — fires on {@link destroy}. RUNTIME-ONLY
|
|
3314
3697
|
* (implemented over `@orkestrel/abort`, AGENTS core precedent), never persisted.
|
|
3315
3698
|
*/
|
|
3316
3699
|
readonly signal: AbortSignal;
|
|
3317
|
-
/**
|
|
3700
|
+
/** Looks up one live phase by its `id`. */
|
|
3318
3701
|
phase(id: string): PhaseInterface | undefined;
|
|
3319
|
-
/**
|
|
3702
|
+
/** Lists every settled task's result across all phases, in positional order — the workflow tier of the result tree. */
|
|
3320
3703
|
results(): readonly TaskResult[];
|
|
3321
3704
|
/**
|
|
3322
|
-
*
|
|
3705
|
+
* Forces this workflow to `skipped`, overriding the derived value; idempotent.
|
|
3323
3706
|
*
|
|
3324
3707
|
* @remarks
|
|
3325
|
-
* A NO-OP
|
|
3708
|
+
* A NO-OP after `status` becomes terminal — a settled workflow cannot be re-forced.
|
|
3326
3709
|
* Always releases a parked {@link wait} waiter regardless (a terminal workflow has nothing
|
|
3327
3710
|
* left to pause for).
|
|
3328
3711
|
*/
|
|
3329
3712
|
skip(): void;
|
|
3330
3713
|
/**
|
|
3331
|
-
*
|
|
3714
|
+
* Forces this workflow to `stopped`, overriding the derived value; idempotent.
|
|
3332
3715
|
*
|
|
3333
3716
|
* @remarks
|
|
3334
|
-
* A NO-OP
|
|
3717
|
+
* A NO-OP after `status` becomes terminal — a settled workflow cannot be re-forced. Always
|
|
3335
3718
|
* releases a parked {@link wait} waiter regardless (a terminal workflow has nothing left to
|
|
3336
3719
|
* pause for).
|
|
3337
3720
|
*/
|
|
3338
3721
|
stop(): void;
|
|
3339
3722
|
/**
|
|
3340
|
-
*
|
|
3723
|
+
* Forces this workflow to `completed`, overriding the derived value.
|
|
3341
3724
|
*
|
|
3342
3725
|
* @remarks
|
|
3343
3726
|
* A NO-OP unless `status` is `pending` and the tree is genuinely vacuous: zero phases or
|
|
@@ -3346,11 +3729,11 @@ export declare interface WorkflowInterface {
|
|
|
3346
3729
|
*/
|
|
3347
3730
|
complete(): void;
|
|
3348
3731
|
/**
|
|
3349
|
-
*
|
|
3732
|
+
* Suspends the workflow (resumable); idempotent.
|
|
3350
3733
|
*
|
|
3351
3734
|
* @remarks
|
|
3352
|
-
* A no-op when already `paused`, when `status` is terminal, or
|
|
3353
|
-
* RUNTIME-ONLY
|
|
3735
|
+
* A no-op when already `paused`, when `status` is terminal, or after {@link destroyed} becomes true.
|
|
3736
|
+
* RUNTIME-ONLY — never a {@link LifecycleStatus}, never persisted in a
|
|
3354
3737
|
* {@link WorkflowSnapshot}. A driving {@link WorkflowRunnerInterface.execute} gates at the
|
|
3355
3738
|
* next phase boundary and before each task's own dispatch; an in-flight task body is
|
|
3356
3739
|
* never suspended mid-flight. **Pausing does NOT suspend the run's timeout / budget /
|
|
@@ -3366,7 +3749,7 @@ export declare interface WorkflowInterface {
|
|
|
3366
3749
|
*/
|
|
3367
3750
|
pause(): void;
|
|
3368
3751
|
/**
|
|
3369
|
-
*
|
|
3752
|
+
* Continues a paused workflow; idempotent — a no-op unless {@link paused}.
|
|
3370
3753
|
*
|
|
3371
3754
|
* @example
|
|
3372
3755
|
* ```ts
|
|
@@ -3376,7 +3759,7 @@ export declare interface WorkflowInterface {
|
|
|
3376
3759
|
*/
|
|
3377
3760
|
resume(): void;
|
|
3378
3761
|
/**
|
|
3379
|
-
*
|
|
3762
|
+
* Tears this workflow down — an atomic TERMINAL teardown: mark
|
|
3380
3763
|
* {@link destroyed}, pin non-terminal workflow/phase overrides to `stopped`, stop every
|
|
3381
3764
|
* non-terminal task, release gates and liveness resources, abort {@link signal}, then
|
|
3382
3765
|
* destroy task, phase, and workflow emitters in ownership order; idempotent.
|
|
@@ -3394,26 +3777,26 @@ export declare interface WorkflowInterface {
|
|
|
3394
3777
|
*/
|
|
3395
3778
|
destroy(): void;
|
|
3396
3779
|
/**
|
|
3397
|
-
*
|
|
3398
|
-
* busy-loop (
|
|
3780
|
+
* Parks until this workflow is not paused — **promise-parked**, never a timer or
|
|
3781
|
+
* busy-loop (mirrors {@link ControllerInterface.wait}'s doc style).
|
|
3399
3782
|
*
|
|
3400
3783
|
* @remarks
|
|
3401
3784
|
* Resolves IMMEDIATELY when not {@link paused}. While paused, parks until `resume` /
|
|
3402
3785
|
* `skip` / `stop` / `destroy` — each always releases a parked waiter (a permanently
|
|
3403
3786
|
* ended workflow has nothing left to pause for). NEVER rejects.
|
|
3404
3787
|
*
|
|
3405
|
-
* @returns A promise that resolves
|
|
3788
|
+
* @returns A promise that resolves after the workflow is no longer paused
|
|
3406
3789
|
*/
|
|
3407
3790
|
wait(): Promise<void>;
|
|
3408
3791
|
/**
|
|
3409
|
-
*
|
|
3410
|
-
* into this workflow (
|
|
3792
|
+
* Mints a live {@link PhaseInterface} (and its tasks) from `definition` and inserts it
|
|
3793
|
+
* into this workflow (the entity structural API) — gated BEFORE delegating
|
|
3411
3794
|
* to {@link phases}' manager.
|
|
3412
3795
|
*
|
|
3413
3796
|
* @remarks
|
|
3414
3797
|
* Converts `definition` → {@link PhaseSnapshot} and constructs the live phase (wired to
|
|
3415
3798
|
* THIS workflow, its recompute cascade, and its emitter hooks) plus each of its live
|
|
3416
|
-
* tasks — each task's `
|
|
3799
|
+
* tasks — each task's `behavior` / `retries` / `timeout` carried from its {@link TaskDefinition}
|
|
3417
3800
|
* and its {@link TaskInterface.handler} resolved against the workflow-level
|
|
3418
3801
|
* {@link WorkflowOptions.functions} registry (mirrors
|
|
3419
3802
|
* {@link import('./factories.js').createWorkflow}'s build-time resolution). The
|
|
@@ -3423,9 +3806,9 @@ export declare interface WorkflowInterface {
|
|
|
3423
3806
|
* {@link PhaseManagerInterface.add}'s own duplicate-id gate).
|
|
3424
3807
|
*
|
|
3425
3808
|
* NATIVE gating, purely from this workflow's own derived `status` and the phase list's
|
|
3426
|
-
* positions (
|
|
3427
|
-
* predecessor: refused outright while this workflow's own `status` is terminal or
|
|
3428
|
-
* {@link destroyed}. Otherwise the effective target position (`index ?? phases.count`)
|
|
3809
|
+
* positions (no runner-installed hook), UNCHANGED from the entity-taking
|
|
3810
|
+
* predecessor: refused outright while this workflow's own `status` is terminal or after
|
|
3811
|
+
* {@link destroyed} becomes true. Otherwise the effective target position (`index ?? phases.count`)
|
|
3429
3812
|
* must fall within the PENDING SUFFIX — the contiguous trailing run of `pending` phases
|
|
3430
3813
|
* (phases run sequentially, so every already-started phase forms a contiguous leading
|
|
3431
3814
|
* prefix); its boundary is {@link import('./helpers.js').deriveBoundary}. A `pending`
|
|
@@ -3439,20 +3822,20 @@ export declare interface WorkflowInterface {
|
|
|
3439
3822
|
*/
|
|
3440
3823
|
add(definition: PhaseDefinition, index?: number): Result<PhaseInterface, WorkflowError>;
|
|
3441
3824
|
/**
|
|
3442
|
-
*
|
|
3825
|
+
* Removes the `pending` phase `id` from this workflow.
|
|
3443
3826
|
*
|
|
3444
3827
|
* @remarks
|
|
3445
3828
|
* NATIVE gating: refused while this workflow's own `status` is terminal. Otherwise the
|
|
3446
3829
|
* target must exist at an index within the pending suffix (at or past
|
|
3447
3830
|
* {@link import('./helpers.js').deriveBoundary}) — the manager separately gates the
|
|
3448
|
-
* target's own `pending` status
|
|
3831
|
+
* target's own `pending` status.
|
|
3449
3832
|
*
|
|
3450
3833
|
* @param id - The phase id to remove
|
|
3451
3834
|
* @returns A {@link Result} boxing the removed phase, or a `MUTATION` failure
|
|
3452
3835
|
*/
|
|
3453
3836
|
remove(id: string): Result<PhaseInterface, WorkflowError>;
|
|
3454
3837
|
/**
|
|
3455
|
-
*
|
|
3838
|
+
* Repositions the `pending` phase `id` to `index` within this workflow.
|
|
3456
3839
|
*
|
|
3457
3840
|
* @remarks
|
|
3458
3841
|
* NATIVE gating: refused while this workflow's own `status` is terminal. Otherwise BOTH
|
|
@@ -3465,7 +3848,7 @@ export declare interface WorkflowInterface {
|
|
|
3465
3848
|
*/
|
|
3466
3849
|
move(id: string, index: number): Result<PhaseInterface, WorkflowError>;
|
|
3467
3850
|
/**
|
|
3468
|
-
*
|
|
3851
|
+
* Applies a validated {@link PhaseUpdate} patch to the `pending` phase `id` in this workflow.
|
|
3469
3852
|
*
|
|
3470
3853
|
* @remarks
|
|
3471
3854
|
* NATIVE gating: refused while this workflow's own `status` is terminal. Otherwise the
|
|
@@ -3480,14 +3863,15 @@ export declare interface WorkflowInterface {
|
|
|
3480
3863
|
}
|
|
3481
3864
|
|
|
3482
3865
|
/**
|
|
3483
|
-
*
|
|
3866
|
+
* Implements the store-backed registry of {@link WorkflowInterface}s keyed by `id`, in insertion order —
|
|
3484
3867
|
* the additive manager tier mirroring the `@orkestrel/agent` line's `ConversationManager` /
|
|
3485
3868
|
* `WorkspaceManager`. Event-free (a registry, like its twins); the observability lives on each
|
|
3486
3869
|
* {@link WorkflowInterface}.
|
|
3487
3870
|
*
|
|
3488
3871
|
* @remarks
|
|
3489
3872
|
* - **Registry.** Workflows live in an insertion-ordered `Map` keyed by `id`. `add(definition)`
|
|
3490
|
-
* mints a live {@link WorkflowInterface} through
|
|
3873
|
+
* mints a live {@link WorkflowInterface} through the same construction path
|
|
3874
|
+
* {@link import('./factories.js').createWorkflow} takes (flowing the manager's
|
|
3491
3875
|
* `functions` registry in) and stores it under `definition.id` — an already-present id
|
|
3492
3876
|
* OVERWRITES (last write wins). `count` is the map size, `workflow(id)` looks one up,
|
|
3493
3877
|
* `workflows()` lists them in insertion order.
|
|
@@ -3496,8 +3880,8 @@ export declare interface WorkflowInterface {
|
|
|
3496
3880
|
* earlier reads; wrong-key payloads reject with `RESTORE`. `save(id)` captures a registered
|
|
3497
3881
|
* workflow's snapshot at invocation and serializes same-id writes without coupling other ids.
|
|
3498
3882
|
* Both remain lenient without a store or registered id.
|
|
3499
|
-
* - **Removal.** `remove` drops one by id, or a batch (
|
|
3500
|
-
*
|
|
3883
|
+
* - **Removal.** `remove` drops one by id, or a batch (array overload FIRST) — `true` only when
|
|
3884
|
+
* every id was removed. `clear` empties the registry.
|
|
3501
3885
|
* - **No active pointer.** Unlike its `ConversationManager` / `WorkspaceManager` twins, there is
|
|
3502
3886
|
* no `active` / `switch` — nothing in the workflow domain renders "the current workflow".
|
|
3503
3887
|
*
|
|
@@ -3526,21 +3910,21 @@ export declare class WorkflowManager implements WorkflowManagerInterface {
|
|
|
3526
3910
|
}
|
|
3527
3911
|
|
|
3528
3912
|
/**
|
|
3529
|
-
*
|
|
3913
|
+
* Declares a store-backed registry of {@link WorkflowInterface}s keyed by their `id`, in insertion
|
|
3530
3914
|
* order — the additive manager tier mirroring `ConversationManagerInterface` /
|
|
3531
3915
|
* `WorkspaceManagerInterface` from the `@orkestrel/agent` line, adapted for the workflow
|
|
3532
|
-
* domain: `add` mints from a {@link WorkflowDefinition} (not an empty `Input`,
|
|
3916
|
+
* domain: `add` mints from a {@link WorkflowDefinition} (not an empty `Input`, because a
|
|
3533
3917
|
* workflow only exists relative to a definition), and the optional `store` seam's `open`
|
|
3534
|
-
* threads the manager's {@link
|
|
3918
|
+
* threads the manager's {@link WorkflowRegistry} registry so a HYDRATED workflow is
|
|
3535
3919
|
* immediately RUNNABLE, not merely a restored state mirror. NO `active` / `switch` pointer
|
|
3536
|
-
*
|
|
3920
|
+
* — the workflow domain has no consumer that renders "the current workflow" the
|
|
3537
3921
|
* way an agent context renders the active conversation/workspace.
|
|
3538
3922
|
*
|
|
3539
3923
|
* @remarks
|
|
3540
3924
|
* - **Registry.** `count` is how many are stored. `add(definition)` mints a live
|
|
3541
|
-
* {@link WorkflowInterface}
|
|
3925
|
+
* {@link WorkflowInterface} through {@link import('./factories.js').createWorkflow} (flowing
|
|
3542
3926
|
* this manager's `functions` registry in) and registers it under `definition.id` — an
|
|
3543
|
-
* already-present id OVERWRITES (last write wins,
|
|
3927
|
+
* already-present id OVERWRITES (last write wins, because `createWorkflow` keys the tree by
|
|
3544
3928
|
* the definition's own id). `workflow(id)` looks one up (`undefined` when absent);
|
|
3545
3929
|
* `workflows()` lists them in insertion order.
|
|
3546
3930
|
* - **Durable open / save (the optional `store` seam).** When a {@link WorkflowStoreInterface}
|
|
@@ -3562,8 +3946,8 @@ export declare class WorkflowManager implements WorkflowManagerInterface {
|
|
|
3562
3946
|
* `.save` — this is the workflow line's caller-driven persistence gaining the standard
|
|
3563
3947
|
* open/save seam, ADDITIVE alongside direct {@link WorkflowStoreInterface} use and
|
|
3564
3948
|
* {@link import('./factories.js').createRestoredWorkflow} (both remain valid).
|
|
3565
|
-
* - **Removal.** `remove` drops one by id, or a batch (
|
|
3566
|
-
* when
|
|
3949
|
+
* - **Removal.** `remove` drops one by id, or a batch (array overload FIRST) — `true` only
|
|
3950
|
+
* when every id was removed. `clear` empties the registry.
|
|
3567
3951
|
* - **Event-free.** A purely registry store — no `Emitter`, no events (each
|
|
3568
3952
|
* {@link WorkflowInterface} owns its own {@link WorkflowEventMap} emitter).
|
|
3569
3953
|
*
|
|
@@ -3583,7 +3967,7 @@ export declare interface WorkflowManagerInterface {
|
|
|
3583
3967
|
workflow(id: string): WorkflowInterface | undefined;
|
|
3584
3968
|
workflows(): readonly WorkflowInterface[];
|
|
3585
3969
|
/**
|
|
3586
|
-
*
|
|
3970
|
+
* Mints a live {@link WorkflowInterface} from `definition` (through
|
|
3587
3971
|
* {@link import('./factories.js').createWorkflow}, flowing this manager's `functions`
|
|
3588
3972
|
* registry in) and register it under `definition.id`.
|
|
3589
3973
|
*
|
|
@@ -3597,7 +3981,7 @@ export declare interface WorkflowManagerInterface {
|
|
|
3597
3981
|
*/
|
|
3598
3982
|
add(definition: WorkflowDefinition): WorkflowInterface;
|
|
3599
3983
|
/**
|
|
3600
|
-
*
|
|
3984
|
+
* Resolves a workflow by id — from the registry if present, else HYDRATED from the
|
|
3601
3985
|
* optional {@link WorkflowStoreInterface} (`store`), RUNNABLE (this manager's `functions`
|
|
3602
3986
|
* registry is threaded into the rehydration).
|
|
3603
3987
|
*
|
|
@@ -3605,7 +3989,7 @@ export declare interface WorkflowManagerInterface {
|
|
|
3605
3989
|
* - If `id` is ALREADY registered, it is returned directly — no store hit.
|
|
3606
3990
|
* - Same-id registry misses share one in-flight `store.get(id)` and resolve to the same live
|
|
3607
3991
|
* object. On a HIT the snapshot is
|
|
3608
|
-
* rehydrated into a fresh {@link WorkflowInterface}
|
|
3992
|
+
* rehydrated into a fresh {@link WorkflowInterface} through
|
|
3609
3993
|
* {@link import('./factories.js').createRestoredWorkflow}, flowing this manager's `functions`
|
|
3610
3994
|
* registry in (so the rehydrated tree carries real resolved `handler`s and can RESUME
|
|
3611
3995
|
* real work), registers it, and returns it. A payload whose own id differs from `id` rejects
|
|
@@ -3621,7 +4005,7 @@ export declare interface WorkflowManagerInterface {
|
|
|
3621
4005
|
*/
|
|
3622
4006
|
open(id: string): Promise<WorkflowInterface | undefined>;
|
|
3623
4007
|
/**
|
|
3624
|
-
*
|
|
4008
|
+
* Persists a REGISTERED workflow's {@link WorkflowInterface.snapshot} to the optional
|
|
3625
4009
|
* {@link WorkflowStoreInterface} (`store`).
|
|
3626
4010
|
*
|
|
3627
4011
|
* @remarks
|
|
@@ -3631,17 +4015,34 @@ export declare interface WorkflowManagerInterface {
|
|
|
3631
4015
|
* queued write. Otherwise (no store, OR an unknown id) it is a NO-OP returning `false`.
|
|
3632
4016
|
*
|
|
3633
4017
|
* @param id - The id of the registered workflow to persist
|
|
3634
|
-
* @returns
|
|
4018
|
+
* @returns True if the snapshot was persisted; false otherwise (no store, or an unknown id)
|
|
3635
4019
|
*/
|
|
3636
4020
|
save(id: string): Promise<boolean>;
|
|
4021
|
+
/**
|
|
4022
|
+
* Drops a batch of registered workflows, one per id.
|
|
4023
|
+
*
|
|
4024
|
+
* @remarks
|
|
4025
|
+
* The array overload is declared FIRST, so a list resolves to the batch form. Every id is
|
|
4026
|
+
* invalidated whether or not it was registered, so an absent id changes nothing else. An
|
|
4027
|
+
* empty list returns `true` vacuously — no id failed to be removed.
|
|
4028
|
+
*
|
|
4029
|
+
* @param ids - The workflow ids to drop
|
|
4030
|
+
* @returns True if every id was removed; false if any id was not registered
|
|
4031
|
+
*/
|
|
3637
4032
|
remove(ids: readonly string[]): boolean;
|
|
4033
|
+
/**
|
|
4034
|
+
* Drops one registered workflow by id.
|
|
4035
|
+
*
|
|
4036
|
+
* @param id - The workflow id to drop
|
|
4037
|
+
* @returns True if the id was registered and removed; false otherwise
|
|
4038
|
+
*/
|
|
3638
4039
|
remove(id: string): boolean;
|
|
3639
4040
|
clear(): void;
|
|
3640
4041
|
}
|
|
3641
4042
|
|
|
3642
4043
|
/**
|
|
3643
|
-
*
|
|
3644
|
-
* seam plus the {@link
|
|
4044
|
+
* Declares the options for `createWorkflowManager` — the optional durable {@link WorkflowStoreInterface}
|
|
4045
|
+
* seam plus the {@link WorkflowRegistry} registry every workflow the manager mints or
|
|
3645
4046
|
* hydrates resolves its tasks' handlers against.
|
|
3646
4047
|
*
|
|
3647
4048
|
* @remarks
|
|
@@ -3649,16 +4050,16 @@ export declare interface WorkflowManagerInterface {
|
|
|
3649
4050
|
* `WorkspaceManagerOptions.store` (the `@orkestrel/agent` line's store standard) — omitted ⇒
|
|
3650
4051
|
* the manager is registry-only: {@link WorkflowManagerInterface.open} resolves only what is
|
|
3651
4052
|
* already registered, and {@link WorkflowManagerInterface.save} is a no-op (`false`). `functions`
|
|
3652
|
-
* is the workflow-specific addition: the SAME {@link
|
|
4053
|
+
* is the workflow-specific addition: the SAME {@link WorkflowRegistry} registry threaded into
|
|
3653
4054
|
* every {@link import('./factories.js').createWorkflow} ({@link WorkflowManagerInterface.add})
|
|
3654
4055
|
* and every {@link import('./factories.js').createRestoredWorkflow}
|
|
3655
4056
|
* ({@link WorkflowManagerInterface.open}'s hydration path) the manager performs — so a
|
|
3656
4057
|
* hydrated workflow carries real resolved `handler`s and is RUNNABLE. Omitted ⇒ named work
|
|
3657
|
-
* remains inspectable but cannot be driven; omitted-`
|
|
4058
|
+
* remains inspectable but cannot be driven; omitted-`behavior` tasks remain deliberate no-ops.
|
|
3658
4059
|
*/
|
|
3659
4060
|
export declare interface WorkflowManagerOptions {
|
|
3660
4061
|
/**
|
|
3661
|
-
*
|
|
4062
|
+
* Holds the optional durable {@link WorkflowStoreInterface} backing
|
|
3662
4063
|
* {@link WorkflowManagerInterface.open} / {@link WorkflowManagerInterface.save} — a memory
|
|
3663
4064
|
* / JSON / SQLite / IndexedDB store a workflow is HYDRATED from (`open` a registry miss)
|
|
3664
4065
|
* and PERSISTED to (`save`). Omitted ⇒ the manager is registry-only: `open` resolves only
|
|
@@ -3666,30 +4067,31 @@ export declare interface WorkflowManagerOptions {
|
|
|
3666
4067
|
*/
|
|
3667
4068
|
readonly store?: WorkflowStoreInterface;
|
|
3668
4069
|
/**
|
|
3669
|
-
*
|
|
3670
|
-
* (`add`,
|
|
3671
|
-
* registry-miss path,
|
|
4070
|
+
* Holds the {@link WorkflowRegistry} registry threaded into every workflow this manager mints
|
|
4071
|
+
* (`add`, through {@link import('./factories.js').createWorkflow}) or hydrates (`open`'s
|
|
4072
|
+
* registry-miss path, through {@link import('./factories.js').createRestoredWorkflow}) — so a
|
|
3672
4073
|
* hydrated workflow is RUNNABLE, its tasks carrying real resolved `handler`s. Omitted ⇒
|
|
3673
4074
|
* named tasks remain inspectable but execution rejects them.
|
|
3674
4075
|
*/
|
|
3675
|
-
readonly functions?:
|
|
4076
|
+
readonly functions?: WorkflowRegistry;
|
|
3676
4077
|
}
|
|
3677
4078
|
|
|
3678
4079
|
/**
|
|
3679
|
-
*
|
|
4080
|
+
* Declares the runtime options for a {@link WorkflowInterface} — the construction bag the
|
|
3680
4081
|
* live derived workflow state machine (W-b) carries, the root {@link createWorkflow}
|
|
3681
4082
|
* accepts.
|
|
3682
4083
|
*
|
|
3683
4084
|
* @remarks
|
|
3684
|
-
* The reserved `on`
|
|
4085
|
+
* The reserved `on` wires initial {@link WorkflowEventMap} listeners.
|
|
3685
4086
|
* `phases` keys per-phase {@link PhaseOptions} by phase `id`, so the whole tree's
|
|
3686
4087
|
* initial listeners + per-task metadata can be supplied in one nested bag (the
|
|
3687
|
-
*
|
|
4088
|
+
* "entity is the key" grouping of `.claude/rules/names.md` § Group options by entity), each leaf
|
|
4089
|
+
* reachable by its lineage of ids.
|
|
3688
4090
|
*/
|
|
3689
4091
|
export declare interface WorkflowOptions {
|
|
3690
|
-
readonly on?:
|
|
4092
|
+
readonly on?: EmitterHooks<WorkflowEventMap>;
|
|
3691
4093
|
/**
|
|
3692
|
-
*
|
|
4094
|
+
* Sets the failure policy the live tree applies — the same boolean toggle as
|
|
3693
4095
|
* {@link WorkflowDefinition.bail}, fed to {@link import('./helpers.js').deriveWorkflowStatus}.
|
|
3694
4096
|
* {@link import('./factories.js').createWorkflow} defaults it to the definition's `bail`. A
|
|
3695
4097
|
* {@link WorkflowSnapshot} PERSISTS the policy, so {@link import('./factories.js').createRestoredWorkflow}
|
|
@@ -3697,114 +4099,140 @@ export declare interface WorkflowOptions {
|
|
|
3697
4099
|
* wins when supplied. Omitted on a fresh build ⇒ the graceful {@link import('./constants.js').DEFAULT_BAIL}.
|
|
3698
4100
|
*/
|
|
3699
4101
|
readonly bail?: boolean;
|
|
3700
|
-
/**
|
|
4102
|
+
/** Holds the emitter's listener-error handler — a listener throw routes here, not to a domain event. */
|
|
3701
4103
|
readonly error?: EmitterErrorHandler;
|
|
3702
|
-
/**
|
|
4104
|
+
/** Holds the per-phase {@link PhaseOptions}, keyed by the phase's `id`. */
|
|
3703
4105
|
readonly phases?: Readonly<Record<string, PhaseOptions>>;
|
|
3704
4106
|
/**
|
|
3705
|
-
*
|
|
3706
|
-
* {@link TaskDefinition.
|
|
4107
|
+
* Holds the `function`-task behavior registry ({@link WorkflowRegistry}) each live task's
|
|
4108
|
+
* {@link TaskDefinition.behavior} / {@link TaskSnapshot.behavior} name resolves against ONCE at
|
|
3707
4109
|
* construction into its runtime {@link TaskInterface.handler} — the SAME registry a
|
|
3708
4110
|
* fresh build ({@link import('./factories.js').createWorkflow}) and a restore
|
|
3709
4111
|
* ({@link import('./factories.js').createRestoredWorkflow}) both consume, and the same shape a
|
|
3710
4112
|
* live {@link WorkflowInterface.add} / {@link PhaseInterface.add} mint resolves a newly
|
|
3711
|
-
* minted task against. An omitted `
|
|
4113
|
+
* minted task against. An omitted `behavior` resolves to no handler and is the deliberate
|
|
3712
4114
|
* no-op form. A present name absent from `functions` also has no handler so exact restore
|
|
3713
4115
|
* remains inspectable, but {@link WorkflowRunnerInterface.execute} rejects that tree.
|
|
3714
|
-
* Omitted ⇒ an empty registry; only tasks that also omit `
|
|
4116
|
+
* Omitted ⇒ an empty registry; only tasks that also omit `behavior` are executable no-ops.
|
|
3715
4117
|
*/
|
|
3716
|
-
readonly functions?:
|
|
3717
|
-
/**
|
|
4118
|
+
readonly functions?: WorkflowRegistry;
|
|
4119
|
+
/** Sets the runtime-only default silence; non-positive, non-finite, or over-`MAX_TIMER_MS` disables it. */
|
|
3718
4120
|
readonly silence?: number;
|
|
3719
4121
|
}
|
|
3720
4122
|
|
|
3721
4123
|
/**
|
|
3722
|
-
*
|
|
4124
|
+
* Coordinates advanced run-local snapshot persistence with one writer and one coalesced most recent obligation.
|
|
3723
4125
|
*
|
|
3724
4126
|
* @remarks
|
|
3725
4127
|
* Normally composed by `WorkflowRunner.execute({ store })`; exported for hosts that need to
|
|
3726
4128
|
* coordinate the same required boundaries around their own runner integration.
|
|
4129
|
+
*
|
|
4130
|
+
* @example
|
|
4131
|
+
* ```ts
|
|
4132
|
+
* import { WorkflowPersistence, createMemoryWorkflowStore, createWorkflow } from '@orkestrel/workflow'
|
|
4133
|
+
*
|
|
4134
|
+
* const workflow = createWorkflow({ id: 'durable', name: 'Durable', phases: [] })
|
|
4135
|
+
* const persistence = new WorkflowPersistence(workflow, createMemoryWorkflowStore())
|
|
4136
|
+
* await persistence.checkpoint('initial')
|
|
4137
|
+
* const durable = await persistence.finalize()
|
|
4138
|
+
* persistence.detach() // idempotent after finalize
|
|
4139
|
+
* ```
|
|
3727
4140
|
*/
|
|
3728
4141
|
export declare class WorkflowPersistence implements WorkflowPersistenceInterface {
|
|
3729
4142
|
#private;
|
|
3730
4143
|
constructor(workflow: WorkflowInterface, store: WorkflowStoreInterface);
|
|
3731
4144
|
get fault(): WorkflowFault | undefined;
|
|
3732
4145
|
/**
|
|
3733
|
-
*
|
|
4146
|
+
* Persists every change through this required boundary.
|
|
3734
4147
|
*
|
|
3735
4148
|
* @param checkpoint - The boundary being made durable
|
|
3736
4149
|
* @param task - The task owning an attempt or settlement
|
|
3737
4150
|
* @param attempt - The persisted attempt number
|
|
3738
|
-
* @returns
|
|
4151
|
+
* @returns True if the most recent state reached the store; false otherwise
|
|
3739
4152
|
*/
|
|
3740
4153
|
checkpoint(checkpoint: WorkflowCheckpoint, task?: TaskInterface, attempt?: number): Promise<boolean>;
|
|
3741
4154
|
/**
|
|
3742
|
-
*
|
|
4155
|
+
* Stops observing the live tree and persists its final state.
|
|
3743
4156
|
*
|
|
3744
|
-
* @returns
|
|
4157
|
+
* @returns True if the final snapshot reached the store; false otherwise
|
|
3745
4158
|
*/
|
|
3746
4159
|
finalize(): Promise<boolean>;
|
|
3747
|
-
/**
|
|
4160
|
+
/** Stops observing the live tree. */
|
|
3748
4161
|
detach(): void;
|
|
3749
4162
|
}
|
|
3750
4163
|
|
|
3751
4164
|
/**
|
|
3752
|
-
*
|
|
4165
|
+
* Declares the advanced run-local durability coordinator normally composed by
|
|
3753
4166
|
* {@link WorkflowRunnerInterface.execute} when `store` is supplied.
|
|
3754
4167
|
*/
|
|
3755
4168
|
export declare interface WorkflowPersistenceInterface {
|
|
3756
|
-
/**
|
|
4169
|
+
/** Records the first required checkpoint failure, if one occurred. */
|
|
3757
4170
|
readonly fault: WorkflowFault | undefined;
|
|
3758
4171
|
/**
|
|
3759
|
-
*
|
|
4172
|
+
* Makes the most recent state durable at one required boundary.
|
|
3760
4173
|
*
|
|
3761
4174
|
* @param checkpoint - The required durability boundary
|
|
3762
4175
|
* @param task - The task owning an attempt or settlement
|
|
3763
4176
|
* @param attempt - The persisted one-based attempt number
|
|
3764
|
-
* @returns
|
|
4177
|
+
* @returns True if the most recent live state reached the store; false otherwise
|
|
3765
4178
|
*/
|
|
3766
4179
|
checkpoint(checkpoint: WorkflowCheckpoint, task?: TaskInterface, attempt?: number): Promise<boolean>;
|
|
3767
|
-
/**
|
|
4180
|
+
/** Detaches observers and makes the final live state durable. */
|
|
3768
4181
|
finalize(): Promise<boolean>;
|
|
3769
|
-
/**
|
|
4182
|
+
/** Stops observing the live workflow tree; idempotent. */
|
|
3770
4183
|
detach(): void;
|
|
3771
4184
|
}
|
|
3772
4185
|
|
|
3773
4186
|
/**
|
|
3774
|
-
*
|
|
4187
|
+
* Declares the `function`-task behavior registry — workflow function names mapped to their
|
|
4188
|
+
* {@link WorkflowFunction} handlers.
|
|
4189
|
+
*
|
|
4190
|
+
* @remarks
|
|
4191
|
+
* A live {@link TaskInterface} resolves its `behavior` name against this registry ONCE at
|
|
4192
|
+
* construction into its {@link TaskInterface.handler}. An omitted `behavior` is the deliberate
|
|
4193
|
+
* no-op case. A present name absent from the registry remains inspectable but makes the tree
|
|
4194
|
+
* non-drivable until restored with a matching handler. A plain record (not a manager) — the
|
|
4195
|
+
* registry is a lookup, with no lifecycle of its own.
|
|
4196
|
+
*/
|
|
4197
|
+
export declare type WorkflowRegistry = Readonly<Record<string, WorkflowFunction>>;
|
|
4198
|
+
|
|
4199
|
+
/**
|
|
4200
|
+
* Represents the structured outcome of a {@link WorkflowRunnerInterface.execute} run — the settled
|
|
3775
4201
|
* live workflow, its final status, and the flattened result tree.
|
|
3776
4202
|
*
|
|
3777
4203
|
* @remarks
|
|
3778
4204
|
* Boxes the settled {@link WorkflowInterface} itself (so a caller can navigate the whole
|
|
3779
4205
|
* live tree — every phase / task's final `status`, its recorded {@link TaskResult}, its
|
|
3780
4206
|
* lineage) ALONGSIDE the two read-throughs the run produced: `status` is the workflow's
|
|
3781
|
-
* derived {@link
|
|
4207
|
+
* derived {@link LifecycleStatus} at settle (`completed` under graceful mode even with
|
|
3782
4208
|
* failed leaves; `failed` under `bail: true`; `stopped` on a workflow-level abort /
|
|
3783
4209
|
* timeout / budget), and `results` is the workflow-tier {@link TaskResult} list (every
|
|
3784
4210
|
* settled task across all phases, in positional order — the same array `workflow.results()`
|
|
3785
|
-
* yields). Returning the live `workflow` (not
|
|
4211
|
+
* yields). Returning the live `workflow` (not only a snapshot) keeps the entity tree the
|
|
3786
4212
|
* source of truth — the runner adds only the convenience `status` / `results` projections.
|
|
3787
4213
|
* A scheduler or other engine-infrastructure failure rejects after the runner coherently
|
|
3788
4214
|
* stops remaining work and attempts final persistence.
|
|
3789
4215
|
*/
|
|
3790
4216
|
export declare interface WorkflowResult {
|
|
3791
4217
|
readonly workflow: WorkflowInterface;
|
|
3792
|
-
|
|
4218
|
+
/** Holds the workflow's derived lifecycle status at settle. */
|
|
4219
|
+
readonly status: LifecycleStatus;
|
|
3793
4220
|
readonly results: readonly TaskResult[];
|
|
3794
|
-
/**
|
|
4221
|
+
/** Reports whether the returned final state is stored; omitted when no store was supplied. */
|
|
3795
4222
|
readonly durable?: boolean;
|
|
3796
|
-
/**
|
|
4223
|
+
/** Records the first required persistence failure; omitted when none occurred. */
|
|
3797
4224
|
readonly fault?: WorkflowFault;
|
|
3798
4225
|
}
|
|
3799
4226
|
|
|
3800
4227
|
/**
|
|
3801
|
-
*
|
|
4228
|
+
* Implements the thin orchestrator that EXECUTES a live W-b workflow tree by COMPOSING the shipped
|
|
3802
4229
|
* substrate — phases sequential, tasks concurrent — dispatching each task through its OWN
|
|
3803
4230
|
* resolved handler under the `bail` policy.
|
|
3804
4231
|
*
|
|
3805
4232
|
* @remarks
|
|
3806
4233
|
* - **Composes, never re-implements.** Per-phase bounded concurrency is one
|
|
3807
|
-
* {@link createRunner} per phase (the substrate {@link RunnerInterface}
|
|
4234
|
+
* {@link createRunner} per phase (the substrate {@link import('./types.js').RunnerInterface}
|
|
4235
|
+
* over the workers
|
|
3808
4236
|
* `Queue`); `bail` maps onto that Runner's fail-fast vs settle-all; the run-level abort /
|
|
3809
4237
|
* timeout / budget / entity `signal` fold through the `@orkestrel/abort` signal contract,
|
|
3810
4238
|
* {@link createTimeout}, and `AbortSignal.any` (exactly as the agent runtime folds its bounds);
|
|
@@ -3818,15 +4246,15 @@ export declare interface WorkflowResult {
|
|
|
3818
4246
|
* resolved its own {@link import('./types.js').WorkflowFunction} into
|
|
3819
4247
|
* {@link import('./types.js').TaskInterface.handler} ONCE at construction (build, restore,
|
|
3820
4248
|
* or a live mint all resolve it identically, from {@link WorkflowOptions.functions}), so
|
|
3821
|
-
* dispatch is
|
|
4249
|
+
* dispatch is "invoke the task's own handler". Provider, protocol, and tool
|
|
3822
4250
|
* integrations remain application-owned {@link import('./types.js').WorkflowFunction}s
|
|
3823
4251
|
* composed into {@link WorkflowOptions.functions}. This module imports none of them.
|
|
3824
4252
|
* - **Two `execute` forms, one engine.** `execute(definition, options)` BUILDS the live tree
|
|
3825
|
-
* from a {@link WorkflowDefinition} (single source of truth for the `
|
|
4253
|
+
* from a {@link WorkflowDefinition} (single source of truth for the `behavior` / `concurrency`
|
|
3826
4254
|
* metadata); `execute(workflow, options)` DRIVES a caller-owned, ALREADY-BUILT
|
|
3827
|
-
* {@link WorkflowInterface} instead — the entity-native control surface
|
|
3828
|
-
* `pause` / `resume` / `add` / `stop` / `destroy` live on the entity itself). Both forms
|
|
3829
|
-
* converge on the SAME `#execute` engine: neither reads a `WorkflowDefinition`
|
|
4255
|
+
* {@link WorkflowInterface} instead — the entity-native control surface
|
|
4256
|
+
* (`pause` / `resume` / `add` / `stop` / `destroy` live on the entity itself). Both forms
|
|
4257
|
+
* converge on the SAME `#execute` engine: neither reads a `WorkflowDefinition` after the tree
|
|
3830
4258
|
* exists — `#runTask` reads each task's OWN {@link import('./types.js').TaskInterface.handler}
|
|
3831
4259
|
* / `retries` / `timeout`, and `#runPhase` reads each phase's OWN
|
|
3832
4260
|
* {@link PhaseInterface.concurrency} / `bail`, so a live `add`-minted phase or task (V5)
|
|
@@ -3840,7 +4268,7 @@ export declare interface WorkflowResult {
|
|
|
3840
4268
|
* for `spawn` to accept (the runner already drained) is swept `skip`ped afterward so the
|
|
3841
4269
|
* phase always reaches a coherent terminal state.
|
|
3842
4270
|
* - **Dispatch by handler.** `#runTask` invokes the live task's own
|
|
3843
|
-
* {@link import('./types.js').TaskInterface.handler} directly. An omitted `
|
|
4271
|
+
* {@link import('./types.js').TaskInterface.handler} directly. An omitted `behavior` deliberately
|
|
3844
4272
|
* auto-completes with JSON `null`; a present unresolved name is rejected by the synchronous
|
|
3845
4273
|
* execution claim and never false-completes.
|
|
3846
4274
|
* - **`bail` → substrate.** Under `bail: true` (halt) a genuine task failure `fail`s the leaf
|
|
@@ -3871,25 +4299,25 @@ export declare interface WorkflowResult {
|
|
|
3871
4299
|
* and the workflow is force-`stop`ped (settles `stopped`). Each task's
|
|
3872
4300
|
* {@link TaskController} signal `AbortSignal.any`-combines the substrate per-unit signal with
|
|
3873
4301
|
* `runSignal`, so a handler observes either cause directly.
|
|
3874
|
-
* - **Re-entrant-safe.** No shared per-run mutable field:
|
|
3875
|
-
*
|
|
3876
|
-
* state.
|
|
4302
|
+
* - **Re-entrant-safe.** No shared per-run mutable field: each `#execute` mints its own
|
|
4303
|
+
* {@link import('./RunHolder.js').RunHolder}, so a nested application-level `execute` cannot
|
|
4304
|
+
* clobber the outer run's state.
|
|
3877
4305
|
*/
|
|
3878
4306
|
export declare class WorkflowRunner implements WorkflowRunnerInterface {
|
|
3879
4307
|
#private;
|
|
3880
4308
|
constructor(scheduler: SchedulerInterface);
|
|
3881
4309
|
/**
|
|
3882
|
-
*
|
|
4310
|
+
* Executes a workflow definition to completion — BUILDS its live tree, runs the phases
|
|
3883
4311
|
* sequentially with each phase's tasks concurrent — resolving its terminal
|
|
3884
4312
|
* {@link WorkflowResult} (whose `workflow` is the freshly-built live tree).
|
|
3885
4313
|
*
|
|
3886
4314
|
* @remarks
|
|
3887
4315
|
* One-shot. The runner BUILDS the live tree from `definition` internally (one source of
|
|
3888
|
-
* truth — the per-task `
|
|
4316
|
+
* truth — the per-task `behavior` and per-phase `concurrency` come from the same definition
|
|
3889
4317
|
* the tree is constructed from, so the executed tree can never drift from the metadata).
|
|
3890
4318
|
* The {@link WorkflowOptions} part of `options` (initial `on` listeners, a `bail` override,
|
|
3891
4319
|
* the per-node `phases` bag, the {@link WorkflowOptions.functions} registry each task's
|
|
3892
|
-
* `
|
|
4320
|
+
* `behavior` resolves against) is forwarded to the build. Under `bail: false` (graceful) every
|
|
3893
4321
|
* task settles (a failure is recorded on its {@link TaskInterface}) and the workflow
|
|
3894
4322
|
* reaches `completed`; under `bail: true` (halt) the first failure aborts the in-flight
|
|
3895
4323
|
* sibling tasks AND `skip`s the remaining tasks / phases, settling the workflow `failed`. A
|
|
@@ -3901,7 +4329,8 @@ export declare class WorkflowRunner implements WorkflowRunnerInterface {
|
|
|
3901
4329
|
*
|
|
3902
4330
|
* @param definition - The {@link WorkflowDefinition} to build the live tree from and drive
|
|
3903
4331
|
* @param options - The construction options ({@link WorkflowOptions}: `on` / `bail` /
|
|
3904
|
-
* `phases` / `functions`) PLUS the per-run bounds (`signal` / `timeout` / `budget`)
|
|
4332
|
+
* `phases` / `functions`) PLUS the per-run bounds (`signal` / `timeout` / `budget`) and the
|
|
4333
|
+
* durable `store`
|
|
3905
4334
|
* @returns The run's terminal {@link WorkflowResult} (its `workflow` is the built tree)
|
|
3906
4335
|
* @example
|
|
3907
4336
|
* ```ts
|
|
@@ -3911,24 +4340,24 @@ export declare class WorkflowRunner implements WorkflowRunnerInterface {
|
|
|
3911
4340
|
*/
|
|
3912
4341
|
execute(definition: WorkflowDefinition, options?: WorkflowRunOptions): Promise<WorkflowResult>;
|
|
3913
4342
|
/**
|
|
3914
|
-
*
|
|
4343
|
+
* Drives an ALREADY-BUILT, CALLER-OWNED live {@link WorkflowInterface} — the entity-native
|
|
3915
4344
|
* counterpart to the definition-building {@link execute} overload.
|
|
3916
4345
|
*
|
|
3917
4346
|
* @remarks
|
|
3918
4347
|
* `createWorkflow` mints the live tree, this overload drives it, and the caller controls
|
|
3919
|
-
* the SAME entity mid-run
|
|
3920
|
-
*
|
|
4348
|
+
* the SAME entity mid-run through its own `pause` / `resume` / `add` / `stop` / `destroy`.
|
|
4349
|
+
* Requires `workflow.status === 'pending'`, `!workflow.destroyed`, and no
|
|
3921
4350
|
* prior execution claim. A process-local object-identity claim shared by all runner instances
|
|
3922
4351
|
* is acquired synchronously and never released, so a same-object second call throws a `TRANSITION`
|
|
3923
|
-
* {@link WorkflowError} before any asynchronous status change.
|
|
4352
|
+
* {@link WorkflowError} before any asynchronous status change. After acceptance, observable
|
|
3924
4353
|
* semantics are byte-identical to the `definition` form —
|
|
3925
4354
|
* except the phase loop RE-READS the live tree every iteration, so a caller's live `add`
|
|
3926
|
-
* mid-run is picked up and actually dispatched. `options` carries only the per-run
|
|
3927
|
-
* (`signal` / `timeout` / `budget`)
|
|
3928
|
-
* does not apply
|
|
4355
|
+
* mid-run is picked up and actually dispatched. `options` carries only the per-run run
|
|
4356
|
+
* controls — the bounds (`signal` / `timeout` / `budget`) and the durable `store` — because the
|
|
4357
|
+
* construction half of {@link WorkflowRunOptions} does not apply to a tree that already exists.
|
|
3929
4358
|
*
|
|
3930
4359
|
* @param workflow - The live {@link WorkflowInterface} to drive
|
|
3931
|
-
* @param options - The per-run bounds (`signal` / `timeout` / `budget`)
|
|
4360
|
+
* @param options - The per-run bounds (`signal` / `timeout` / `budget`) and the durable `store`
|
|
3932
4361
|
* @returns The run's terminal {@link WorkflowResult} (its `workflow` is the SAME entity passed in)
|
|
3933
4362
|
* @example
|
|
3934
4363
|
* ```ts
|
|
@@ -3943,43 +4372,43 @@ export declare class WorkflowRunner implements WorkflowRunnerInterface {
|
|
|
3943
4372
|
}
|
|
3944
4373
|
|
|
3945
4374
|
/**
|
|
3946
|
-
*
|
|
4375
|
+
* Declares a thin orchestrator that EXECUTES a live {@link WorkflowInterface} tree by composing the
|
|
3947
4376
|
* shipped substrate — phases sequential, tasks concurrent, each task dispatched through its
|
|
3948
4377
|
* OWN resolved handler under the `bail` policy.
|
|
3949
4378
|
*
|
|
3950
4379
|
* @remarks
|
|
3951
4380
|
* `execute(definition, options?)` BUILDS the live W-b entity tree from the definition itself
|
|
3952
|
-
* (
|
|
4381
|
+
* (through {@link import('./factories.js').createWorkflow}) and drives it to a terminal
|
|
3953
4382
|
* {@link WorkflowResult} — phases SEQUENTIALLY and, within each phase, the tasks CONCURRENTLY
|
|
3954
4383
|
* through ONE substrate {@link RunnerInterface} (concurrency =
|
|
3955
4384
|
* the phase's {@link PhaseDefinition.concurrency}). The definition is the SINGLE source of
|
|
3956
4385
|
* truth: the runner owns both the declarative state (the live tree it constructs) and the
|
|
3957
|
-
* EXECUTION-ONLY field the snapshot deliberately dropped — each task's `
|
|
4386
|
+
* EXECUTION-ONLY field the snapshot deliberately dropped — each task's `behavior` (resolved into
|
|
3958
4387
|
* its {@link TaskInterface.handler} once at construction, against
|
|
3959
4388
|
* {@link WorkflowOptions.functions}) and each phase's `concurrency` (so there is no
|
|
3960
4389
|
* separately-supplied workflow to drift from the definition). The freshly-built live tree is
|
|
3961
4390
|
* returned in {@link WorkflowResult.workflow}. The runner carries NO registry of its own — it
|
|
3962
|
-
*
|
|
4391
|
+
* invokes each task's OWN {@link TaskInterface.handler}; an omitted `behavior` is the only
|
|
3963
4392
|
* auto-completing no-op. The runner DRIVES the live entity (`start` → `complete` / `fail`), never
|
|
3964
4393
|
* re-implementing status. The `bail` policy maps onto the substrate's fail-fast (`bail: true`
|
|
3965
4394
|
* — the first failure aborts in-flight siblings and skips the rest) vs settle-all (`bail:
|
|
3966
4395
|
* false` — failures are recorded and the run finishes). The {@link WorkflowOptions} half of
|
|
3967
4396
|
* the options is forwarded to `createWorkflow` (initial listeners, a `bail` override,
|
|
3968
4397
|
* per-node options, the `functions` registry); the Abort / Timeout / Budget bounds fold per
|
|
3969
|
-
* run
|
|
4398
|
+
* run through `AbortSignal.any`, halting the run and `stop`ping the workflow. A second
|
|
3970
4399
|
* `execute(workflow, options?)` overload drives a CALLER-BUILT live tree instead — the
|
|
3971
|
-
* entity-native control surface (
|
|
4400
|
+
* entity-native control surface (`pause` / `resume` / `add` / `stop` /
|
|
3972
4401
|
* `destroy` live on {@link WorkflowInterface} itself); see its own doc for details.
|
|
3973
4402
|
*/
|
|
3974
4403
|
export declare interface WorkflowRunnerInterface {
|
|
3975
4404
|
/**
|
|
3976
|
-
*
|
|
4405
|
+
* Executes a workflow definition to completion — BUILDS its live tree, runs the phases
|
|
3977
4406
|
* sequentially with each phase's tasks concurrent — resolving its terminal
|
|
3978
4407
|
* {@link WorkflowResult} (whose `workflow` is the freshly-built live tree).
|
|
3979
4408
|
*
|
|
3980
4409
|
* @remarks
|
|
3981
4410
|
* One-shot. The runner BUILDS the live tree from `definition` internally (one source of
|
|
3982
|
-
* truth — the per-task `
|
|
4411
|
+
* truth — the per-task `behavior` (resolved into its {@link TaskInterface.handler}) and per-phase
|
|
3983
4412
|
* `concurrency` come from the same definition the tree is constructed from, so the executed
|
|
3984
4413
|
* tree can never drift from the metadata). The {@link WorkflowOptions} part of `options`
|
|
3985
4414
|
* (initial `on` listeners, a `bail` override, the per-node `phases` bag, the `functions`
|
|
@@ -3995,7 +4424,7 @@ export declare interface WorkflowRunnerInterface {
|
|
|
3995
4424
|
* the run as `stopped` — the cancel supersedes the same-tick failure, and that task's error
|
|
3996
4425
|
* is not recorded.
|
|
3997
4426
|
*
|
|
3998
|
-
* **Programmer-error exception
|
|
4427
|
+
* **Programmer-error exception.** A PATHOLOGICAL `definition` (for example, a
|
|
3999
4428
|
* duplicate phase or task `id`) THROWS SYNCHRONOUSLY at construction — before any phase
|
|
4000
4429
|
* runs, and before the returned `Promise` is even created — rather than resolving a
|
|
4001
4430
|
* failed/partial {@link WorkflowResult}. Unexpected scheduler or engine-infrastructure
|
|
@@ -4004,23 +4433,23 @@ export declare interface WorkflowRunnerInterface {
|
|
|
4004
4433
|
*
|
|
4005
4434
|
* @param definition - The {@link WorkflowDefinition} to build the live tree from and drive
|
|
4006
4435
|
* @param options - The construction options ({@link WorkflowOptions}: `on` / `bail` /
|
|
4007
|
-
* `phases`) PLUS the per-run bounds (`signal` / `timeout` / `budget`)
|
|
4436
|
+
* `phases`) PLUS the per-run bounds (`signal` / `timeout` / `budget`) and the durable `store`
|
|
4008
4437
|
* @returns The run's terminal {@link WorkflowResult} (its `workflow` is the built tree)
|
|
4009
4438
|
*/
|
|
4010
4439
|
execute(definition: WorkflowDefinition, options?: WorkflowRunOptions): Promise<WorkflowResult>;
|
|
4011
4440
|
/**
|
|
4012
|
-
*
|
|
4441
|
+
* Drives an ALREADY-BUILT, CALLER-OWNED live {@link WorkflowInterface} — the
|
|
4013
4442
|
* ENTITY-NATIVE counterpart to the definition-building {@link execute} overload.
|
|
4014
4443
|
*
|
|
4015
4444
|
* @remarks
|
|
4016
|
-
* The entity itself is
|
|
4445
|
+
* The entity itself is the single control surface (no separate run handle):
|
|
4017
4446
|
* `createWorkflow` mints the live tree, this overload drives it, and the caller
|
|
4018
|
-
* controls the SAME entity mid-run
|
|
4019
|
-
* `destroy
|
|
4447
|
+
* controls the SAME entity mid-run through its own `pause` / `resume` / `add` / `stop` /
|
|
4448
|
+
* `destroy`. Requires `workflow.status === 'pending'`,
|
|
4020
4449
|
* `!workflow.destroyed`, and no prior execution claim. A process-local object-identity claim
|
|
4021
4450
|
* shared by every runner instance is acquired synchronously and never released, so a same-object
|
|
4022
4451
|
* call throws a `TRANSITION` {@link import('./errors.js').WorkflowError} even before an
|
|
4023
|
-
* asynchronous status change.
|
|
4452
|
+
* asynchronous status change. After acceptance, phases run
|
|
4024
4453
|
* SEQUENTIALLY and, within each phase, tasks CONCURRENTLY — byte-identical observable
|
|
4025
4454
|
* semantics to the `definition`-form `execute` — except the phase loop RE-READS the
|
|
4026
4455
|
* live `workflow.phases` / each phase's live `tasks` every iteration (a cursor over
|
|
@@ -4029,30 +4458,31 @@ export declare interface WorkflowRunnerInterface {
|
|
|
4029
4458
|
* phase boundary AND before each task's dispatch (an in-flight task body is never
|
|
4030
4459
|
* suspended); `workflow.stop()` skips not-yet-started work gracefully; `workflow.destroy()`
|
|
4031
4460
|
* folds `workflow.signal` into the run's cancellation, aborting in-flight work
|
|
4032
|
-
* immediately. `options` carries only the per-run
|
|
4033
|
-
* `budget`) — the construction half of
|
|
4034
|
-
* does not apply
|
|
4461
|
+
* immediately. `options` carries only the per-run RUN CONTROLS — the bounds (`signal` /
|
|
4462
|
+
* `timeout` / `budget`) and the durable `store` — because the construction half of
|
|
4463
|
+
* {@link WorkflowRunOptions} does not apply to a tree that already exists.
|
|
4035
4464
|
*
|
|
4036
4465
|
* **Run round-trips through the snapshot.** Driving a tree rebuilt by
|
|
4037
4466
|
* {@link import('./factories.js').createRestoredWorkflow} behaves according to whether a
|
|
4038
|
-
* {@link
|
|
4039
|
-
* each task's `
|
|
4467
|
+
* {@link WorkflowRegistry} registry was supplied at that build: WITH a registry,
|
|
4468
|
+
* each task's `behavior` name is re-resolved against it, so a matched task carries a real
|
|
4040
4469
|
* handler and this overload actually DISPATCHES it, resuming real work. Without a registry,
|
|
4041
|
-
* the persisted {@link TaskInterface.
|
|
4470
|
+
* the persisted {@link TaskInterface.behavior} remains visible for inspection while `handler` is
|
|
4042
4471
|
* `undefined`, and this overload rejects the tree before dispatch. A quiescent recovered tree may contain
|
|
4043
4472
|
* terminal work plus pending work; a tree with any `running` leaf is not drivable.
|
|
4044
4473
|
*
|
|
4045
4474
|
* @param workflow - The live {@link WorkflowInterface} to drive (its own entity surface —
|
|
4046
4475
|
* `pause` / `resume` / `add` / `stop` / `destroy` — is the caller's control seam)
|
|
4047
|
-
* @param options - The per-run bounds (`signal` / `timeout` / `budget`)
|
|
4048
|
-
* half of {@link WorkflowRunOptions} does not apply (the tree
|
|
4476
|
+
* @param options - The per-run bounds (`signal` / `timeout` / `budget`) and the durable
|
|
4477
|
+
* `store`; the construction half of {@link WorkflowRunOptions} does not apply (the tree
|
|
4478
|
+
* already exists)
|
|
4049
4479
|
* @returns The run's terminal {@link WorkflowResult} (its `workflow` is the SAME entity passed in)
|
|
4050
4480
|
*/
|
|
4051
4481
|
execute(workflow: WorkflowInterface, options?: Omit<WorkflowRunOptions, keyof WorkflowOptions>): Promise<WorkflowResult>;
|
|
4052
4482
|
}
|
|
4053
4483
|
|
|
4054
4484
|
/**
|
|
4055
|
-
*
|
|
4485
|
+
* Declares the options for `createWorkflowRunner` — the optional pacing scheduler the runner
|
|
4056
4486
|
* paces phase boundaries with.
|
|
4057
4487
|
*
|
|
4058
4488
|
* @remarks
|
|
@@ -4063,8 +4493,8 @@ export declare interface WorkflowRunnerInterface {
|
|
|
4063
4493
|
* `yield` between phases). Omitted ⇒ the shipped cross-environment default
|
|
4064
4494
|
* ({@link createScheduler}).
|
|
4065
4495
|
*
|
|
4066
|
-
* The reserved `on` key
|
|
4067
|
-
* the W-b entities' OWN emitters (subscribe
|
|
4496
|
+
* The reserved `on` key is intentionally ABSENT: the runner is THIN and drives
|
|
4497
|
+
* the W-b entities' OWN emitters (subscribe through `workflow.emitter` / `phase.emitter` /
|
|
4068
4498
|
* `task.emitter`), so it owns no event map of its own — there is nothing for an `on` to
|
|
4069
4499
|
* wire. A future runner-level emitter would introduce its own `EmitterHooks` here.
|
|
4070
4500
|
*/
|
|
@@ -4073,12 +4503,13 @@ export declare interface WorkflowRunnerOptions {
|
|
|
4073
4503
|
}
|
|
4074
4504
|
|
|
4075
4505
|
/**
|
|
4076
|
-
*
|
|
4077
|
-
* CONSTRUCTION options ({@link WorkflowOptions}) PLUS the per-run
|
|
4078
|
-
* a deadline, and a cost ceiling), each
|
|
4506
|
+
* Declares the options for one {@link WorkflowRunnerInterface.execute} call — the live tree's
|
|
4507
|
+
* CONSTRUCTION options ({@link WorkflowOptions}) PLUS the per-run RUN CONTROLS: the bounds
|
|
4508
|
+
* (an external abort, a deadline, and a cost ceiling), each folded into every task's
|
|
4509
|
+
* cancellation, and the optional durable `store`.
|
|
4079
4510
|
*
|
|
4080
4511
|
* @remarks
|
|
4081
|
-
* `execute` is single-source: it BUILDS the live tree from the definition internally (
|
|
4512
|
+
* `execute` is single-source: it BUILDS the live tree from the definition internally (through
|
|
4082
4513
|
* {@link import('./factories.js').createWorkflow}), so these options carry BOTH halves of
|
|
4083
4514
|
* that one call —
|
|
4084
4515
|
* - the **construction** half is {@link WorkflowOptions} (`on` initial listeners, the `bail`
|
|
@@ -4086,9 +4517,10 @@ export declare interface WorkflowRunnerOptions {
|
|
|
4086
4517
|
* so construction-time emitter listeners, a `bail` override, and per-node options all apply
|
|
4087
4518
|
* to the tree it builds (`createWorkflow` resolves `bail` as `options.bail ?? definition.bail
|
|
4088
4519
|
* ?? DEFAULT_BAIL`); and
|
|
4089
|
-
* - the **run-control** half is the
|
|
4520
|
+
* - the **run-control** half is the bounds and the `store` below; the bounds feed the run-level
|
|
4521
|
+
* fold and the store makes the run durable.
|
|
4090
4522
|
*
|
|
4091
|
-
* The three bounds compose
|
|
4523
|
+
* The three bounds compose through `AbortSignal.any` (exactly as the agent runtime folds its
|
|
4092
4524
|
* own): a fire of ANY of them cancels every in-flight task (its
|
|
4093
4525
|
* {@link TaskControllerInterface.signal} fires) and HALTS the run — the remaining tasks
|
|
4094
4526
|
* and phases are `skip`ped and the workflow settles `stopped`.
|
|
@@ -4100,6 +4532,17 @@ export declare interface WorkflowRunnerOptions {
|
|
|
4100
4532
|
* `signal` and `start`s it. (A `max: 0` budget is exhausted from its first `start`, so it
|
|
4101
4533
|
* cancels the run at entry — a DIFFERENT primitive from the `timeout: 0` "no deadline" case.)
|
|
4102
4534
|
*
|
|
4535
|
+
* `store` is not a bound. Supplying a {@link WorkflowStoreInterface} makes the run DURABLE: the
|
|
4536
|
+
* runner composes a {@link WorkflowPersistenceInterface} over it and writes the live
|
|
4537
|
+
* {@link WorkflowSnapshot} at each required checkpoint — before the first phase, around every
|
|
4538
|
+
* attempt and settlement, and once more when the run finishes — so an interrupted run is
|
|
4539
|
+
* recoverable from the store through
|
|
4540
|
+
* {@link import('./factories.js').createRecoveredWorkflow}. It also adds the two durability
|
|
4541
|
+
* read-throughs to the result: {@link WorkflowResult.durable} reports whether the FINAL state
|
|
4542
|
+
* reached the store, and {@link WorkflowResult.fault} carries the first required write that
|
|
4543
|
+
* failed. Both are OMITTED without a store, because a run that was never asked to persist has
|
|
4544
|
+
* nothing to report. A required checkpoint that fails stops the run rather than continuing work
|
|
4545
|
+
* whose state is no longer recoverable. This half applies to BOTH `execute` overloads.
|
|
4103
4546
|
*/
|
|
4104
4547
|
export declare type WorkflowRunOptions = WorkflowOptions & {
|
|
4105
4548
|
readonly signal?: AbortSignal;
|
|
@@ -4109,7 +4552,7 @@ export declare type WorkflowRunOptions = WorkflowOptions & {
|
|
|
4109
4552
|
};
|
|
4110
4553
|
|
|
4111
4554
|
/**
|
|
4112
|
-
*
|
|
4555
|
+
* Describes the shape of a {@link import('./types.js').WorkflowDefinition} — the contract root:
|
|
4113
4556
|
* identity, its ordered {@link phaseShape} phases, and the optional `bail` boolean
|
|
4114
4557
|
* failure policy (the literal pair `true`/`false`, the runtime mirror of the boolean
|
|
4115
4558
|
* toggle; omitted ⇒ the graceful default).
|
|
@@ -4126,7 +4569,7 @@ export declare const workflowShape: ObjectShape<{
|
|
|
4126
4569
|
id: StringShape;
|
|
4127
4570
|
name: StringShape;
|
|
4128
4571
|
description: OptionalShape<StringShape>;
|
|
4129
|
-
|
|
4572
|
+
behavior: OptionalShape<StringShape>;
|
|
4130
4573
|
retries: OptionalShape<NumberShape>;
|
|
4131
4574
|
timeout: OptionalShape<NumberShape>;
|
|
4132
4575
|
}, false>>;
|
|
@@ -4137,7 +4580,7 @@ export declare const workflowShape: ObjectShape<{
|
|
|
4137
4580
|
}, false>;
|
|
4138
4581
|
|
|
4139
4582
|
/**
|
|
4140
|
-
*
|
|
4583
|
+
* Represents a JSON-serializable snapshot of a whole workflow's state — its identity, status, its
|
|
4141
4584
|
* forced override (if any), the `bail` policy it ran under, its nested phase snapshots,
|
|
4142
4585
|
* and creation / update timestamps.
|
|
4143
4586
|
*
|
|
@@ -4145,7 +4588,7 @@ export declare const workflowShape: ObjectShape<{
|
|
|
4145
4588
|
* Pure JSON DATA — the COMPLETE, SELF-CONTAINED payload the durable store (W-d) persists,
|
|
4146
4589
|
* designed in full at W-a so its shape is fixed from the start. It can be written to disk,
|
|
4147
4590
|
* sent to a prompt companion, loaded across conversations, or reviewed by an agent. Because
|
|
4148
|
-
* it is self-contained, it carries the policy it ran under: `bail`
|
|
4591
|
+
* it is self-contained, it carries the policy it ran under: `bail` is the
|
|
4149
4592
|
* failure policy, so {@link import('./factories.js').createRestoredWorkflow} re-derives status
|
|
4150
4593
|
* IDENTICALLY without a silent default. `status` is the EFFECTIVE status (override-or-derived)
|
|
4151
4594
|
* at snapshot time; `override` is the forced status of a whole-workflow `skip` / `stop` or
|
|
@@ -4158,21 +4601,19 @@ export declare interface WorkflowSnapshot {
|
|
|
4158
4601
|
readonly id: string;
|
|
4159
4602
|
readonly name: string;
|
|
4160
4603
|
readonly description?: string;
|
|
4161
|
-
|
|
4162
|
-
|
|
4163
|
-
|
|
4164
|
-
|
|
4604
|
+
/** Holds the workflow's persisted effective lifecycle status (override-or-derived). */
|
|
4605
|
+
readonly status: LifecycleStatus;
|
|
4606
|
+
/** Records a whole-workflow `skip` / `stop` or a valid task-free vacuous `completed`; omitted when derived. */
|
|
4607
|
+
readonly override?: LifecycleStatus;
|
|
4608
|
+
/** Records the failure policy the workflow ran under — persisted so a restore re-derives identically. */
|
|
4165
4609
|
readonly bail: boolean;
|
|
4166
4610
|
readonly phases: readonly PhaseSnapshot[];
|
|
4167
4611
|
readonly created: number;
|
|
4168
4612
|
readonly updated: number;
|
|
4169
4613
|
}
|
|
4170
4614
|
|
|
4171
|
-
/** Locate the nearest identifiable node for an inconsistent owned snapshot. */
|
|
4172
|
-
export declare function workflowSnapshotContext(value: unknown): Readonly<Record<string, unknown>> | undefined;
|
|
4173
|
-
|
|
4174
4615
|
/**
|
|
4175
|
-
*
|
|
4616
|
+
* Represents one row of the table a {@link import('./stores/DatabaseWorkflowStore.js').DatabaseWorkflowStore}
|
|
4176
4617
|
* persists — a workflow `id` plus its {@link WorkflowSnapshot} held as ONE OPAQUE JSON column.
|
|
4177
4618
|
*
|
|
4178
4619
|
* @remarks
|
|
@@ -4181,30 +4622,22 @@ export declare function workflowSnapshotContext(value: unknown): Readonly<Record
|
|
|
4181
4622
|
* `@orkestrel/queue`'s `StoredEntry` stores a queue entry's `input`), so the row
|
|
4182
4623
|
* type stays FLAT and the deeply-nested snapshot shape (workflow → phases → tasks → results) never
|
|
4183
4624
|
* forces the contract to `Infer` it — sidestepping a TS2589 instantiation-depth blow-up. The column
|
|
4184
|
-
* therefore reads back as the broad `unknown`; the store narrows it to a
|
|
4185
|
-
* `get`
|
|
4625
|
+
* therefore reads back as the broad `unknown`; the store owns and narrows it to a
|
|
4626
|
+
* {@link WorkflowSnapshot} on `get` through {@link import('./cloners.js').cloneWorkflowSnapshot},
|
|
4627
|
+
* whose semantic pass is {@link import('./validators.js').isOwnedWorkflowSnapshot} — the
|
|
4628
|
+
* boundary narrow, which also key-checks the row and refuses a mismatch. The total guard
|
|
4629
|
+
* {@link import('./validators.js').isWorkflowSnapshot} is the same boundary narrow for a caller
|
|
4630
|
+
* holding an untrusted payload of its own. `id`
|
|
4186
4631
|
* mirrors {@link WorkflowSnapshot.id} (the primary key), so a `set` writes `{ id: snapshot.id, snapshot }`.
|
|
4187
4632
|
*/
|
|
4188
4633
|
export declare interface WorkflowSnapshotRow {
|
|
4189
4634
|
readonly id: string;
|
|
4190
|
-
/**
|
|
4635
|
+
/** Holds the whole {@link WorkflowSnapshot} as one opaque JSON blob — read back as `unknown`, narrowed on `get`. */
|
|
4191
4636
|
readonly snapshot: unknown;
|
|
4192
4637
|
}
|
|
4193
4638
|
|
|
4194
4639
|
/**
|
|
4195
|
-
*
|
|
4196
|
-
* derived from its phases' statuses under the `bail` policy.
|
|
4197
|
-
*
|
|
4198
|
-
* @remarks
|
|
4199
|
-
* A semantic tier of the shared {@link LifecycleStatus} vocabulary. `failed` is
|
|
4200
|
-
* reachable ONLY under `bail: true` (a single failed task halts the whole workflow);
|
|
4201
|
-
* under `bail: false` a workflow `completed`s even with failed leaf tasks. See
|
|
4202
|
-
* {@link import('./helpers.js').deriveWorkflowStatus}.
|
|
4203
|
-
*/
|
|
4204
|
-
export declare type WorkflowStatus = LifecycleStatus;
|
|
4205
|
-
|
|
4206
|
-
/**
|
|
4207
|
-
* The durable persistence seam for a {@link WorkflowSnapshot} — three async primitives
|
|
4640
|
+
* Declares the durable persistence seam for a {@link WorkflowSnapshot} — three async primitives
|
|
4208
4641
|
* (`get` / `set` / `delete`) keyed by a workflow id, the snapshot analogue of
|
|
4209
4642
|
* the server package's `SessionStoreInterface` (and the `@orkestrel/queue`
|
|
4210
4643
|
* `QueueStoreInterface` driver-swap pattern).
|
|
@@ -4225,11 +4658,12 @@ export declare type WorkflowStatus = LifecycleStatus;
|
|
|
4225
4658
|
* `id`). UNLIKE a session store there is NO idle-TTL / eviction — a persisted workflow run-state
|
|
4226
4659
|
* lives until an explicit `delete`, never silently expiring (it is durable orchestration state,
|
|
4227
4660
|
* not an ephemeral session). It is concrete over {@link WorkflowSnapshot} — no generic parameter
|
|
4228
|
-
* (
|
|
4661
|
+
* (the smallest interface the capability requires), because the snapshot is the ONE payload a
|
|
4662
|
+
* workflow store persists.
|
|
4229
4663
|
*/
|
|
4230
4664
|
export declare interface WorkflowStoreInterface {
|
|
4231
4665
|
/**
|
|
4232
|
-
*
|
|
4666
|
+
* Resolves the persisted snapshot for `id`, or `undefined` if none is stored.
|
|
4233
4667
|
* A present payload whose own `id` differs from the requested storage key is corrupt and
|
|
4234
4668
|
* rejects with a normalized `RESTORE` error carrying both ids.
|
|
4235
4669
|
*
|
|
@@ -4238,14 +4672,14 @@ export declare interface WorkflowStoreInterface {
|
|
|
4238
4672
|
*/
|
|
4239
4673
|
get(id: string): Promise<WorkflowSnapshot | undefined>;
|
|
4240
4674
|
/**
|
|
4241
|
-
*
|
|
4675
|
+
* Inserts or replaces a snapshot under its own `snapshot.id` (no separate id param —
|
|
4242
4676
|
* mirroring `QueueStoreInterface.save` from `@orkestrel/queue`).
|
|
4243
4677
|
*
|
|
4244
4678
|
* @param snapshot - The snapshot to store (keyed by its `id`)
|
|
4245
4679
|
*/
|
|
4246
4680
|
set(snapshot: WorkflowSnapshot): Promise<void>;
|
|
4247
4681
|
/**
|
|
4248
|
-
*
|
|
4682
|
+
* Drops a snapshot by id; an absent id is a no-op (no throw).
|
|
4249
4683
|
*
|
|
4250
4684
|
* @param id - The workflow id to drop
|
|
4251
4685
|
*/
|