@orkestrel/workflow 0.0.15 → 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.
@@ -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
- * Build a {@link PhaseContext} a phase's own identity plus a back-reference to its
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
- * Build a {@link TaskContext} — a task's own identity plus a back-reference to its phase
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
- * Build a {@link WorkflowContext} — the identity every level inherits — from a node's
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
- * Test whether the live W-b task state machine may move directly from one
59
- * {@link TaskStatus} to another — the legal-transition guard.
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 `true` when the move is legal
84
+ * @returns True if the move is legal; false otherwise
70
85
  */
71
- export declare function canTransitionTask(from: TaskStatus, to: TaskStatus): boolean;
86
+ export declare function canTransitionTask(from: LifecycleStatus, to: LifecycleStatus): boolean;
72
87
 
73
88
  /**
74
- * Capture every top-level {@link WorkflowOptions} value exactly once into an owned plain bag.
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
- * Validate and clone one complete task activity frame.
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
- * Validate and own a workflow snapshot before live construction.
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
- * Flatten a nested list of per-phase {@link TaskResult} lists into one positional list
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
- * The per-unit handle a runner handler receives — wraps the unit's identity,
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
- * Park until this unit's `signal` aborts — **promise-parked**, never a timer.
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 once the unit's `signal` aborts
357
+ * @returns A promise that resolves after the unit's `signal` aborts
207
358
  */
208
359
  wait(): Promise<void>;
209
360
  /**
210
- * Add a sibling unit to the run; returns its result promise.
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
- * Cancel this unit — fires its `signal` with the optional reason.
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
- * Create a {@link DatabaseWorkflowStore} over any {@link DriverInterface} — the durable,
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 import('./helpers.js').isWorkflowSnapshot}). The `driver` DEFAULTS to
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
- * Create a {@link DeferredInterface} — a promise whose settlement is driven
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 (AGENTS §21 minimal): a persisted run-state lives until an explicit `delete`. This is
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
- * Build an interrupted workflow back to life at its remaining retry budget.
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 `run` binding once before constructing tasks. Recovery
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
- * Build an equivalent live W-b entity tree from a {@link WorkflowSnapshot} — the
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 `run`
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
- * Create a thin generic orchestrator that drives declared units — and any they
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 (§13):** a
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 via an
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 it should NOT `await` a spawn inline (a
388
- * slot-holding handler awaiting its own spawn can deadlock); fan out and return instead.
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
- * Create the safe cross-environment cooperative-yield default — a
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 via a zero-delay macrotask (so pending I/O,
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
- * Build the live W-b entity tree from a {@link WorkflowDefinition} — the whole
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 AGENTS §8 nested-by-id bag). The W-b tree is 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').WorkflowFunctions} registry each live
477
- * task's `run` name resolves against ONCE at construction into its runtime
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
- * Compile the workflow definition contract — the JSON Schema, guard, parser, and
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
- * Create a {@link WorkflowManagerInterface} — the store-backed registry of
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`, via
532
- * {@link createWorkflow}) or hydrates (`open`'s registry-miss path, via
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
- * Create a workflow runner — a {@link WorkflowRunnerInterface} that EXECUTES a live W-b
560
- * workflow tree by COMPOSING the shipped substrate: phases sequential, tasks concurrent,
561
- * each task dispatched through its OWN resolved handler under the workflow's `bail` policy.
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 (via
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 `run` auto-completes; unresolved named work is rejected
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', run: 'compile' },
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
- * A {@link WorkflowStoreInterface} backed by one table of the `databases` layera
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 column back to
631
- * a {@link WorkflowSnapshot} ({@link import('../helpers.js').isWorkflowSnapshot} — the AGENTS §14
632
- * boundary narrow for an untrusted storage read), or `undefined` if none is stored. A present
633
- * snapshot whose own id differs from the requested key rejects with normalized `RESTORE` evidence.
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
- * §22 method bijection with {@link WorkflowStoreInterface}). Restore stays a caller concern: read a
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
- * Wrap a table as a workflow store.
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
- /** Resolve and key-check the snapshot for `id`, narrowing the opaque column to `WorkflowSnapshot`. */
846
+ /** Resolves and key-checks the snapshot for `id`, narrowing the opaque column to `WorkflowSnapshot`. */
665
847
  get(id: string): Promise<WorkflowSnapshot | undefined>;
666
- /** Insert or replace under the snapshot's OWN `id` (no separate id param) — the row is `{ id, snapshot }`. */
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
- /** Drop a snapshot by id; an absent id is a no-op (no throw). */
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
- /** The default {@link import('./types.js').WorkflowDefinition.bail} — graceful (continue on a leaf failure). */
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
- * The default per-phase task concurrency the {@link import('./factories.js').createWorkflowRunner}
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
- * A promise paired with its externally-callable `resolve`/`reject` the settle path
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 `run` /
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 now.
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
- * Derive the PENDING SUFFIX boundary of a positional list of {@link LifecycleStatus}es —
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 (AGENTS §12): a
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 simply the count of leading
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
- * Derive a phase's status from its tasks' statuses (tasks are concurrent, so this
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 PhaseStatus}
980
+ * @returns The derived phase {@link LifecycleStatus}
786
981
  */
787
- export declare function derivePhaseStatus(tasks: readonly TaskStatus[]): PhaseStatus;
982
+ export declare function derivePhaseStatus(tasks: readonly LifecycleStatus[]): LifecycleStatus;
788
983
 
789
984
  /**
790
- * Derive a workflow's status from its phases' {@link PhaseDerivation}s — each phase's status
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 now a per-phase override (AGENTS §4.4), so it is carried on each
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 WorkflowStatus}
1010
+ * @returns The derived workflow {@link LifecycleStatus}
816
1011
  */
817
- export declare function deriveWorkflowStatus(phases: readonly PhaseDerivation[]): WorkflowStatus;
1012
+ export declare function deriveWorkflowStatus(phases: readonly PhaseDerivation[]): LifecycleStatus;
818
1013
 
819
1014
  /**
820
- * Normalize an unknown thrown value to a non-empty persistence-safe message.
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
- * Box an error as a {@link Failure} — the graceful outcome half of a {@link Result}.
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
- * Find the first {@link TaskResult} in a positional list whose boxed outcome is a
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 §12 invariant throw (a derived `failed`
851
- * status guarantees a failing result exists) since throwing on `undefined` is
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
- * Test that every named task has a callable runtime handler before dispatch.
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 `run` binding at most once from `functions`. A live workflow
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
- * @returns Whether every named task resolves to a callable handler
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: WorkflowFunctions | undefined): boolean;
1075
+ export declare function hasWorkflowHandlers(workflow: WorkflowSnapshot, functions: WorkflowRegistry | undefined): boolean;
877
1076
 
878
1077
  /**
879
- * Insert one `[key, value]` entry at a positional index into a readonly entries array —
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
- * Shared by {@link import('./tasks/TaskManager.js').TaskManager} and
884
- * {@link import('./phases/PhaseManager.js').PhaseManager}: both convert their
885
- * insertion-ordered `Map` to `[...map.entries()]`, call this to splice the new entry
886
- * in at the target index, then rebuild the `Map` from the result (a stateful step that
887
- * stays a `#` private method — this helper does no `Map` construction). Does not
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
- /** Test the workflow lifecycle vocabulary. */
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
- * Validate a safe owned JSON graph as a coherent workflow snapshot.
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
- * Test whether an unknown value is valid persisted task activity.
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
- * Test whether an unknown value is a valid whole-frame activity report.
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
- /** Test a normalized persisted task failure. */
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
- /** Test a result's lineage against its containing snapshot nodes. */
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
- * Test whether a {@link LifecycleStatus} is TERMINAL — a node in this state will not
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 all three tiers (AGENTS §4.4 "one concept = one word"):
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. Terminal: `completed` /
941
- * `failed` / `skipped` / `stopped`; the only non-terminal states are `pending` and
942
- * `running`.
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 `true` when the status is terminal
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
- * Narrow an unknown caught value to a {@link WorkflowError}.
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 `true` when `value` is a {@link WorkflowError}
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
- /** Total hostile-boundary workflow snapshot guard. */
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
- * The shared lifecycle vocabulary every tier draws from — `pending` before it runs,
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 behind the three semantic tiers ({@link TaskStatus} /
976
- * {@link PhaseStatus} / {@link WorkflowStatus}), which alias it so each keeps its own
977
- * name + doc while the vocabulary lives in one place (AGENTS §4.4 "one concept = one
978
- * word"). It also types the single runtime terminal check
979
- * {@link import('./helpers.js').isTerminalStatus} every tier's value is a
980
- * `LifecycleStatus`, so the one predicate accepts them all. The three tiers are direct
981
- * aliases, not branded types, so TypeScript accepts any one of them wherever another is
982
- * expected. Each name documents which tier a value came from; it does not enforce it.
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
- /** Compare two optional description values. */
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
- * The largest delay representable by the host timer APIs without overflow or clamping.
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
- * The in-memory {@link WorkflowStoreInterface} — a process-lifetime `Map` of
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>` (AGENTS §21 — the snapshot is already pure,
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 §22 method
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
- * Reposition the entry keyed `key` to a new positional index in a readonly entries
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 (`TaskManager.move` / `PhaseManager.move`)
1048
- * already gates on the target's existence before calling this, so the no-op branch is
1049
- * defensive, never reached in practice. Does not mutate `entries`; returns a new array.
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
- * Park until `signal` aborts a promise-parked wait (AGENTS §21), never a timer or
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 once `signal` has aborted
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
- * The live DERIVED state machine (W-b) for one phase an observable (AGENTS §13) whose
1089
- * {@link PhaseStatus} is computed from its tasks (never set directly) and recomputed
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
- * - **Derived status.** `status` is `#override` when one is in force, else
1094
- * {@link derivePhaseStatus} over the live tasks' statuses. `#recompute` (passed to
1095
- * each child {@link Task}) re-derives on every child transition; a CHANGE emits the matching
1096
- * event AND escalates to the workflow (`#escalate`, the upward step of the cascade).
1097
- * - **Override (AGENTS §10).** `skip` / `stop` FORCE the phase's status (e.g. skipping a whole
1098
- * phase), overriding the derived value; the override is PERSISTED in the snapshot's own
1099
- * `override` field and restored DIRECTLY (no divergence guess), so a forced phase round-trips.
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
- /** Every {@link PhaseStatus} value, frozen — the lifecycle vocabulary of a phase. */
1172
- export declare const PHASE_STATUSES: readonly PhaseStatus[];
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
- * The ambient context of a phase — its own identity plus a back-reference to the
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
- * The serializable definition of one phase — its identity, its ordered tasks, and
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
- /** Max tasks in flight at once (a resource throttle); omitted ⇒ unbounded. */
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 (AGENTS §4.4). Omitted ⇒ the phase INHERITS the
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
- * Convert one {@link import('./types.js').PhaseDefinition} into an initial, all-`pending`
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
- * One phase's contribution to the workflow-status derivation — its {@link PhaseStatus} paired
1232
- * with the EFFECTIVE `bail` policy it ran under (`phase.bail ?? workflow.bail`, AGENTS §4.4).
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}: since `bail` is now a
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
- readonly status: PhaseStatus;
1691
+ /** Holds the phase's derived lifecycle status. */
1692
+ readonly status: LifecycleStatus;
1244
1693
  readonly bail: boolean;
1245
1694
  }
1246
1695
 
1247
1696
  /**
1248
- * The push observation surface (AGENTS §13) of the phase entity (W-b) — analogous
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` (AGENTS §7) — never on a
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 (AGENTS §13). A `type` alias (AGENTS §4.5)
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
- /** The phase began — its `id`. */
1712
+ /** Signals that the phase began — its `id`. */
1265
1713
  readonly start: readonly [id: string];
1266
- /** Every task in the phase settled successfully. */
1714
+ /** Signals that every task in the phase settled successfully. */
1267
1715
  readonly complete: readonly [];
1268
- /** A task failed under `bail` — the failing task's result. */
1716
+ /** Signals that a task failed under `bail` — the failing task's result. */
1269
1717
  readonly fail: readonly [result: TaskResult];
1270
- /** The phase's runtime gate closed. */
1718
+ /** Signals that the phase's runtime gate closed. */
1271
1719
  readonly pause: readonly [];
1272
- /** The phase's runtime gate opened. */
1720
+ /** Signals that the phase's runtime gate opened. */
1273
1721
  readonly resume: readonly [];
1274
- /** The phase was intentionally skipped. */
1722
+ /** Signals that the phase was intentionally skipped. */
1275
1723
  readonly skip: readonly [];
1276
- /** The phase was permanently stopped. */
1724
+ /** Signals that the phase was permanently stopped. */
1277
1725
  readonly stop: readonly [];
1278
- /** A task was inserted — the inserted task + its final index. */
1726
+ /** Signals that a task was inserted — the inserted task + its final index. */
1279
1727
  readonly add: readonly [task: TaskInterface, index: number];
1280
- /** A task was removed — the removed task. */
1728
+ /** Signals that a task was removed — the removed task. */
1281
1729
  readonly remove: readonly [task: TaskInterface];
1282
- /** A task was repositioned — the moved task + its new index. */
1730
+ /** Signals that a task was repositioned — the moved task + its new index. */
1283
1731
  readonly move: readonly [task: TaskInterface, index: number];
1284
- /** A task was patched — the patched task. */
1732
+ /** Signals that a task was patched — the patched task. */
1285
1733
  readonly update: readonly [task: TaskInterface];
1286
1734
  };
1287
1735
 
1288
- /** Initial {@link PhaseEventMap} listeners the reserved `on` option (AGENTS §8). */
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
- * The live derived state machine (W-b) for one {@link PhaseDefinition} — an
1296
- * observable (AGENTS §13) phase whose {@link PhaseStatus} is DERIVED from its tasks
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 via
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} (AGENTS §9 — an
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` (AGENTS §10) FORCE the phase's status, overriding the
1309
- * derived value (e.g. skipping a whole phase); the override survives a snapshot.
1310
- * - **Observable (AGENTS §13).** The owned {@link emitter} ({@link PhaseEventMap}) fires
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 (AGENTS §10).** `pause` / `resume` / `wait` mirror
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
- readonly description?: string;
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
- readonly status: PhaseStatus;
1329
- /** The RESOLVED effective failure policy this phase runs under (`phase.bail ?? workflow.bail`); mirrors {@link WorkflowInterface.bail}. */
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
- /** Max tasks in flight at once (a resource throttle); mirrors {@link PhaseSnapshot.concurrency}. `undefined` ⇒ unbounded. */
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
- * Whether the phase is currently paused (AGENTS §10 — resumable); RUNTIME-ONLY — never a
1335
- * {@link PhaseStatus}, never persisted in a {@link PhaseSnapshot} (a paused phase's
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
- /** Look up one live task by its `id`. */
1787
+ /** Looks up one live task by its `id`. */
1341
1788
  task(id: string): TaskInterface | undefined;
1342
- /** The settled tasks' results, in positional order — the phase tier of the result tree. */
1789
+ /** Lists the settled tasks' results, in positional order — the phase tier of the result tree. */
1343
1790
  results(): readonly TaskResult[];
1344
1791
  /**
1345
- * FORCE this phase to `skipped` (AGENTS §10), overriding the derived value; idempotent.
1792
+ * Forces this phase to `skipped`, overriding the derived value; idempotent.
1346
1793
  *
1347
1794
  * @remarks
1348
- * A NO-OP once `status` is already terminal — a settled phase cannot be re-forced. Always
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
- * FORCE this phase to `stopped` (AGENTS §10), overriding the derived value; idempotent.
1801
+ * Forces this phase to `stopped`, overriding the derived value; idempotent.
1355
1802
  *
1356
1803
  * @remarks
1357
- * A NO-OP once `status` is already terminal (a settled phase cannot be re-forced). Always
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
- * Suspend the phase (AGENTS §10 — resumable); idempotent.
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 (AGENTS §10)
1367
- * never a {@link PhaseStatus}, never persisted in a {@link PhaseSnapshot}. A driving
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
- * Continue a paused phase (AGENTS §10); idempotent — a no-op unless {@link paused}.
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
- * Park until this phase is not paused — **promise-parked**, never a timer or busy-loop
1392
- * (AGENTS §21; mirrors {@link WorkflowInterface.wait}).
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 once the phase is no longer paused
1846
+ * @returns A promise that resolves after the phase is no longer paused
1400
1847
  */
1401
1848
  wait(): Promise<void>;
1402
1849
  /**
1403
- * MINT a live {@link TaskInterface} from `definition` and insert it into this phase
1404
- * (AGENTS §7 the entity structural API) — gated BEFORE delegating to {@link tasks}'
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 `run` /
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` (AGENTS §12 — no
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 guarantees this phase cannot reach a terminal status while the accepted task is
1424
- * still `pending` (its status feeds `status` via {@link import('./helpers.js').derivePhaseStatus}).
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 guarantees the task
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
- * Remove the `pending` task `id` from this phase.
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
- * Reposition the `pending` task `id` to `index` within this phase.
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
- * Apply a validated {@link TaskUpdate} patch to the `pending` task `id` in this phase.
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
- * Apply a validated declarative patch to SELF (`name` / `description` /
1923
+ * Applies a validated declarative patch to SELF (`name` / `description` /
1477
1924
  * `concurrency` / `bail`).
1478
1925
  *
1479
1926
  * @remarks
1480
- * Defense-in-depth (AGENTS §12): the owning {@link WorkflowInterface.update} gates
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
- * The lean child manager (AGENTS §9) of a {@link import('../Workflow.js').Workflow}'s
1497
- * live phases — an insertion-ordered registry keyed by phase `id`, the phase analogue
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
- * - **Positional store.** Phases live in an insertion-ordered `Map` keyed by `id`;
1502
- * `append` adds one at the end, `phase(id)` looks one up, `phases()` lists them in
1503
- * positional order, `count` is the size. A snapshot RESTORE re-`append`s in the
1504
- * snapshot's order, reproducing it exactly.
1505
- * - **Gated mutation API (AGENTS §12).** `add` / `remove` / `move` / `update` are the
1506
- * graceful `Result` counterparts to `append`, gating ONLY on the target's OWN
1507
- * existence/status/id/bounds a duplicate id, an absent/non-`pending` target, an
1508
- * out-of-bounds `index`, or a patch that fails {@link phaseUpdateShape} validation
1509
- * all fail gracefully with a `MUTATION` {@link WorkflowError} instead of throwing.
1510
- * - **No batch matrix.** A workflow's phases are a fixed positional set, so AGENTS §9.2
1511
- * is deliberately omitted.
1512
- * - **Event-free.** A purely structural container — the live {@link PhaseInterface}s own
1513
- * their own emitters.
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
- * The lean child manager (AGENTS §9) of a {@link WorkflowInterface}'s live phases —
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` (AGENTS §12) are the GATED mutation
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
- * Add `phase` at the end (the build-time wiring path).
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, AGENTS §12) instead of
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
- * Insert `phase` at `index` (default the end) — the GATED mutation counterpart to
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
- * Remove the `pending` phase `id`.
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
- * Reposition the `pending` phase `id` to `index`.
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
- * Apply a validated {@link PhaseUpdate} patch to the `pending` phase `id`.
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
- * The runtime options for a {@link PhaseInterface} — the construction bag the live
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` (AGENTS §8) wires initial {@link PhaseEventMap} listeners.
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?: PhaseHooks;
1613
- /** The emitter's listener-error handler (AGENTS §13) — a listener throw routes here, not to a domain event. */
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
- /** Per-task {@link TaskOptions}, keyed by the task's `id`. */
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
- * The shape of a {@link import('./types.js').PhaseDefinition} — identity, its ordered
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
- run: OptionalShape<StringShape>;
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
- * A JSON-serializable snapshot of one phase's state — its identity, status, its forced
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` (AGENTS §10) — PRESENT only
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
- readonly status: PhaseStatus;
1657
- /** The forced status of a whole-phase `skip` / `stop`; present only when an override is in force. */
1658
- readonly override?: PhaseStatus;
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
- * The EFFECTIVE failure policy this phase ran under (`phase.bail ?? workflow.bail`, AGENTS §4.4)
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
- * Max tasks in flight at once (a resource throttle), persisted so a restore reinstates the
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
- * The lifecycle status of a phase — the same vocabulary as {@link TaskStatus},
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 via {@link import('./shapers.js').phaseUpdateShape}.
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
- * The shape of a {@link import('./types.js').PhaseUpdate} — a partial edit to a
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, AGENTS §12).
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
- * Convert interrupted running work into a recoverable pending suffix or an
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
- * Resolve a task's runtime silence window against its workflow default.
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
- * A thin generic orchestrator that drives declared units — and any they `spawn` —
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 via a count gate.** `#launch` increments
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 just the declared units.
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` (§10) ride the backing Queue.** `pause` / `resume`
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) once every unit
2284
+ * completion and settles normally. `execute` RESOLVES (never rejects) after every unit
1785
2285
  * has settled, with whatever results actually completed.
1786
- * - **Observable (§13).** The owned {@link emitter} ({@link RunnerEventMap}) carries the run
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
- * Inject one more unit into an IN-FLIGHT `execute` run — a LIVE counterpart to a
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 — AGENTS §12) unless the
1808
- * runner is currently mid-`execute` and not yet stopped — covering "never started",
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 via `#launch` — the outstanding-
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) once accepted.
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
- * Suspend dispatch (AGENTS §10 — resumable): delegates to the backing queue's own
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 once the runner is `stopped` — a stopped runner has no dispatch left to
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
- * Continue a paused runner (AGENTS §10); delegates to the backing queue's `resume`.
2342
+ * Continues a paused runner; delegates to the backing queue's `resume`.
1843
2343
  *
1844
2344
  * @remarks
1845
- * A no-op once the runner is `stopped` (nothing left to resume) and a no-op when the
1846
- * runner is not currently `paused`, so calling it repeatedly or on a never-paused
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
- * Permanently end the runner (AGENTS §10) — a GRACEFUL stop, distinct from `abort`.
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
- * The per-entry reliability OVERRIDES for one unit — its extra attempts on failure and its
1866
- * per-attempt deadline, resolved from the unit's input via {@link RunnerOptions.entries}.
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
- * The push observation surface of a {@link RunnerInterface} (AGENTS §13) — the run
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 (AGENTS §13): every event is emitted directly and a
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 via `runner.emitter.on(...)`.
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`, §4.5 — `EventMap` is a
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
- /** A unit's handler began running — the unit's id (declared or spawned). */
2406
+ /** Signals that a unit's handler began running — the unit's id (declared or spawned). */
1907
2407
  readonly unit: readonly [id: string];
1908
- /** A sub-unit was spawned — its id + the spawning parent's id (when known). */
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
- /** A unit completed successfully — its id (after its outcome was recorded). */
2410
+ /** Signals that a unit completed successfully — its id (after its outcome was recorded). */
1911
2411
  readonly settle: readonly [id: string];
1912
- /** A unit failed — its id + the error (always `unknown`). */
2412
+ /** Signals that a unit failed — its id + the error (always `unknown`). */
1913
2413
  readonly fail: readonly [id: string, error: unknown];
1914
- /** The batch settled — the run's ordered results (the same array `execute` resolves). */
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
- /** The run was aborted (fail-fast, a user `abort`, or `destroy`) — the cancel reason. */
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
- * A thin generic orchestrator that drives declared units — plus any they `spawn` —
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} (AGENTS §13) carrying its run lifecycle moments
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 via
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
- /** Whether the runner is currently paused (AGENTS §10 — resumable, no new dispatch); rides the backing queue's own `paused`. */
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
- * Run all `inputs` — and anything they `spawn` — to completion; resolve their
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
- * Inject one more unit into an IN-FLIGHT `execute` run — a LIVE counterpart to a
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 — AGENTS §12) when the
1977
- * runner is not currently mid-`execute`, or the run has already fully drained — the
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 once the unit
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
- * Cancel every in-flight + pending unit (and the backing queue), making a running
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
- * Suspend dispatch (AGENTS §10 — resumable): the backing queue holds the NEXT dispatch
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
- * Continue a paused runner (AGENTS §10); idempotent.
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
- * Permanently end the runner (AGENTS §10) — a GRACEFUL stop: no further unit is
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) once every unit has
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
- * Tear the runner down, awaiting backing-queue cleanup before destroying the emitter last.
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
- * Options for `createRunner`.
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 (§8): initial listeners for the runner's
2058
- * {@link RunnerEventMap}, wired at construction (e.g. `{ finish: (r) => log(r) }`).
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
- /** The emitter's listener-error handler (AGENTS §13) — a listener throw routes here, not to a domain event. */
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
- /** Per-entry `retries` / `timeout` overrides, resolved from each input; falls back to the runner-level defaults. */
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
- * One unit the {@link RunnerInterface} is tracking: the queue payload it was enqueued
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 §5
2079
- * centralizes every file-local type — declared or spawned, every unit flows through the
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
- * Schedule one cancellable host operation behind an owned settlement signal.
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
- * The safe cross-environment cooperative-yield default — a {@link SchedulerInterface}
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 scheduleHost} links an owned settlement composite to the caller before arming
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
- * Yield control back to the host so other tasks (I/O, timers, rendering) can
2158
- * run, then resume — a macrotask turn via `setTimeout(0)` (NOT a microtask,
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
- * Resume after at least `ms` milliseconds; abort rejects with `signal.reason`.
2677
+ * Resumes after at least `ms` milliseconds; abort rejects with `signal.reason`.
2164
2678
  *
2165
2679
  * @remarks
2166
- * `ms` should be a non-negative finite number. The primitive stays minimal and
2167
- * does no validation: it passes `ms` straight to the host `setTimeout`, which
2168
- * clamps a negative value or `NaN` to ~0 — so an out-of-domain `ms` resolves on
2169
- * the next host turn rather than throwing.
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
- * A cooperative host-yield primitive: a loop decides WHAT to do; the scheduler
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
- * Yield control back to the host so other tasks (I/O, timers, rendering) can
2183
- * run, then resume.
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
- /** Resume after at least `ms` milliseconds. */
2700
+ /** Resumes after at least `ms` milliseconds. */
2187
2701
  delay(ms: number, options?: SchedulerOptions): Promise<void>;
2188
2702
  }
2189
2703
 
2190
- /** Options for a single cooperative yield/delay. */
2704
+ /** Declares the options for a single cooperative yield/delay. */
2191
2705
  export declare interface SchedulerOptions {
2192
2706
  /**
2193
- * A relative urgency hint. Honoured by environment backends; the
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
- /** A signal whose abort rejects a pending yield/delay with its `reason`. */
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
- * Relative urgency hint for cooperative scheduling. Honoured by environment
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
- * Box a value as a {@link Success} — the graceful outcome half of a {@link Result}.
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
- * The live leaf state machine (W-b) for one task an observable (AGENTS §13), guarded
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<TaskStatus, readonly TaskStatus[]>>;
2748
+ export declare const TASK_TRANSITIONS: Readonly<Record<LifecycleStatus, readonly LifecycleStatus[]>>;
2327
2749
 
2328
2750
  /**
2329
- * The bounded, JSON-serializable activity most recently accepted from a task reporter.
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
- * One complete replacement of a running task's observable activity.
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
- * One constraint claimed active when a running task's complete frame was accepted.
2777
+ * Represents one identified thing a running task claims active, with the moment the claim began.
2356
2778
  *
2357
2779
  * @remarks
2358
- * Constraints describe active limits or requirements without embedding provider policy in
2359
- * core. `id` is unique within one complete report and `started` is finite and non-negative.
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 TaskConstraint {
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
- * The ambient context of a task its own identity plus a back-reference to the
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
- * The attempt-scoped handle a {@link import('./types.js').WorkflowFunction} receives.
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 NEW, lean handle (NOT the runner `Controller` — it carries no `spawn`; a workflow task
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
- /** The task's open `metadata` bag (its {@link TaskInput} payload); `{}` when none. */
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
- /** The one-based persisted launch represented by this handle. */
2842
+ /** Reports the one-based persisted launch represented by this handle. */
2445
2843
  readonly attempt: number;
2446
- /** Whether the workflow, phase, or task cooperative gate is currently paused. */
2844
+ /** Reports whether the workflow, phase, or task cooperative gate is paused. */
2447
2845
  readonly paused: boolean;
2448
2846
  /**
2449
- * Replace this running task's complete observable activity.
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
- * Confirm liveness without replacing current activity.
2854
+ * Confirms liveness without replacing current activity.
2457
2855
  *
2458
- * @returns `true` when committed, or `false` after ownership is lost or this attempt aborts
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
- * Cooperatively park while any workflow, phase, or task gate is paused, or until cancelled.
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
- /** Every settled task's result across already-finished phases — the result tree, read-only. */
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
- * The serializable definition of one task — its identity plus an optional reference to
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. `run` is a
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 WorkflowFunctions} registry into a runtime {@link TaskInterface.handler}
2481
- * carried on the live task. An omitted `run` is the deliberate no-op form and completes
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 run?: string;
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
- * Convert one {@link import('./types.js').TaskDefinition} into an initial, `pending`
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
- * `run` / `retries` / `timeout` carry over verbatim (persisted declarative config, like a
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 once paired with a {@link import('./types.js').WorkflowOptions.functions}
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
- * The push observation surface (AGENTS §13) of the task entity (W-b) — the
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 (AGENTS §13). A `type` alias (AGENTS §4.5) so it satisfies
2936
+ * not the domain surface. A `type` alias so it satisfies
2535
2937
  * `EventMap`.
2536
2938
  */
2537
2939
  export declare type TaskEventMap = {
2538
- /** The task began — its `id`. */
2940
+ /** Signals that the task began — its `id`. */
2539
2941
  readonly start: readonly [id: string];
2540
- /** The task finished successfully — its result. */
2942
+ /** Signals that the task finished successfully — its result. */
2541
2943
  readonly complete: readonly [result: TaskResult];
2542
- /** The task failed — its result. */
2944
+ /** Signals that the task failed — its result. */
2543
2945
  readonly fail: readonly [result: TaskResult];
2544
- /** The task's runtime gate closed. */
2946
+ /** Signals that the task's runtime gate closed. */
2545
2947
  readonly pause: readonly [];
2546
- /** The task's runtime gate opened. */
2948
+ /** Signals that the task's runtime gate opened. */
2547
2949
  readonly resume: readonly [];
2548
- /** The task was intentionally skipped. */
2950
+ /** Signals that the task was intentionally skipped. */
2549
2951
  readonly skip: readonly [];
2550
- /** The task was permanently stopped. */
2952
+ /** Signals that the task was permanently stopped. */
2551
2953
  readonly stop: readonly [];
2552
- /** A complete activity replacement was committed. */
2954
+ /** Signals that a complete activity replacement was committed. */
2553
2955
  readonly report: readonly [activity: TaskActivity];
2554
- /** The task confirmed liveness without replacing its current activity. */
2956
+ /** Signals that the task confirmed liveness without replacing its current activity. */
2555
2957
  readonly pulse: readonly [activity: TaskActivity];
2556
- /** No report or pulse was accepted during the effective silence window. */
2958
+ /** Signals that no report or pulse was accepted during the effective silence window. */
2557
2959
  readonly silence: readonly [];
2558
2960
  };
2559
2961
 
2560
- /** A normalized JSON-safe task failure persisted without a stack or cause. */
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
- * The structured outcome of a task executionits full lineage, its terminal
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
- * Carries the complete lineage (`task` / `phase` / `workflow` contexts) so a result
2572
- * is self-describing wherever it travels. `status` is the terminal state this
2573
- * result records. `result` BOXES the produced outcome in a {@link Result}: it is
2574
- * PRESENT exactly when `status` is `completed` (a {@link import('@orkestrel/contract').Success})
2575
- * or `failed` (a {@link import('@orkestrel/contract').Failure}), and ABSENT when `status` is
2576
- * `skipped` or `stopped` (terminal, but produced no outcome) — a pending/running
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
- * The minimal data to create a task context — a partial {@link TaskContext} plus
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
- /** An open consumer bag — stored and snapshotted, never interpreted by the workflow. */
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
- * The live leaf state machine (W-b) for one {@link TaskDefinition} — an observable
2603
- * (AGENTS §13), guarded synchronous task whose explicit {@link TaskStatus} advances
2604
- * through the AGENTS §10 transitions.
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 (AGENTS §10).** `status` is the explicit current state. `start`
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` (AGENTS §10 — intentionally not run),
2615
- * and `stop` (AGENTS §10 — ended early). Each is GUARDED: an illegal transition (e.g.
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} once the task settled with an
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 (AGENTS §13).** The owned {@link emitter} ({@link TaskEventMap}) fires
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
- readonly description?: string;
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
- readonly status: TaskStatus;
2636
- /** Total launches already consumed; zero while fresh and one-based after launch. */
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
- /** The recorded outcome once the task settled with one (`completed` / `failed`), else `undefined`. */
3034
+ /** Holds the recorded outcome after the task settled with one (`completed` / `failed`), else `undefined`. */
2639
3035
  readonly result: TaskResult | undefined;
2640
3036
  /**
2641
- * The behavior reference — a plain registry key name, PERSISTED (mirrors
2642
- * {@link TaskDefinition.run} / {@link TaskSnapshot.run}), like {@link PhaseInterface.bail}.
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 run: string | undefined;
3041
+ readonly behavior: string | undefined;
2646
3042
  /**
2647
- * The RESOLVED runtime handler — RUNTIME-ONLY, NEVER persisted in a {@link TaskSnapshot}.
2648
- * Resolved ONCE at construction (build, restore, or a live mint) by looking `run` up in the
2649
- * workflow-level {@link WorkflowOptions.functions} registry: `functions?.[run]` when `run`
2650
- * is defined, else `undefined`. An omitted `run` is the deliberate no-op form. A present,
2651
- * unresolved `run` remains visible on exact restore, but the runner rejects it before
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
- * Extra attempts after the first on failure — PERSISTED (mirrors {@link TaskDefinition.retries}
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
- * The workflow-owned per-attempt deadline in milliseconds (`0..MAX_TIMER_MS`) — PERSISTED
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
- /** The last accepted reporter claim, absent while pending. */
3062
+ /** Holds the last accepted reporter claim, absent while pending. */
2667
3063
  readonly activity: TaskActivity | undefined;
2668
- /** The effective host-safe silence window (`1..MAX_TIMER_MS`), or `undefined` when disabled. */
3064
+ /** Holds the effective host-safe silence window (`1..MAX_TIMER_MS`), or `undefined` when disabled. */
2669
3065
  readonly silence: number | undefined;
2670
- /** Whether no report or pulse was accepted during the current silence window. */
3066
+ /** Reports whether no report or pulse was accepted during the current silence window. */
2671
3067
  readonly silent: boolean;
2672
- /** Whether this task's cooperative execution gate is paused. */
3068
+ /** Reports whether this task's cooperative execution gate is paused. */
2673
3069
  readonly paused: boolean;
2674
- /** This task's own cancellation signal; running/pending {@link stop} or {@link skip} fires it. */
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
- * Replace the complete observable activity of this running task.
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
- * Confirm liveness without replacing the current operations, progress, or constraints.
3085
+ * Confirms liveness without replacing the current operations, progress, or constraints.
2690
3086
  *
2691
- * @returns `true` when committed, or `false` when the task is not running
3087
+ * @returns True if the pulse was committed while the task is running; false otherwise
2692
3088
  */
2693
3089
  pulse(): boolean;
2694
- /** Suspend this task's cooperative gate while pending or running; idempotent. */
3090
+ /** Suspends this task's cooperative gate while pending or running; idempotent. */
2695
3091
  pause(): void;
2696
- /** Continue this task's cooperative gate; idempotent. */
3092
+ /** Continues this task's cooperative gate; idempotent. */
2697
3093
  resume(): void;
2698
3094
  /**
2699
- * Park until this task is not paused.
3095
+ * Parks until this task is not paused.
2700
3096
  *
2701
- * @returns A promise that resolves once the task gate is released
3097
+ * @returns A promise that resolves after the task gate is released
2702
3098
  */
2703
3099
  wait(): Promise<void>;
2704
3100
  /**
2705
- * Apply a validated declarative patch to SELF (`name` / `description`).
3101
+ * Applies a validated declarative patch to SELF (`name` / `description`).
2706
3102
  *
2707
3103
  * @remarks
2708
- * Defense-in-depth (AGENTS §12): the owning {@link TaskManagerInterface.update} gates
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
- * The lean child manager (AGENTS §9) of a {@link import('../phases/Phase.js').Phase}'s live
2725
- * tasks — an insertion-ordered registry keyed by task `id`, so positional order is
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
- * - **Positional store.** Tasks live in an insertion-ordered `Map` keyed by `id`;
2730
- * `append` adds one at the end (the build-time wiring path), `task(id)` looks one up,
2731
- * `tasks()` lists them in positional order, `count` is the size. A `skip` is a STATUS
2732
- * change on a stored task (never a removal), so order survives it; a snapshot RESTORE
2733
- * re-`append`s in the snapshot's order, reproducing it exactly.
2734
- * - **Gated mutation API (AGENTS §12).** `add` / `remove` / `move` / `update` are the
2735
- * graceful `Result` counterparts to `append`, gating ONLY on the target's OWN
2736
- * existence/status/id/bounds a duplicate id, an absent/non-`pending` target, an
2737
- * out-of-bounds `index`, or a patch that fails {@link taskUpdateShape} validation all
2738
- * fail gracefully with a `MUTATION` {@link WorkflowError} instead of throwing.
2739
- * - **No batch matrix.** A phase's tasks are a fixed positional set, so AGENTS §9.2 (the
2740
- * bulk verb overloads) is deliberately omitted there is no `remove` family here.
2741
- * - **Event-free.** A purely structural container the live {@link TaskInterface}s own
2742
- * their own emitters; the manager observes nothing.
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
- * The lean child manager (AGENTS §9) of a {@link PhaseInterface}'s live tasks —
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 (AGENTS §9.2 is deliberately omitted — a phase's tasks are a
2773
- * fixed positional set, not a bulk-mutated collection). `add` / `remove` / `move` /
2774
- * `update` (AGENTS §12) are the GATED mutation counterparts a
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
- * Add `task` at the end (the build-time wiring path).
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, AGENTS §12) instead of
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
- * Insert `task` at `index` (default the end) — the GATED mutation counterpart to
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
- * Remove the `pending` task `id`.
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
- * Reposition the `pending` task `id` to `index`.
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
- * Apply a validated {@link TaskUpdate} patch to the `pending` task `id`.
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
- * One operation claimed active when a running task's complete frame was accepted.
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 human-readable label,
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
- * The runtime options for a {@link TaskInterface} — the construction bag the live
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` (AGENTS §8) wires initial {@link TaskEventMap} listeners; a
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?: TaskHooks;
2859
- /** The emitter's listener-error handler (AGENTS §13) — a listener throw routes here, not to a domain event. */
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
- /** An open consumer bag — stored and snapshotted, never interpreted by the workflow. */
3259
+ /** Holds an open consumer bag — stored and snapshotted, never interpreted by the workflow. */
2862
3260
  readonly metadata?: JSONRecord;
2863
- /** Runtime-only silence window; non-positive, non-finite, or over-`MAX_TIMER_MS` disables inheritance. */
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
- * The aggregate progress most recently reported by a running task.
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
- readonly status: TaskStatus;
2886
- /** The boxed outcome — present for `completed` (Success) / `failed` (Failure), absent otherwise. */
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
- * The shape of a {@link import('./types.js').TaskDefinition} — identity plus an optional
2893
- * `run` behavior reference (a plain registry-key string, min length 1). `description` is
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
- run: OptionalShape<StringShape>;
3315
+ behavior: OptionalShape<StringShape>;
2901
3316
  retries: OptionalShape<NumberShape>;
2902
3317
  timeout: OptionalShape<NumberShape>;
2903
3318
  }, false>;
2904
3319
 
2905
3320
  /**
2906
- * A JSON-serializable snapshot of one task's state — the leaf of the snapshot tree
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
- * `run` / `retries` / `timeout` are the DECLARATIVE config the task carries — persisted
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 (`run` re-resolves against the
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
- readonly status: TaskStatus;
3339
+ /** Holds the task's persisted lifecycle status. */
3340
+ readonly status: LifecycleStatus;
2925
3341
  readonly result?: TaskResult;
2926
3342
  readonly metadata: JSONRecord;
2927
- /** Total launches already consumed; zero while fresh and never reset by recovery. */
3343
+ /** Counts total launches already consumed; zero while fresh and never reset by recovery. */
2928
3344
  readonly attempts: number;
2929
- /** The behavior reference — a registry key resolved against {@link WorkflowFunctions} on restore/build. */
2930
- readonly run?: string;
2931
- /** Extra attempts after the first on failure (a non-negative integer); overrides the phase Runner default. */
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
- /** Workflow-owned per-attempt deadline (`0..MAX_TIMER_MS`); zero or omission means disabled. */
3349
+ /** Records the workflow-owned per-attempt deadline (`0..MAX_TIMER_MS`); zero or omission means disabled. */
2934
3350
  readonly timeout?: number;
2935
- /** Pending omits activity; running/completed/failed require it; skipped/stopped may retain it. */
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
- * The lifecycle status of a task`pending` before it runs, `running` while in
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 via {@link import('./shapers.js').taskUpdateShape}.
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 `run` / `retries` / `timeout` (a form/reliability change is a structural
2963
- * replace, not a patch) and never `id` (identity is immutable once created). Every
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
- * The shape of a {@link import('./types.js').TaskUpdate} — a partial edit to a
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` / `run` / `retries` / `timeout` (those
2983
- * are not patchable fields, AGENTS §12).
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
- * The {@link TaskStatus} values that are TERMINAL — a task in one of these will
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 TERMINAL_TASK_STATUSES: readonly TaskStatus[];
3398
+ export declare const TERMINAL_STATUSES: readonly LifecycleStatus[];
2999
3399
 
3000
3400
  /**
3001
- * One unit's settled outcome a discriminated union so a value of `undefined` is still
3002
- * a success (`{ ok: true, value: undefined }`), never mistaken for a failure or an
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 (AGENTS §10).** `skip` / `stop` FORCE the status; an executed task-free pending tree
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 (AGENTS §13).** The owned {@link emitter} ({@link WorkflowEventMap}) fires
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 (AGENTS §7).** `add` / `remove` / `move` / `update` gate BEFORE
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 (AGENTS §10).** `pause` / `resume` / `wait` gate execution at the runner's
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(): WorkflowStatus;
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
- /** Every {@link WorkflowStatus} value, frozen — the lifecycle vocabulary of a workflow. */
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
- * The ambient context of a workflow — the identity every level inherits.
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
- * The serializable definition of a whole workflow — its identity, its ordered
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, AGENTS §4.4): `false` (the default) is GRACEFUL —
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
- /** Failure policy: `false` (default) continues gracefully, `true` halts on the first failure. */
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
- * An error raised by the workflow runtime.
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`), or a host
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
- * The machine-readable code of a {@link import('./errors.js').WorkflowError} — the
3155
- * fault the live W-b state machine raises (AGENTS §12).
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 (e.g. `start`ing a task that is
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 (AGENTS §12) returns it as a graceful `Result` `failure` —
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, AGENTS §12). The error `context` names
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
- * The push observation surface (AGENTS §13) of the workflow entity (W-b) — the
3185
- * lifecycle moments a fire-and-forget observer subscribes to via
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` (AGENTS §7) — never on a refused/gated one. A throwing listener never
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, AGENTS §13). Declared as a `type` alias (not
3199
- * `interface extends EventMap`, AGENTS §4.5) so the type-literal satisfies `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
- /** The workflow began — its `id`. */
3601
+ /** Signals that the workflow began — its `id`. */
3204
3602
  readonly start: readonly [id: string];
3205
- /** Every phase settled successfully. */
3603
+ /** Signals that every phase settled successfully. */
3206
3604
  readonly complete: readonly [];
3207
- /** A phase failed under `bail` — the failing task's result. */
3605
+ /** Signals that a phase failed under `bail` — the failing task's result. */
3208
3606
  readonly fail: readonly [result: TaskResult];
3209
- /** The workflow's runtime gate closed. */
3607
+ /** Signals that the workflow's runtime gate closed. */
3210
3608
  readonly pause: readonly [];
3211
- /** The workflow's runtime gate opened. */
3609
+ /** Signals that the workflow's runtime gate opened. */
3212
3610
  readonly resume: readonly [];
3213
- /** The workflow was intentionally skipped. */
3611
+ /** Signals that the workflow was intentionally skipped. */
3214
3612
  readonly skip: readonly [];
3215
- /** The workflow was permanently stopped. */
3613
+ /** Signals that the workflow was permanently stopped. */
3216
3614
  readonly stop: readonly [];
3217
- /** A phase was inserted — the inserted phase + its final index. */
3615
+ /** Signals that a phase was inserted — the inserted phase + its final index. */
3218
3616
  readonly add: readonly [phase: PhaseInterface, index: number];
3219
- /** A phase was removed — the removed phase. */
3617
+ /** Signals that a phase was removed — the removed phase. */
3220
3618
  readonly remove: readonly [phase: PhaseInterface];
3221
- /** A phase was repositioned — the moved phase + its new index. */
3619
+ /** Signals that a phase was repositioned — the moved phase + its new index. */
3222
3620
  readonly move: readonly [phase: PhaseInterface, index: number];
3223
- /** A phase was patched — the patched phase. */
3621
+ /** Signals that a phase was patched — the patched phase. */
3224
3622
  readonly update: readonly [phase: PhaseInterface];
3225
3623
  };
3226
3624
 
3227
- /** A normalized persistence failure surfaced as workflow result data. */
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
- * A registered workflow function — the behavior a `function`-form
3238
- * {@link TaskDefinition} runs, resolved BY NAME through the {@link WorkflowFunctions}
3239
- * registry (AGENTS §4.5 — a `Handler` function type the framework invokes).
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
- * should honour `controller.signal` (a workflow-level abort / timeout / budget, or — under
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
- * The live derived state machine (W-b) for a whole {@link WorkflowDefinition} — the
3273
- * observable (AGENTS §13) root whose {@link WorkflowStatus} is DERIVED from its phases
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 via
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} (AGENTS §9);
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` (AGENTS §10) FORCE the workflow's status; `complete`
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 (AGENTS §13).** The owned {@link emitter} ({@link WorkflowEventMap}) fires
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
- readonly description?: string;
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
- readonly status: WorkflowStatus;
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
- * Whether the workflow is currently paused (AGENTS §10 — resumable); RUNTIME-ONLY —
3306
- * never a {@link WorkflowStatus}, never persisted in a {@link WorkflowSnapshot} (a
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
- /** Whether {@link destroy} has torn this workflow down; RUNTIME-ONLY, never persisted. */
3693
+ /** Reports whether {@link destroy} has torn this workflow down; RUNTIME-ONLY, never persisted. */
3311
3694
  readonly destroyed: boolean;
3312
3695
  /**
3313
- * This workflow's own cancellation signal — fires on {@link destroy}. RUNTIME-ONLY
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
- /** Look up one live phase by its `id`. */
3700
+ /** Looks up one live phase by its `id`. */
3318
3701
  phase(id: string): PhaseInterface | undefined;
3319
- /** Every settled task's result across all phases, in positional order — the workflow tier of the result tree. */
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
- * FORCE this workflow to `skipped` (AGENTS §10), overriding the derived value; idempotent.
3705
+ * Forces this workflow to `skipped`, overriding the derived value; idempotent.
3323
3706
  *
3324
3707
  * @remarks
3325
- * A NO-OP once `status` is already terminal — a settled workflow cannot be re-forced.
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
- * FORCE this workflow to `stopped` (AGENTS §10), overriding the derived value; idempotent.
3714
+ * Forces this workflow to `stopped`, overriding the derived value; idempotent.
3332
3715
  *
3333
3716
  * @remarks
3334
- * A NO-OP once `status` is already terminal — a settled workflow cannot be re-forced. Always
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
- * FORCE this workflow to `completed` (AGENTS §10), overriding the derived value.
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
- * Suspend the workflow (AGENTS §10 — resumable); idempotent.
3732
+ * Suspends the workflow (resumable); idempotent.
3350
3733
  *
3351
3734
  * @remarks
3352
- * A no-op when already `paused`, when `status` is terminal, or once {@link destroyed}.
3353
- * RUNTIME-ONLY (AGENTS §10) — never a {@link WorkflowStatus}, never persisted in a
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
- * Continue a paused workflow (AGENTS §10); idempotent — a no-op unless {@link paused}.
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
- * Tear this workflow down (AGENTS §10) — an atomic TERMINAL teardown: mark
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
- * Park until this workflow is not paused — **promise-parked**, never a timer or
3398
- * busy-loop (AGENTS §21; mirrors {@link ControllerInterface.wait}'s doc style).
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 once the workflow is no longer paused
3788
+ * @returns A promise that resolves after the workflow is no longer paused
3406
3789
  */
3407
3790
  wait(): Promise<void>;
3408
3791
  /**
3409
- * MINT a live {@link PhaseInterface} (and its tasks) from `definition` and insert it
3410
- * into this workflow (AGENTS §7 the entity structural API) — gated BEFORE delegating
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 `run` / `retries` / `timeout` carried from its {@link TaskDefinition}
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 (AGENTS §12 — no runner-installed hook), UNCHANGED from the entity-taking
3427
- * predecessor: refused outright while this workflow's own `status` is terminal or once
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
- * Remove the `pending` phase `id` from this workflow.
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 (AGENTS §9).
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
- * Reposition the `pending` phase `id` to `index` within this workflow.
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
- * Apply a validated {@link PhaseUpdate} patch to the `pending` phase `id` in this workflow.
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
- * The store-backed registry of {@link WorkflowInterface}s keyed by `id`, in insertion order —
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 {@link createWorkflow} (flowing the manager's
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 (§9.2, array overload FIRST) — `true` when
3500
- * any was removed. `clear` empties the registry.
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
- * A store-backed registry of {@link WorkflowInterface}s keyed by their `id`, in insertion
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`, since a
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 WorkflowFunctions} registry so a HYDRATED workflow is
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
- * (AGENTS §21) — the workflow domain has no consumer that renders "the current workflow" the
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} via {@link import('./factories.js').createWorkflow} (flowing
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, since `createWorkflow` keys the tree by
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 (§9.2, array overload FIRST) — `true`
3566
- * when any was removed. `clear` empties the registry.
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
- * MINT a live {@link WorkflowInterface} from `definition` (via
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
- * Resolve a workflow by id — from the registry if present, else HYDRATED from the
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} via
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
- * Persist a REGISTERED workflow's {@link WorkflowInterface.snapshot} to the optional
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 `true` when the snapshot was persisted; `false` when no store / unknown id
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
- * Options for `createWorkflowManager` — the optional durable {@link WorkflowStoreInterface}
3644
- * seam plus the {@link WorkflowFunctions} registry every workflow the manager mints or
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 WorkflowFunctions} registry threaded into
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-`run` tasks remain deliberate no-ops.
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
- * The optional durable {@link WorkflowStoreInterface} backing
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
- * The {@link WorkflowFunctions} registry threaded into every workflow this manager mints
3670
- * (`add`, via {@link import('./factories.js').createWorkflow}) or hydrates (`open`'s
3671
- * registry-miss path, via {@link import('./factories.js').createRestoredWorkflow}) — so a
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?: WorkflowFunctions;
4076
+ readonly functions?: WorkflowRegistry;
3676
4077
  }
3677
4078
 
3678
4079
  /**
3679
- * The runtime options for a {@link WorkflowInterface} — the construction bag the
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` (AGENTS §8) wires initial {@link WorkflowEventMap} listeners.
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
- * AGENTS §8 "entity is the key" grouping), each leaf reachable by its lineage of ids.
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?: WorkflowHooks;
4092
+ readonly on?: EmitterHooks<WorkflowEventMap>;
3691
4093
  /**
3692
- * The failure policy (AGENTS §4.4) the live tree applies — the same boolean toggle as
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
- /** The emitter's listener-error handler (AGENTS §13) — a listener throw routes here, not to a domain event. */
4102
+ /** Holds the emitter's listener-error handler — a listener throw routes here, not to a domain event. */
3701
4103
  readonly error?: EmitterErrorHandler;
3702
- /** Per-phase {@link PhaseOptions}, keyed by the phase's `id`. */
4104
+ /** Holds the per-phase {@link PhaseOptions}, keyed by the phase's `id`. */
3703
4105
  readonly phases?: Readonly<Record<string, PhaseOptions>>;
3704
4106
  /**
3705
- * The `function`-task behavior registry ({@link WorkflowFunctions}) each live task's
3706
- * {@link TaskDefinition.run} / {@link TaskSnapshot.run} name resolves against ONCE at
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 `run` resolves to no handler and is the deliberate
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 `run` are executable no-ops.
4116
+ * Omitted ⇒ an empty registry; only tasks that also omit `behavior` are executable no-ops.
3715
4117
  */
3716
- readonly functions?: WorkflowFunctions;
3717
- /** Runtime-only default silence; non-positive, non-finite, or over-`MAX_TIMER_MS` disables it. */
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
- * Advanced run-local snapshot persistence with one writer and one coalesced latest obligation.
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
- * Persist every change through this required boundary.
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 Whether the latest state reached the store
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
- * Stop observing the live tree and persist its final state.
4155
+ * Stops observing the live tree and persists its final state.
3743
4156
  *
3744
- * @returns Whether the final snapshot reached the store
4157
+ * @returns True if the final snapshot reached the store; false otherwise
3745
4158
  */
3746
4159
  finalize(): Promise<boolean>;
3747
- /** Stop observing the live tree. */
4160
+ /** Stops observing the live tree. */
3748
4161
  detach(): void;
3749
4162
  }
3750
4163
 
3751
4164
  /**
3752
- * The advanced run-local durability coordinator normally composed by
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
- /** The first required checkpoint failure, if one occurred. */
4169
+ /** Records the first required checkpoint failure, if one occurred. */
3757
4170
  readonly fault: WorkflowFault | undefined;
3758
4171
  /**
3759
- * Make the latest state durable at one required boundary.
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 Whether the latest live state reached the store
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
- /** Detach observers and make the final live state durable. */
4180
+ /** Detaches observers and makes the final live state durable. */
3768
4181
  finalize(): Promise<boolean>;
3769
- /** Stop observing the live workflow tree; idempotent. */
4182
+ /** Stops observing the live workflow tree; idempotent. */
3770
4183
  detach(): void;
3771
4184
  }
3772
4185
 
3773
4186
  /**
3774
- * The structured outcome of a {@link WorkflowRunnerInterface.execute} run the settled
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 WorkflowStatus} at settle (`completed` under graceful mode even with
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 just a snapshot) keeps the entity tree the
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
- readonly status: WorkflowStatus;
4218
+ /** Holds the workflow's derived lifecycle status at settle. */
4219
+ readonly status: LifecycleStatus;
3793
4220
  readonly results: readonly TaskResult[];
3794
- /** Whether the returned final state is stored; omitted when no store was supplied. */
4221
+ /** Reports whether the returned final state is stored; omitted when no store was supplied. */
3795
4222
  readonly durable?: boolean;
3796
- /** The first required persistence failure; omitted when none occurred. */
4223
+ /** Records the first required persistence failure; omitted when none occurred. */
3797
4224
  readonly fault?: WorkflowFault;
3798
4225
  }
3799
4226
 
3800
4227
  /**
3801
- * The thin orchestrator that EXECUTES a live W-b workflow tree by COMPOSING the shipped
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} over the workers
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 simply "invoke the task's own handler". Provider, protocol, and tool
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 `run` / `concurrency`
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 (AGENTS §10:
3828
- * `pause` / `resume` / `add` / `stop` / `destroy` live on the entity itself). Both forms
3829
- * converge on the SAME `#execute` engine: neither reads a `WorkflowDefinition` once the tree
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 `run` deliberately
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: the active-Runner holder is LOCAL to
3875
- * each `#execute`, so a nested application-level `execute` cannot clobber the outer run's
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
- * Execute a workflow definition to completion — BUILD its live tree, run the phases
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 `run` and per-phase `concurrency` come from the same definition
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
- * `run` resolves against) is forwarded to the build. Under `bail: false` (graceful) every
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
- * Drive an ALREADY-BUILT, CALLER-OWNED live {@link WorkflowInterface} — the entity-native
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 via its own `pause` / `resume` / `add` / `stop` / `destroy`
3920
- * (AGENTS §10). Requires `workflow.status === 'pending'`, `!workflow.destroyed`, and no
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. Once accepted, observable
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 bounds
3927
- * (`signal` / `timeout` / `budget`) the construction half of {@link WorkflowRunOptions}
3928
- * does not apply, since the tree already exists.
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
- * A thin orchestrator that EXECUTES a live {@link WorkflowInterface} tree by composing the
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
- * (via {@link import('./factories.js').createWorkflow}) and drives it to a terminal
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 `run` (resolved into
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
- * simply invokes each task's OWN {@link TaskInterface.handler}; an omitted `run` is the only
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 via `AbortSignal.any`, halting the run and `stop`ping the workflow. A second
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 (AGENTS §10: `pause` / `resume` / `add` / `stop` /
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
- * Execute a workflow definition to completion — BUILD its live tree, run the phases
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 `run` (resolved into its {@link TaskInterface.handler}) and per-phase
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 (AGENTS §12).** A PATHOLOGICAL `definition` (e.g. a
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
- * Drive an ALREADY-BUILT, CALLER-OWNED live {@link WorkflowInterface} — the
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 now the single control surface (no separate run handle):
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 via its own `pause` / `resume` / `add` / `stop` /
4019
- * `destroy` (AGENTS §10). Requires `workflow.status === 'pending'`,
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. Once accepted, phases run
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 BOUNDS (`signal` / `timeout` /
4033
- * `budget`) — the construction half of {@link WorkflowRunOptions}
4034
- * does not apply, since the tree already exists.
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 WorkflowFunctions} registry was supplied at that build: WITH a registry,
4039
- * each task's `run` name is re-resolved against it, so a matched task carries a real
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.run} remains visible for inspection while `handler` is
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`); the construction
4048
- * half of {@link WorkflowRunOptions} does not apply (the tree already exists)
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
- * The options for `createWorkflowRunner` — the optional pacing scheduler the runner
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 (AGENTS §8) is intentionally ABSENT: the runner is THIN and drives
4067
- * the W-b entities' OWN emitters (subscribe via `workflow.emitter` / `phase.emitter` /
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
- * The options for one {@link WorkflowRunnerInterface.execute} call — the live tree's
4077
- * CONSTRUCTION options ({@link WorkflowOptions}) PLUS the per-run BOUNDS (an external abort,
4078
- * a deadline, and a cost ceiling), each bound folded into every task's cancellation.
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 (via
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 three bounds below, used only for the run-level fold.
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 via `AbortSignal.any` (exactly as the agent runtime folds its
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
- * The shape of a {@link import('./types.js').WorkflowDefinition} — the contract root:
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
- run: OptionalShape<StringShape>;
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
- * A JSON-serializable snapshot of a whole workflow's state — its identity, status, its
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` (AGENTS §4.4) is the
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
- readonly status: WorkflowStatus;
4162
- /** Whole-workflow `skip` / `stop` or valid task-free vacuous `completed`; omitted when derived. */
4163
- readonly override?: WorkflowStatus;
4164
- /** The failure policy the workflow ran under (AGENTS §4.4) — persisted so a restore re-derives identically. */
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
- * One row of the table a {@link import('./stores/DatabaseWorkflowStore.js').DatabaseWorkflowStore}
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 {@link WorkflowSnapshot} on
4185
- * `get` ({@link import('./helpers.js').isWorkflowSnapshot}, the AGENTS §14 boundary narrow). `id`
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
- /** The whole {@link WorkflowSnapshot} as one opaque JSON blob — read back as `unknown`, narrowed on `get`. */
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
- * The lifecycle status of a workflow the same vocabulary as {@link TaskStatus},
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
- * (AGENTS §21 minimal-interface), since the snapshot is the ONE payload a workflow store persists.
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
- * Resolve the persisted snapshot for `id`, or `undefined` if none is stored.
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
- * Insert or replace a snapshot under its own `snapshot.id` (no separate id param —
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
- * Drop a snapshot by id; an absent id is a no-op (no throw).
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
  */