@sanity/workflow-engine 0.15.0 → 0.16.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.d.ts CHANGED
@@ -40,15 +40,16 @@ export declare function abortReason(
40
40
 
41
41
  /**
42
42
  * The structured half of applicability: does a required subject entry
43
- * (`doc.ref` / `doc.refs`, workflow scope) accept `documentType`? Name-blind
44
- * and EXISTENTIAL: ANY required ref entry counts — a multi-input definition
45
- * (say, contract + counterparty) surfaces from either document's picker, and
46
- * the start dialog collects the remaining required entries (their fail-hard
47
- * validation backstops). An entry without `types` accepts any type; a
48
- * definition with NO required ref entry takes no subject and never matches.
49
- * Cheap and indexable — no GROQ evaluation — so a consumer can pre-filter
50
- * before loading document content. (`required` is pinned to caller-filled
51
- * `input` entries by a deploy invariant, so it alone identifies the handoff.)
43
+ * ({@link isSubjectEntry} — `doc.ref` / `doc.refs`, workflow scope) accept
44
+ * `documentType`? Name-blind and EXISTENTIAL: ANY required ref entry counts —
45
+ * a multi-input definition (say, contract + counterparty) surfaces from
46
+ * either document's picker, and the start dialog collects the remaining
47
+ * required entries (their fail-hard validation backstops). An entry without
48
+ * `types` accepts any type; a definition with NO required ref entry takes no
49
+ * subject and never matches. Cheap and indexable — no GROQ evaluation — so a
50
+ * consumer can pre-filter before loading document content. (`required` is
51
+ * pinned to caller-filled `input` entries by a deploy invariant, so it alone
52
+ * identifies the handoff.)
52
53
  */
53
54
  export declare function acceptsDocumentType(
54
55
  definition: Pick<ApplicabilitySource, "fields">,
@@ -77,7 +78,9 @@ export declare function aclPathForResource(
77
78
  res: WorkflowResource,
78
79
  ): string | undefined;
79
80
 
80
- export declare type Action = ActionFields<Op, string[]>;
81
+ export declare type Action = ActionFields<Op, string[]> & {
82
+ roles?: string[] | undefined;
83
+ };
81
84
 
82
85
  /**
83
86
  * The engine's per-reason detail fragment — the same wording
@@ -121,11 +124,22 @@ export declare type ActionDisabledReason = Exclude<
121
124
  export declare interface ActionEvaluation {
122
125
  action: Action;
123
126
  allowed: boolean;
127
+ /**
128
+ * The action is cascade-fired (`when`): the engine fires it on truth, it
129
+ * is never fireAction-able, and a consumer must not render it as a
130
+ * button — narrate it ("will escalate when overdue") via `whenInsight`.
131
+ * Always set together with the `cascade-fired` `disabledReason` — either
132
+ * check suffices; the flag is the ergonomic spelling.
133
+ */
134
+ triggered?: true;
124
135
  /** Present iff `allowed === false`. The first failing gate wins. */
125
136
  disabledReason?: DisabledReason;
126
137
  /** Derived state of the action's `filter` gate — why it holds or fails,
127
138
  * atom by atom. Present iff the action declares a filter. */
128
139
  insight?: ConditionInsight;
140
+ /** Derived state of a cascade-fired action's `when` trigger — what would
141
+ * fire it. Present iff the action declares `when`. */
142
+ whenInsight?: ConditionInsight;
129
143
  }
130
144
 
131
145
  /** Type-mirror of {@link actionFields}, parameterised over the op and
@@ -135,10 +149,12 @@ declare type ActionFields<TOp, TGroup> = {
135
149
  title?: string | undefined;
136
150
  description?: string | undefined;
137
151
  group?: TGroup | undefined;
152
+ when?: string | undefined;
138
153
  filter?: string | undefined;
139
154
  params?: ActionParam[] | undefined;
140
155
  ops?: TOp[] | undefined;
141
156
  effects?: Effect[] | undefined;
157
+ spawn?: Subworkflows | undefined;
142
158
  };
143
159
 
144
160
  export declare type ActionName = string;
@@ -205,6 +221,26 @@ export declare class ActionParamsInvalidError extends WorkflowError<"action-para
205
221
  });
206
222
  }
207
223
 
224
+ /**
225
+ * The three-way rendering verdict every surface applies to an action:
226
+ * `absent` — its `filter` failed, so it does not exist for this actor/visit
227
+ * (GROQ existence semantics; never even a disabled affordance). `automation` —
228
+ * cascade-fired, so the engine's cascade is its only firing path (narrate it,
229
+ * never render a fire affordance). `button` — fireable: enabled when
230
+ * `allowed`, otherwise disabled WITH its {@link DisabledReason} shown.
231
+ * Structural over the shared verdict fields so {@link ActionEvaluation} and
232
+ * `AvailableAction` both qualify; filter-existence dominates automation, the
233
+ * same order the engine's own verdicts apply.
234
+ */
235
+ export declare function actionRendering(action: {
236
+ triggered?: true;
237
+ disabledReason?:
238
+ | {
239
+ kind: DisabledReason["kind"];
240
+ }
241
+ | undefined;
242
+ }): "absent" | "automation" | "button";
243
+
208
244
  /** The fireable-action verdict for one action on an activity — its `allowed`
209
245
  * state, structured `disabledReason`, and declared params, tagged with the
210
246
  * owning activity. The per-action atom both projections share:
@@ -219,7 +255,6 @@ export declare function actionVerdict(
219
255
  export declare type Activity = ActivityFields<
220
256
  FieldEntry,
221
257
  Action,
222
- Op,
223
258
  ManualTarget,
224
259
  string[]
225
260
  >;
@@ -271,19 +306,16 @@ export declare const ACTIVITY_KINDS: readonly [
271
306
  * `schema.ts → enums.ts` terminates here.
272
307
  */
273
308
  declare const ACTIVITY_STATUSES: readonly [
274
- "pending",
275
309
  "active",
276
310
  "done",
277
311
  "skipped",
278
312
  "failed",
279
313
  ];
280
314
 
281
- /** An activity's four gates, each described — absent keys mirror undeclared gates. */
315
+ /** An activity's gates, each described — absent keys mirror undeclared gates. */
282
316
  export declare interface ActivityDescription {
283
317
  requirements?: Record<string, ConditionDescription>;
284
318
  filter?: ConditionDescription;
285
- completeWhen?: ConditionDescription;
286
- failWhen?: ConditionDescription;
287
319
  }
288
320
 
289
321
  export declare interface ActivityEntry {
@@ -294,6 +326,14 @@ export declare interface ActivityEntry {
294
326
  startedAt?: string;
295
327
  completedAt?: string;
296
328
  completedBy?: string;
329
+ /**
330
+ * Names of this activity's cascade-fired actions that have fired during
331
+ * THIS stage visit — the once-per-visit ledger. Level-triggered: a name
332
+ * lands here on the first evaluation that finds its `when` true and never
333
+ * re-fires within the visit; stage re-entry rebuilds entries, so re-arming
334
+ * on a new visit is structural. Absent until the first trigger fires.
335
+ */
336
+ firedActions?: string[];
297
337
  filterEvaluation?: {
298
338
  at: string;
299
339
  truthy: boolean;
@@ -314,13 +354,27 @@ export declare interface ActivityEvaluation {
314
354
  activity: Activity;
315
355
  status: ActivityStatus;
316
356
  /**
317
- * The activity's effective {@link ActivityKind} the explicit {@link Activity.kind}, or
318
- * the shape-derived default when omitted. Advisory: a label so a consumer can
319
- * render each activity as what it is (`user` / `service` / `script` / `manual` / `receive`).
357
+ * The activity's shape-derived {@link ActivityKind}. Advisory: a label so a
358
+ * consumer can render each activity as what it is (`user` / `service` /
359
+ * `script` / `manual` / `receive`).
320
360
  */
321
361
  kind: ActivityKind;
362
+ /**
363
+ * Who, if anyone, the activity waits on — derived from the definition
364
+ * alone: `autonomous` (every action cascade-fired), `interactive` (only
365
+ * fireAction-fired actions), `off-system` (`target` present), or `hybrid`.
366
+ */
367
+ classification: ExecutorClassification;
322
368
  /** Whether this activity is the current actor's responsibility right now. */
323
369
  pendingOnActor: boolean;
370
+ /**
371
+ * The stage-entry `filter` scoped this activity out of the current visit:
372
+ * its entry is `skipped` and never started, so it does not exist for this
373
+ * visit — surfaces hide it entirely (an action-resolved `skipped` was real,
374
+ * started work and stays visible). Derived via {@link isFilterScopedOut},
375
+ * stamped here so consumers never re-join entry state to compute it.
376
+ */
377
+ scopedOut: boolean;
324
378
  /**
325
379
  * The activity's unmet {@link Activity.requirements}, by name — present iff at least
326
380
  * one is unmet. The activity's own readiness summary: a consumer can explain why
@@ -332,45 +386,28 @@ export declare interface ActivityEvaluation {
332
386
  * Present iff the activity declares requirements; `unmetRequirements`
333
387
  * is exactly the keys whose insight isn't satisfied. */
334
388
  requirementInsights?: Record<string, ConditionInsight>;
335
- /** Derived state of the activity's `filter` skip-gate. Present iff declared.
336
- * Advisory read: the engine's cascade owns the gate itself. */
389
+ /** Derived state of the activity's `filter` existence gate. Present iff
390
+ * declared. Advisory read: the engine's stage entry owns the gate itself. */
337
391
  filterInsight?: ConditionInsight;
338
- /** Derived state of `completeWhen` — what would auto-complete this activity.
339
- * Present iff declared. */
340
- completeWhenInsight?: ConditionInsight;
341
- /** Derived state of `failWhen` — what would auto-fail this activity.
342
- * Present iff declared. */
343
- failWhenInsight?: ConditionInsight;
344
392
  actions: ActionEvaluation[];
345
393
  }
346
394
 
347
- /** Type-mirror of {@link activityFields}, parameterised over field/action/op/target/group. */
348
- declare type ActivityFields<TField, TAction, TOp, TTarget, TGroup> = {
395
+ /** Type-mirror of {@link activityFields}, parameterised over field/action/target/group. */
396
+ declare type ActivityFields<TField, TAction, TTarget, TGroup> = {
349
397
  name: string;
350
398
  title?: string | undefined;
351
399
  description?: string | undefined;
352
400
  groups?: Group[] | undefined;
353
401
  group?: TGroup | undefined;
354
- kind?: ActivityKind | undefined;
355
402
  target?: TTarget | undefined;
356
- activation?: "auto" | "manual" | undefined;
357
403
  filter?: string | undefined;
358
404
  requirements?: Record<string, string> | undefined;
359
- completeWhen?: string | undefined;
360
- failWhen?: string | undefined;
361
- ops?: TOp[] | undefined;
362
- effects?: Effect[] | undefined;
363
405
  actions?: TAction[] | undefined;
364
- subworkflows?: Subworkflows | undefined;
365
406
  fields?: TField[] | undefined;
366
407
  };
367
408
 
368
409
  export declare type ActivityKind = (typeof ACTIVITY_KINDS)[number];
369
410
 
370
- /** The effective kind of an activity: the explicitly declared {@link Activity.kind}, or
371
- * the shape-derived default when omitted. */
372
- export declare function activityKind(activity: Activity): ActivityKind;
373
-
374
411
  export declare type ActivityName = string;
375
412
 
376
413
  export declare type ActivityStatus = (typeof ACTIVITY_STATUSES)[number];
@@ -409,13 +446,18 @@ export declare type ActorKind = (typeof ACTOR_KINDS)[number];
409
446
  export { analyzeCondition };
410
447
 
411
448
  /** The definition surface applicability reads — structural, so authored,
412
- * stored, and deployed definition shapes all fit. `name` is error context
413
- * only: a broken `applicableWhen` fails naming its definition. */
449
+ * stored, and deployed definition shapes all fit. `name` binds
450
+ * `$definition` and names the definition in a broken-filter error. */
414
451
  export declare interface ApplicabilitySource {
415
452
  name?: string | undefined;
416
453
  lifecycle?: WorkflowLifecycle | undefined;
417
454
  fields?: FieldEntry[] | undefined;
418
- applicableWhen?: string | undefined;
455
+ start?:
456
+ | {
457
+ kind?: StartKind | undefined;
458
+ filter?: string | undefined;
459
+ }
460
+ | undefined;
419
461
  }
420
462
 
421
463
  /**
@@ -427,6 +469,8 @@ export declare function applicableDefinitions<
427
469
  >(args: {
428
470
  definitions: readonly T[];
429
471
  document: CandidateDocument;
472
+ /** Caller-side filter bindings, shared by every definition's evaluation. */
473
+ scope?: StartFilterScope;
430
474
  }): Promise<T[]>;
431
475
 
432
476
  /**
@@ -496,7 +540,6 @@ export declare type AuthoringAction = AuthoringRawAction | ClaimAction;
496
540
  export declare type AuthoringActivity = ActivityFields<
497
541
  AuthoringFieldEntry,
498
542
  AuthoringAction,
499
- AuthoringOp,
500
543
  AuthoringManualTarget,
501
544
  GroupMembership
502
545
  >;
@@ -905,7 +948,7 @@ declare const AuthoringManualTargetSchema: v.VariantSchema<
905
948
  undefined
906
949
  >;
907
950
 
908
- declare type AuthoringOp = v.InferOutput<typeof AuthoringOpSchema>;
951
+ export declare type AuthoringOp = v.InferOutput<typeof AuthoringOpSchema>;
909
952
 
910
953
  declare const AuthoringOpSchema: v.VariantSchema<
911
954
  "type",
@@ -1058,7 +1101,7 @@ declare const AuthoringOpSchema: v.VariantSchema<
1058
1101
  undefined
1059
1102
  >;
1060
1103
  readonly status: v.PicklistSchema<
1061
- readonly ["pending", "active", "done", "skipped", "failed"],
1104
+ readonly ["active", "done", "skipped", "failed"],
1062
1105
  `Invalid option: expected one of ${string}`
1063
1106
  >;
1064
1107
  },
@@ -1123,15 +1166,21 @@ declare const AuthoringOpSchema: v.VariantSchema<
1123
1166
  * Authoring action — the stored fields plus two field sugars with one
1124
1167
  * defined expansion each:
1125
1168
  *
1126
- * - `roles` a `count($actor.roles[@ in [...]]) > 0` membership condition
1127
- * ANDed with the authored `filter`. The definition's `roleAliases`
1128
- * ({@link RoleAliasesSchema}) widen that membership at desugar time.
1169
+ * - `roles` on a fireAction-fired action (no `when`) it desugars to a
1170
+ * `count($actor.roles[@ in [...]]) > 0` membership condition ANDed with
1171
+ * the authored `filter` (for a caller, "not yours to fire" and "doesn't
1172
+ * exist for you" are the same advisory answer). On a CASCADE-FIRED
1173
+ * action it stores VERBATIM — the pin on which identities may execute
1174
+ * the trigger; folding it into `filter` would make the action's
1175
+ * existence depend on whose token happens to cascade. The definition's
1176
+ * `roleAliases` ({@link RoleAliasesSchema}) widen the membership either
1177
+ * way.
1129
1178
  * - `status` → a `status.set` op on the firing activity, appended **after**
1130
1179
  * the authored ops (deliberately never implied: a forgotten explicit
1131
1180
  * `status` is a visible stall, an implied default silently completes
1132
1181
  * claim-like actions). Status is the health axis: a decision action
1133
1182
  * (decline, send back) resolves `done` and writes the decision into a
1134
- * field the transition filter reads — `failed` is for work that
1183
+ * field the transition trigger reads — `failed` is for work that
1135
1184
  * genuinely could not complete.
1136
1185
  */
1137
1186
  declare type AuthoringRawAction = ActionFields<AuthoringOp, GroupMembership> & {
@@ -1152,217 +1201,24 @@ export declare type AuthoringStage = StageFields<
1152
1201
  AuthoringEditable
1153
1202
  >;
1154
1203
 
1155
- export declare type AuthoringTransition =
1156
- TransitionFields<AuthoringTransitionOp> & {
1157
- filter?: string | undefined;
1158
- };
1159
-
1160
- declare type AuthoringTransitionOp = v.InferOutput<
1161
- typeof AuthoringTransitionOpSchema
1162
- >;
1204
+ export declare type AuthoringStartBlock = StartFields & {
1205
+ kind?: StartKind | undefined;
1206
+ };
1163
1207
 
1164
1208
  /**
1165
- * Authoring transitions may omit `filter`; desugar fills the safe,
1166
- * overwhelmingly-common gate `"$allActivitiesDone"`. "Fire unconditionally"
1167
- * stays spellable as an explicit `filter: "true"`.
1209
+ * Authoring transitions may omit `when`; desugar fills the safe,
1210
+ * overwhelmingly-common trigger `"$allActivitiesDone"`. "Fire unconditionally"
1211
+ * stays spellable as an explicit `when: "true"`.
1168
1212
  */
1169
- declare const AuthoringTransitionOpSchema: v.VariantSchema<
1170
- "type",
1171
- [
1172
- v.StrictObjectSchema<
1173
- {
1174
- readonly type: v.LiteralSchema<"field.set", undefined>;
1175
- readonly target: v.StrictObjectSchema<
1176
- {
1177
- readonly scope: v.OptionalSchema<
1178
- v.PicklistSchema<
1179
- readonly ["workflow", "stage", "activity"],
1180
- `Invalid option: expected one of ${string}`
1181
- >,
1182
- undefined
1183
- >;
1184
- readonly field: v.SchemaWithPipe<
1185
- readonly [
1186
- v.StringSchema<undefined>,
1187
- v.MinLengthAction<string, 1, "must be a non-empty string">,
1188
- ]
1189
- >;
1190
- },
1191
- undefined
1192
- >;
1193
- readonly value: v.GenericSchema<ValueExprInternal>;
1194
- },
1195
- undefined
1196
- >,
1197
- v.StrictObjectSchema<
1198
- {
1199
- readonly type: v.LiteralSchema<"field.unset", undefined>;
1200
- readonly target: v.StrictObjectSchema<
1201
- {
1202
- readonly scope: v.OptionalSchema<
1203
- v.PicklistSchema<
1204
- readonly ["workflow", "stage", "activity"],
1205
- `Invalid option: expected one of ${string}`
1206
- >,
1207
- undefined
1208
- >;
1209
- readonly field: v.SchemaWithPipe<
1210
- readonly [
1211
- v.StringSchema<undefined>,
1212
- v.MinLengthAction<string, 1, "must be a non-empty string">,
1213
- ]
1214
- >;
1215
- },
1216
- undefined
1217
- >;
1218
- },
1219
- undefined
1220
- >,
1221
- v.StrictObjectSchema<
1222
- {
1223
- readonly type: v.LiteralSchema<"field.append", undefined>;
1224
- readonly target: v.StrictObjectSchema<
1225
- {
1226
- readonly scope: v.OptionalSchema<
1227
- v.PicklistSchema<
1228
- readonly ["workflow", "stage", "activity"],
1229
- `Invalid option: expected one of ${string}`
1230
- >,
1231
- undefined
1232
- >;
1233
- readonly field: v.SchemaWithPipe<
1234
- readonly [
1235
- v.StringSchema<undefined>,
1236
- v.MinLengthAction<string, 1, "must be a non-empty string">,
1237
- ]
1238
- >;
1239
- },
1240
- undefined
1241
- >;
1242
- readonly value: v.GenericSchema<ValueExprInternal>;
1243
- },
1244
- undefined
1245
- >,
1246
- v.StrictObjectSchema<
1247
- {
1248
- readonly type: v.LiteralSchema<"field.updateWhere", undefined>;
1249
- readonly target: v.StrictObjectSchema<
1250
- {
1251
- readonly scope: v.OptionalSchema<
1252
- v.PicklistSchema<
1253
- readonly ["workflow", "stage", "activity"],
1254
- `Invalid option: expected one of ${string}`
1255
- >,
1256
- undefined
1257
- >;
1258
- readonly field: v.SchemaWithPipe<
1259
- readonly [
1260
- v.StringSchema<undefined>,
1261
- v.MinLengthAction<string, 1, "must be a non-empty string">,
1262
- ]
1263
- >;
1264
- },
1265
- undefined
1266
- >;
1267
- readonly where: v.SchemaWithPipe<
1268
- readonly [
1269
- v.StringSchema<undefined>,
1270
- v.MinLengthAction<string, 1, "must be a non-empty string">,
1271
- ]
1272
- >;
1273
- readonly value: v.GenericSchema<ValueExprInternal>;
1274
- },
1275
- undefined
1276
- >,
1277
- v.StrictObjectSchema<
1278
- {
1279
- readonly type: v.LiteralSchema<"field.removeWhere", undefined>;
1280
- readonly target: v.StrictObjectSchema<
1281
- {
1282
- readonly scope: v.OptionalSchema<
1283
- v.PicklistSchema<
1284
- readonly ["workflow", "stage", "activity"],
1285
- `Invalid option: expected one of ${string}`
1286
- >,
1287
- undefined
1288
- >;
1289
- readonly field: v.SchemaWithPipe<
1290
- readonly [
1291
- v.StringSchema<undefined>,
1292
- v.MinLengthAction<string, 1, "must be a non-empty string">,
1293
- ]
1294
- >;
1295
- },
1296
- undefined
1297
- >;
1298
- readonly where: v.SchemaWithPipe<
1299
- readonly [
1300
- v.StringSchema<undefined>,
1301
- v.MinLengthAction<string, 1, "must be a non-empty string">,
1302
- ]
1303
- >;
1304
- },
1305
- undefined
1306
- >,
1307
- v.StrictObjectSchema<
1308
- {
1309
- readonly type: v.LiteralSchema<"audit", undefined>;
1310
- readonly target: v.StrictObjectSchema<
1311
- {
1312
- readonly scope: v.OptionalSchema<
1313
- v.PicklistSchema<
1314
- readonly ["workflow", "stage", "activity"],
1315
- `Invalid option: expected one of ${string}`
1316
- >,
1317
- undefined
1318
- >;
1319
- readonly field: v.SchemaWithPipe<
1320
- readonly [
1321
- v.StringSchema<undefined>,
1322
- v.MinLengthAction<string, 1, "must be a non-empty string">,
1323
- ]
1324
- >;
1325
- },
1326
- undefined
1327
- >;
1328
- readonly value: v.GenericSchema<ValueExprInternal>;
1329
- readonly stampFields: v.OptionalSchema<
1330
- v.StrictObjectSchema<
1331
- {
1332
- readonly actor: v.OptionalSchema<
1333
- v.SchemaWithPipe<
1334
- readonly [
1335
- v.StringSchema<undefined>,
1336
- v.MinLengthAction<string, 1, "must be a non-empty string">,
1337
- ]
1338
- >,
1339
- undefined
1340
- >;
1341
- readonly at: v.OptionalSchema<
1342
- v.SchemaWithPipe<
1343
- readonly [
1344
- v.StringSchema<undefined>,
1345
- v.MinLengthAction<string, 1, "must be a non-empty string">,
1346
- ]
1347
- >,
1348
- undefined
1349
- >;
1350
- },
1351
- undefined
1352
- >,
1353
- undefined
1354
- >;
1355
- },
1356
- undefined
1357
- >,
1358
- ],
1359
- undefined
1360
- >;
1213
+ export declare type AuthoringTransition = TransitionFields & {
1214
+ when?: string | undefined;
1215
+ };
1361
1216
 
1362
1217
  /** The authoring surface: stored primitives plus the define-time sugar. */
1363
1218
  export declare type AuthoringWorkflow = WorkflowFields<
1364
1219
  AuthoringFieldEntry,
1365
- AuthoringStage
1220
+ AuthoringStage,
1221
+ AuthoringStartBlock
1366
1222
  >;
1367
1223
 
1368
1224
  export declare interface AvailableAction {
@@ -1376,7 +1232,10 @@ export declare interface AvailableAction {
1376
1232
  }
1377
1233
 
1378
1234
  /** Flatten an evaluation's current-stage activities into the actions the actor
1379
- * could fire, each carrying whether it's allowed (and why not). */
1235
+ * could fire, each carrying whether it's allowed (and why not). A
1236
+ * filter-scoped-out activity does not exist for this visit, so its actions
1237
+ * never list — the same {@link ActivityEvaluation.scopedOut} split every
1238
+ * other surface applies. */
1380
1239
  export declare function availableActions(
1381
1240
  activities: ActivityEvaluation[],
1382
1241
  ): AvailableAction[];
@@ -1389,6 +1248,22 @@ export declare interface AvailableActionsResult {
1389
1248
  actions: AvailableAction[];
1390
1249
  }
1391
1250
 
1251
+ /**
1252
+ * Type each caller-supplied name→value against the workflow's declared field
1253
+ * entries — the engine takes typed {@link InitialFieldValue}s, and a value's
1254
+ * type IS its declared entry's kind. Only `input`-sourced entries read
1255
+ * caller values (the engine silently ignores the rest), so anything else
1256
+ * fails here, naming the fields that ARE settable; value validation stays
1257
+ * in the engine.
1258
+ */
1259
+ export declare function buildInitialFields({
1260
+ declared,
1261
+ values,
1262
+ }: {
1263
+ declared: Pick<FieldEntry, "type" | "name" | "initialValue">[];
1264
+ values: Record<string, unknown>;
1265
+ }): InitialFieldValue[];
1266
+
1392
1267
  /**
1393
1268
  * Build a snapshot from a set of loaded docs. Pure transform.
1394
1269
  *
@@ -1410,7 +1285,7 @@ export declare function buildSnapshot(args: {
1410
1285
  /**
1411
1286
  * A LOADED candidate document. Applicability evaluates content, so a ref or
1412
1287
  * bare id is not enough: the doc must carry its schema `_type` plus whatever
1413
- * attributes `applicableWhen` predicates read — under whatever perspective
1288
+ * attributes `start.filter` predicates read — under whatever perspective
1414
1289
  * the caller loaded it with.
1415
1290
  */
1416
1291
  export declare interface CandidateDocument {
@@ -1419,12 +1294,12 @@ export declare interface CandidateDocument {
1419
1294
  }
1420
1295
 
1421
1296
  /**
1422
- * Thrown when auto-transitions on an instance fail to stabilise within
1423
- * {@link CascadeLimitError.limit} passes — the signature of a runaway
1424
- * cascade. The classic trigger is two stages whose transition guards
1297
+ * Thrown when hops on an instance fail to stabilise within
1298
+ * {@link CascadeLimitError.limit} moves — the signature of a runaway
1299
+ * cascade. The classic cause is two stages whose transition `when`s
1425
1300
  * stay simultaneously satisfied (e.g. an `op.field.set` lands a value
1426
- * that trips the very guard that fired, and nothing ever clears it), so
1427
- * the engine flip-flops and would otherwise write revisions forever.
1301
+ * that trips the very trigger that fired, and nothing ever clears it),
1302
+ * so the engine flip-flops and would otherwise write revisions forever.
1428
1303
  *
1429
1304
  * The cascade aborts at the limit rather than the engine hanging; the
1430
1305
  * instance is left at whatever stage the last completed pass reached.
@@ -1575,13 +1450,13 @@ export declare interface CompleteEffectArgs extends DedupableOperationArgs {
1575
1450
  effectKey: string;
1576
1451
  status: EffectCompletionStatus;
1577
1452
  /**
1578
- * Named values produced by the effect. If supplied, these are merged
1579
- * into `effectsContext` (replace-by-key) and become available to
1580
- * downstream effect bindings on the same instance. Each value may be any
1581
- * JSON scalar, {@link GlobalDocumentReference}, or an arbitrary
1582
- * object/array (the whole record stores as one `effectsContext.json` entry).
1453
+ * Named values produced by the effect recorded on the run's
1454
+ * `effectHistory` row and read downstream as
1455
+ * `$effects['<effect name>'].<output>` (the latest completed run per
1456
+ * effect name wins). Validated against the effect's declared `outputs`
1457
+ * allowlist; each value may be any JSON.
1583
1458
  */
1584
- outputs?: EffectsContext;
1459
+ outputs?: Record<string, unknown>;
1585
1460
  /**
1586
1461
  * The state half of the effect: `field.*` ops to apply in the completion
1587
1462
  * commit, computed from the effect's real result (e.g. a `field.set` of a
@@ -1616,6 +1491,26 @@ export declare function computeDiffEntries<
1616
1491
  target: DeployTarget;
1617
1492
  }): Promise<DiffEntry[]>;
1618
1493
 
1494
+ /**
1495
+ * Completion twin of {@link ConcurrentFireActionError}: a `completeEffect`
1496
+ * commit lost the optimistic-locking race on every attempt. Same contract —
1497
+ * nothing committed on the final try, so the pending entry (and its claim)
1498
+ * is untouched: the completion can be retried, and a claim whose lease
1499
+ * lapses is recovered by a later drain. The handler's reported outcome is
1500
+ * NOT applied — a caller that retries must not re-run the side effect,
1501
+ * only re-report it.
1502
+ */
1503
+ export declare class ConcurrentCompleteEffectError extends WorkflowError<"concurrent-complete-effect"> {
1504
+ readonly instanceId: string;
1505
+ readonly effectKey: string;
1506
+ readonly attempts: number;
1507
+ constructor(args: {
1508
+ instanceId: string;
1509
+ effectKey: string;
1510
+ attempts: number;
1511
+ });
1512
+ }
1513
+
1619
1514
  /**
1620
1515
  * Edit-seam twin of {@link ConcurrentFireActionError}: an `editField` commit
1621
1516
  * lost the optimistic-locking race on every attempt. Same contract — re-read
@@ -1642,7 +1537,7 @@ export declare class ConcurrentEditFieldError extends WorkflowError<"concurrent-
1642
1537
 
1643
1538
  /**
1644
1539
  * Thrown when a `fireAction` commit loses the optimistic-locking race on
1645
- * all {@link CONCURRENT_FIRE_ACTION_MAX_ATTEMPTS} attempts — every reload +
1540
+ * all {@link CONCURRENT_COMMIT_MAX_ATTEMPTS} attempts — every reload +
1646
1541
  * `ifRevisionId` retry was beaten by another writer committing first.
1647
1542
  * Surfacing it (rather than silently overwriting) lets the caller decide
1648
1543
  * whether to retry later or report a write storm; nothing was committed
@@ -1689,6 +1584,17 @@ export { ConditionClause };
1689
1584
 
1690
1585
  export { ConditionDescription };
1691
1586
 
1587
+ /**
1588
+ * Every STATIC `$fields.<name>` (or `$fields['<name>']` — groq-js normalises
1589
+ * both to `AccessAttribute`) read in a condition, from the AST. Dynamic access
1590
+ * (`$fields[$var]`) carries no static name and is not collected. A malformed
1591
+ * condition reads nothing here ({@link conditionSyntaxIssues} owns the parse
1592
+ * error).
1593
+ */
1594
+ export declare function conditionFieldReadNames(
1595
+ groq: string,
1596
+ ): ReadonlySet<string>;
1597
+
1692
1598
  export { ConditionInsight };
1693
1599
 
1694
1600
  export { ConditionOutcome };
@@ -1697,8 +1603,8 @@ export { ConditionRead };
1697
1603
 
1698
1604
  /**
1699
1605
  * Every condition a definition declares, in stable order: author predicates,
1700
- * then per stage — transitions, activities (filter, requirements,
1701
- * completeWhen, failWhen, action filters), editable gates, tighten-overrides.
1606
+ * then per stage — transitions, activities (filter, requirements, action
1607
+ * filters and `when` triggers), editable gates, tighten-overrides.
1702
1608
  * Editable gates resolve through the same helper the runtime projection uses
1703
1609
  * ({@link editableFieldsInStage}: entry `editable` ANDed with the stage
1704
1610
  * tighten-override), so every live editable-field address exists here with
@@ -1724,25 +1630,30 @@ export declare interface ConditionVar {
1724
1630
  * The condition-variable inventory — the single source of truth for every
1725
1631
  * `$var` the engine binds when it evaluates a {@link Condition}.
1726
1632
  *
1727
- * Three evaluation contexts read a definition's GROQ:
1633
+ * Four evaluation contexts read a definition's GROQ:
1728
1634
  *
1729
1635
  * 1. **Rendered condition scope** — every condition site in a definition
1730
- * (transition filters, `completeWhen`/`failWhen`, action filters, effect
1731
- * bindings, `subworkflows` reads, where-op `where`s, editability
1732
- * predicates, author predicates). {@link CONDITION_VARS} is its inventory;
1733
- * each entry's `binding` says when the var actually holds a value. The
1636
+ * (transition `when`s, activity filters, action `when`s/filters, effect
1637
+ * bindings, `spawn` reads, where-op `where`s, editability predicates,
1638
+ * author predicates). {@link CONDITION_VARS} is its inventory; each
1639
+ * entry's `binding` says when the var actually holds a value. The
1734
1640
  * where-op context is the one closed subset — its bound set is statically
1735
1641
  * fixed and deploy-enforced (see the op-where scope's param-name list in
1736
1642
  * the op applier).
1737
- * 2. **Filter evaluation without a caller** — the engine's cascade evaluates
1738
- * transition filters and the activity gates (`filter`, `completeWhen`,
1739
- * `failWhen`) with no caller, so only the `'always'`-bound subset carries
1740
- * values there ({@link FILTER_SCOPE_VARS}). Caller-bound vars fail closed —
1741
- * `$assigned` binds its caller-free constant `false`, the rest evaluate to
1742
- * `undefined` — and deploy rejects them at these sites: routing and gate
1743
- * resolution must resolve identically no matter whose token triggers the
1744
- * evaluation.
1745
- * 3. **Guard predicates** — NOT conditions. A lake mutation guard's
1643
+ * 2. **Cascade gates** — transition `when`s, activity filters, and a
1644
+ * cascade-fired action's `when`/`filter` must resolve identically no
1645
+ * matter whose token drives the cascade, so only the `'always'`-bound
1646
+ * subset carries values there ({@link FILTER_SCOPE_VARS}). Caller-bound
1647
+ * vars fail closed — `$assigned` binds its caller-free constant `false`,
1648
+ * the rest evaluate to `undefined` — and deploy rejects them at these
1649
+ * sites; a cascade-fired action's per-token gate is `roles`, never its
1650
+ * conditions.
1651
+ * 3. **The start-filter context** — a definition's `start.filter` evaluates
1652
+ * against a CANDIDATE (no instance exists yet): the candidate document is
1653
+ * the root, {@link START_FILTER_VARS} are the only bound vars, and
1654
+ * `*[...]` reads the WORKFLOW resource's dataset. None of the rendered
1655
+ * condition vars exist there.
1656
+ * 4. **Guard predicates** — NOT conditions. A lake mutation guard's
1746
1657
  * `predicate` is groq-js **delta-mode** GROQ over a document mutation:
1747
1658
  * `before()`/`after()`/`identity()` are dialect natives, and the wire
1748
1659
  * format binds the identifiers in {@link GUARD_PREDICATE_VARS}. None of
@@ -1756,10 +1667,42 @@ export declare interface ConditionVar {
1756
1667
  * - `'caller'` — rides the acting caller; without one the var is `undefined`
1757
1668
  * (conditions referencing it fail closed). Author predicates may not read
1758
1669
  * these — they pre-evaluate once per instance, caller-free.
1759
- * - `'spawn'` — bound only at `subworkflows` sites (the per-row `$row`).
1670
+ * - `'spawn'` — bound only at spawn sites (the per-row `$row`).
1760
1671
  */
1761
1672
  export declare type ConditionVarBinding = "always" | "caller" | "spawn";
1762
1673
 
1674
+ /**
1675
+ * The one-doc read a reactive adapter subscribes with to observe a content doc
1676
+ * under a perspective stack — the same GROQ as the engine's own hydration read
1677
+ * ({@link hydrateSnapshot}), so the adapter and the engine resolve identical
1678
+ * content: draft/version content projected onto the published id, a doc that
1679
+ * exists only as a draft (or only inside a release) still visible.
1680
+ */
1681
+ export declare function contentDocQuery(documentId: string): CompiledQuery;
1682
+
1683
+ /**
1684
+ * Whether a watched content doc's reactive read may fall back to the DRAFT —
1685
+ * the fallback half of the per-doc resolution rule {@link contentReleaseName}
1686
+ * starts. Mirrors the engine's own hydration under the instance's effective
1687
+ * perspective (`instance.perspective ?? DEFAULT_CONTENT_PERSPECTIVE`): a draft
1688
+ * is visible only when that perspective names `'drafts'` — the drafts default,
1689
+ * `'drafts'` itself, or a stack like `[release, 'drafts']`. Under `'published'`
1690
+ * / `'raw'` and under a stack without a `'drafts'` entry (`[release]`,
1691
+ * `['published']`) drafts are invisible, and an adapter feeding one would
1692
+ * evaluate content the engine's read can never see.
1693
+ *
1694
+ * Raw refs ({@link readsRaw}) answer `true` by contract, and it is
1695
+ * load-bearing: instance / ancestor / `system.release` docs have no draft
1696
+ * form, and the `true` keeps them on the adapters' raw per-doc read path —
1697
+ * never a perspective-scoped content read.
1698
+ */
1699
+ export declare function contentDraftFallback(args: {
1700
+ ref: {
1701
+ type: string;
1702
+ };
1703
+ perspective: WorkflowPerspective | undefined;
1704
+ }): boolean;
1705
+
1763
1706
  /**
1764
1707
  * The Content Release a watched doc resolves under, or `undefined` for a raw
1765
1708
  * read — how a reactive adapter turns the watch-set's perspective into the
@@ -1772,9 +1715,10 @@ export declare type ConditionVarBinding = "always" | "caller" | "spawn";
1772
1715
  *
1773
1716
  * Note: this resolves a **single** release — the documented `instance.perspective`
1774
1717
  * shapes (`[release]` / `[release, "drafts"]`). The stores' per-doc reads take
1775
- * one release, so a multi-release stack can't be observed reactively here; the
1776
- * engine's own fetch path ({@link hydrateSnapshot}) honours the full stack via
1777
- * `client.fetch({perspective})`.
1718
+ * one release, so a multi-release stack can't be observed through them; the
1719
+ * engine's own fetch path ({@link hydrateSnapshot}) and the SDK adapter's
1720
+ * query-store route for stacks without a `'drafts'` entry — honour the full
1721
+ * stack via `client.fetch({perspective})`.
1778
1722
  */
1779
1723
  export declare function contentReleaseName(args: {
1780
1724
  ref: {
@@ -1783,6 +1727,85 @@ export declare function contentReleaseName(args: {
1783
1727
  perspective: WorkflowPerspective | undefined;
1784
1728
  }): string | undefined;
1785
1729
 
1730
+ /**
1731
+ * Context-bag entry kinds.
1732
+ */
1733
+ export declare const CONTEXT_ENTRY_DISPLAY: {
1734
+ "context.string": {
1735
+ title: string;
1736
+ description: string;
1737
+ };
1738
+ "context.number": {
1739
+ title: string;
1740
+ description: string;
1741
+ };
1742
+ "context.boolean": {
1743
+ title: string;
1744
+ description: string;
1745
+ };
1746
+ "context.ref": {
1747
+ title: string;
1748
+ description: string;
1749
+ };
1750
+ "context.json": {
1751
+ title: string;
1752
+ description: string;
1753
+ };
1754
+ };
1755
+
1756
+ /**
1757
+ * One entry of the instance's `context` bag, rendered to conditions as
1758
+ * `$context.<name>`. **Written exactly twice, both at start**: the
1759
+ * `startInstance` seed and a parent's `spawn.context` handoff. Never
1760
+ * mutated afterwards — completed effects' outputs live on
1761
+ * `effectHistory[].outputs` and render as `$effects`, a separate bag.
1762
+ *
1763
+ * Critical: `context` is NOT a workflow field container. Transition
1764
+ * triggers must NOT read it as fields. The workflow's fields live on
1765
+ * `fields[]`; external state lives in the lake (queryable via conditions).
1766
+ */
1767
+ export declare type ContextEntry =
1768
+ | {
1769
+ _key: string;
1770
+ _type: "context.string";
1771
+ name: string;
1772
+ value: string;
1773
+ }
1774
+ | {
1775
+ _key: string;
1776
+ _type: "context.number";
1777
+ name: string;
1778
+ value: number;
1779
+ }
1780
+ | {
1781
+ _key: string;
1782
+ _type: "context.boolean";
1783
+ name: string;
1784
+ value: boolean;
1785
+ }
1786
+ | {
1787
+ _key: string;
1788
+ _type: "context.ref";
1789
+ name: string;
1790
+ /** GDR — see `../core/refs.ts` */
1791
+ value: GlobalDocumentReference;
1792
+ }
1793
+ | {
1794
+ _key: string;
1795
+ _type: "context.json";
1796
+ name: string;
1797
+ value: string;
1798
+ };
1799
+
1800
+ /**
1801
+ * Render the instance's `context` bag as the `$context` map — the
1802
+ * start-time seed plus a parent's spawn handoff. `json` entries decode to
1803
+ * their object form.
1804
+ */
1805
+ export declare function contextMap(
1806
+ instance: Pick<WorkflowInstance, "context">,
1807
+ ): Record<string, unknown>;
1808
+
1786
1809
  /**
1787
1810
  * A caller broke a public-API contract — a call the engine rejects
1788
1811
  * before touching the lake: an invalid `tag`, a `workflow.query` GROQ that
@@ -1968,6 +1991,11 @@ export declare const DEFAULT_EFFECT_LEASE_MS: number;
1968
1991
  * configured `idempotencyTtlMs`. */
1969
1992
  export declare const DEFAULT_IDEMPOTENCY_TTL_MS: number;
1970
1993
 
1994
+ /** The condition a transition gets when the author declares none — fire once
1995
+ * the stage's own work settles. Exported so consumers describing transition
1996
+ * conditions can recognize the default's spelling without copying it. */
1997
+ export declare const DEFAULT_TRANSITION_WHEN = "$allActivitiesDone";
1998
+
1971
1999
  /**
1972
2000
  * Default LoggerFactory — writes through the global `console`. Exposed
1973
2001
  * so callers outside `createEngine` (drive scripts, the
@@ -2071,7 +2099,7 @@ export declare interface DefinitionsForDocumentArgs {
2071
2099
  /**
2072
2100
  * The LOADED candidate document — unlike {@link InstancesForDocumentArgs},
2073
2101
  * a ref won't do: applicability evaluates content (`_type` against subject
2074
- * entry `types`, `applicableWhen` against the attributes), under whatever
2102
+ * entry `types`, `start.filter` against the attributes), under whatever
2075
2103
  * perspective the caller loaded the document with.
2076
2104
  */
2077
2105
  document: CandidateDocument;
@@ -2272,16 +2300,26 @@ export declare interface DeployTarget {
2272
2300
  }
2273
2301
 
2274
2302
  /**
2275
- * Classify an activity from its shape, in precedence order: an activity a person acts on
2276
- * (`actions`) is `user`; otherwise an automated effect step is `service`;
2277
- * otherwise an activity that waits on a condition (`completeWhen` or a `subworkflows`
2278
- * fan-out) is `receive`; otherwise an inline machine step is `script`.
2279
- *
2280
- * Never returns `manual` — off-system work reads identically to a `user` or
2281
- * `receive` activity by shape, so it is only ever an EXPLICIT {@link Activity.kind}.
2303
+ * Classify an activity from its shape, BPMN-aligned: `target` marks off-system
2304
+ * work (`manual`); otherwise any fireAction-fired action means a person (or
2305
+ * robot caller) acts on it (`user`); otherwise cascade-fired effects make it a
2306
+ * `service` step; otherwise cascade-fired status flips make it a `receive`
2307
+ * wait; anything left is an inline `script` step.
2282
2308
  */
2283
2309
  export declare function deriveActivityKind(activity: Activity): ActivityKind;
2284
2310
 
2311
+ /**
2312
+ * Who, if anyone, the activity waits on — derived ahead-of-time from the
2313
+ * definition alone: `off-system` when `target` is present; else `autonomous`
2314
+ * (every action cascade-fired — no caller ever needed), `interactive` (only
2315
+ * fireAction-fired actions), or `hybrid` (mixed). An actionless activity
2316
+ * classifies `autonomous` vacuously — nothing waits on a caller (deploy's
2317
+ * terminal-reachability invariant rejects it anyway).
2318
+ */
2319
+ export declare function deriveExecutorClassification(
2320
+ activity: Activity,
2321
+ ): ExecutorClassification;
2322
+
2285
2323
  export declare type Describable =
2286
2324
  | ConditionInsight
2287
2325
  | FieldInsight
@@ -2348,8 +2386,10 @@ export declare function describeFieldInsight(
2348
2386
  /**
2349
2387
  * The one front door: feed it any insight-bearing node off an evaluation and
2350
2388
  * get its description — a checklist for gate nodes (undefined when the node
2351
- * declares no gate), all four gates for an activity, involvement + proposals
2352
- * for a field. Dispatch is by each node's defining property, which is
2389
+ * declares no gate), every declared gate for an activity, involvement +
2390
+ * proposals for a field. For an action node the firing gate wins: a
2391
+ * cascade-fired action describes its `when` trigger; a fireAction action
2392
+ * its `filter`. Dispatch is by each node's defining property, which is
2353
2393
  * unambiguous across the union.
2354
2394
  */
2355
2395
  export declare function describeNode<T extends Describable>(
@@ -2379,7 +2419,7 @@ export declare function describeSiteHeading(
2379
2419
  * so a hand-crafted stuck permutation doesn't have to fabricate insights. */
2380
2420
  export declare type DiagnosedTransition = Pick<
2381
2421
  TransitionEvaluation,
2382
- "transition" | "filterSatisfied" | "unevaluable"
2422
+ "transition" | "whenSatisfied" | "unevaluable"
2383
2423
  >;
2384
2424
 
2385
2425
  /**
@@ -2513,12 +2553,19 @@ export declare type DisabledReason =
2513
2553
  * The action's condition evaluated falsy for this actor — the ONE
2514
2554
  * engine-side gate (advisory, like every engine check). Sugar like
2515
2555
  * `roles` desugared into this condition, so a role miss surfaces
2516
- * here too.
2556
+ * here too. Under filter-existence semantics a consumer renders the
2557
+ * action ABSENT, never disabled.
2517
2558
  */
2518
2559
  kind: "filter-failed";
2519
2560
  filter: string;
2520
2561
  detail?: string;
2521
2562
  }
2563
+ | {
2564
+ /** The action is cascade-fired (`when`) — the engine's cascade is its
2565
+ * only firing path; `fireAction` rejects it for every caller. */
2566
+ kind: "cascade-fired";
2567
+ when: string;
2568
+ }
2522
2569
  | {
2523
2570
  kind: "activity-not-active";
2524
2571
  status: TerminalActivityStatus;
@@ -2657,6 +2704,20 @@ declare type DocumentEnvelopeKey =
2657
2704
  | "modelVersion"
2658
2705
  | "minReaderModel";
2659
2706
 
2707
+ /**
2708
+ * The document-prefilter GROQ arm — matches instances that MAY reference any
2709
+ * of `documents`. A deliberate lake-side SUPERSET (it also matches
2710
+ * exited-stage refs); narrow fetched rows to the exact watch-set with
2711
+ * {@link instanceWatchesDocument}. Binds `$documents` + `$bareIds` into
2712
+ * `params`. Exposed for list builders that compose their own conditions
2713
+ * (e.g. the CLI's cross-partition list); {@link instancesQuery} consumers get
2714
+ * it via the `document`/`documents` filter fields instead.
2715
+ */
2716
+ export declare function documentPrefilter(
2717
+ documents: readonly GdrUri[],
2718
+ params: Record<string, string | string[]>,
2719
+ ): string;
2720
+
2660
2721
  export declare type DocumentValuePermission =
2661
2722
  (typeof DOCUMENT_VALUE_PERMISSIONS)[number];
2662
2723
 
@@ -2869,8 +2930,9 @@ export declare type EffectCompletionStatus = Exclude<
2869
2930
 
2870
2931
  /**
2871
2932
  * External effect handler — invoked at drain time with the resolved
2872
- * `params` and a context. Returning `outputs` upserts them into
2873
- * `effectsContext` (replace-by-key) so downstream effects can bind.
2933
+ * `params` and a context. Returning `outputs` records them on the run's
2934
+ * `effectHistory` row, where downstream bindings and conditions read them
2935
+ * as `$effects['<effect name>'].<output>`.
2874
2936
  * Returning `ops` applies the state half of the effect in the completion
2875
2937
  * commit — `field.*` computed from the real result, run through the same op
2876
2938
  * applier as an action's field ops (so a created doc's ref enters `$fields`, or
@@ -2924,7 +2986,7 @@ export declare type EffectHandler = (
2924
2986
  log: (message: string, extra?: Record<string, unknown>) => void;
2925
2987
  },
2926
2988
  ) => Promise<{
2927
- outputs?: EffectsContext;
2989
+ outputs?: Record<string, unknown>;
2928
2990
  ops?: FieldOp[];
2929
2991
  } | void>;
2930
2992
 
@@ -2954,9 +3016,9 @@ export declare interface EffectHistoryEntry {
2954
3016
  stack?: string;
2955
3017
  };
2956
3018
  /**
2957
- * Outputs the runtime reported back. The engine merges these into
2958
- * `effectsContext` (replace-by-name) so downstream effect bindings and
2959
- * `$effects.<name>` reads can reference them. Recorded here for audit.
3019
+ * Outputs the runtime reported back the source the `$effects` read
3020
+ * derives from (`$effects['<effect name>'].<output>` is the latest
3021
+ * completed run's outputs, by name). Recorded here for audit.
2960
3022
  */
2961
3023
  outputs?: Record<string, unknown>;
2962
3024
  }
@@ -3004,14 +3066,16 @@ export declare interface EffectOrigin {
3004
3066
  name: string;
3005
3067
  }
3006
3068
 
3007
- /** The lifecycle boundary that queued an effect — the node IS the moment. */
3008
- export declare type EffectOriginKind = "activity" | "transition" | "action";
3069
+ /** The boundary that queued an effect — actions are the only effect
3070
+ * carriers, so the kind is structural (kept on the row for
3071
+ * self-description). */
3072
+ export declare type EffectOriginKind = "action";
3009
3073
 
3010
3074
  /**
3011
3075
  * Thrown when an effect completes with a returned output its declaration doesn't
3012
3076
  * allow — an undeclared key or a value that doesn't fit the declared shape. The
3013
3077
  * declared `outputs` are a strict allowlist bounding what an effect may persist
3014
- * into `effectsContext`, so the completion does NOT commit rather than silently
3078
+ * onto its `effectHistory` entry, so the completion does NOT commit rather than silently
3015
3079
  * storing off-contract data. An effect that declares no `outputs` has an EMPTY
3016
3080
  * allowlist (produces nothing), so any returned output fails here.
3017
3081
  */
@@ -3021,6 +3085,16 @@ export declare class EffectOutputsInvalidError extends WorkflowError<"effect-out
3021
3085
  constructor(args: { effect: string; issues: string[] });
3022
3086
  }
3023
3087
 
3088
+ /**
3089
+ * Render completed effects' outputs as the `$effects` map — each effect's
3090
+ * LATEST completed run with outputs wins, by name, across the whole
3091
+ * history (outputs are workflow-scope handler results; the per-visit
3092
+ * signal is `$effectStatus`).
3093
+ */
3094
+ export declare function effectOutputsMap(
3095
+ instance: Pick<WorkflowInstance, "effectHistory">,
3096
+ ): Record<string, unknown>;
3097
+
3024
3098
  /**
3025
3099
  * Every terminal state an effect run can record. `done` and `failed` are
3026
3100
  * reported through completion ({@link EffectCompletionStatus}); `cancelled`
@@ -3030,32 +3104,6 @@ export declare class EffectOutputsInvalidError extends WorkflowError<"effect-out
3030
3104
  */
3031
3105
  export declare type EffectRunStatus = "done" | "failed" | "cancelled";
3032
3106
 
3033
- /**
3034
- * EffectsContext entry kinds.
3035
- */
3036
- export declare const EFFECTS_CONTEXT_DISPLAY: {
3037
- "effectsContext.string": {
3038
- title: string;
3039
- description: string;
3040
- };
3041
- "effectsContext.number": {
3042
- title: string;
3043
- description: string;
3044
- };
3045
- "effectsContext.boolean": {
3046
- title: string;
3047
- description: string;
3048
- };
3049
- "effectsContext.ref": {
3050
- title: string;
3051
- description: string;
3052
- };
3053
- "effectsContext.json": {
3054
- title: string;
3055
- description: string;
3056
- };
3057
- };
3058
-
3059
3107
  declare const EffectSchema: v.StrictObjectSchema<
3060
3108
  {
3061
3109
  readonly name: v.SchemaWithPipe<
@@ -3098,8 +3146,9 @@ declare const EffectSchema: v.StrictObjectSchema<
3098
3146
  * doesn't fit its shape — fails the completion (nothing is stored). Omitting
3099
3147
  * `outputs` is an EMPTY allowlist: the effect produces nothing, so any returned
3100
3148
  * output is rejected — the bound is universal, not opt-in.
3101
- * Why strict: `effectsContext` lives on the instance document, so the allowlist
3102
- * keeps it bounded — a handler can't accidentally spread a whole API response
3149
+ * Why strict: outputs land on the instance document's `effectHistory`, so
3150
+ * the allowlist keeps it bounded — a handler can't accidentally spread a
3151
+ * whole API response
3103
3152
  * into the instance — and the declared shapes let tooling (e.g. the simulator's
3104
3153
  * drain UI) suggest an effect's exact output keys. Declaring outputs also
3105
3154
  * powers the advisory deploy-time producer/consumer lint.
@@ -3112,72 +3161,6 @@ declare const EffectSchema: v.StrictObjectSchema<
3112
3161
  undefined
3113
3162
  >;
3114
3163
 
3115
- /**
3116
- * The named-params record effects bind against: what a caller supplies at
3117
- * `startInstance` (stored as {@link WorkflowInstance.effectsContext} entries)
3118
- * and what a handler's `outputs` merges back in (replace-by-key).
3119
- *
3120
- * Each value may be any JSON — a scalar, a {@link GlobalDocumentReference}, or
3121
- * an arbitrary object/array. Scalars and GDRs store as their typed
3122
- * `effectsContext` entries; anything else stores as one `effectsContext.json`
3123
- * entry, so all forms read back the same under `$effects.<name>`.
3124
- */
3125
- export declare type EffectsContext = Record<string, unknown>;
3126
-
3127
- /**
3128
- * Each entry is a named param the runtime hands to effect handlers via
3129
- * binding resolution, rendered to conditions as `$effects.<name>`. **Set at
3130
- * start (including a parent's `subworkflows.context` handoff); appended to
3131
- * only by completed effects reporting `outputs`** — those land as one
3132
- * `json` entry per effect, read as `$effects['<effect name>'].<output>`.
3133
- * Never mutated by user-facing API.
3134
- *
3135
- * Critical: `effectsContext` is NOT a workflow field container.
3136
- * Transition filters must NOT read it as fields. The workflow's fields live
3137
- * on `fields[]`; external state lives in the lake (queryable via filters).
3138
- */
3139
- export declare type EffectsContextEntry =
3140
- | {
3141
- _key: string;
3142
- _type: "effectsContext.string";
3143
- name: string;
3144
- value: string;
3145
- }
3146
- | {
3147
- _key: string;
3148
- _type: "effectsContext.number";
3149
- name: string;
3150
- value: number;
3151
- }
3152
- | {
3153
- _key: string;
3154
- _type: "effectsContext.boolean";
3155
- name: string;
3156
- value: boolean;
3157
- }
3158
- | {
3159
- _key: string;
3160
- _type: "effectsContext.ref";
3161
- name: string;
3162
- /** GDR — see `../core/refs.ts` */
3163
- value: GlobalDocumentReference;
3164
- }
3165
- | {
3166
- _key: string;
3167
- _type: "effectsContext.json";
3168
- name: string;
3169
- value: string;
3170
- };
3171
-
3172
- /**
3173
- * Render `effectsContext` as the `$effects` map. `json` entries decode to
3174
- * their object form so a completed effect's outputs read namespaced:
3175
- * `$effects['<effect name>'].<output>`.
3176
- */
3177
- export declare function effectsContextMap(
3178
- instance: Pick<WorkflowInstance, "effectsContext">,
3179
- ): Record<string, unknown>;
3180
-
3181
3164
  /** The `effectHistory` outcome {@link EffectNotFoundError} reports when the
3182
3165
  * missing key belongs to a settled run. `detail` is the row's recorded
3183
3166
  * detail — for a cancellation, the cause the canceller stamped. */
@@ -3274,7 +3257,7 @@ export declare interface Engine {
3274
3257
  /** The startable half of {@link Engine.instancesForDocument}: the latest
3275
3258
  * deployed version of every definition that applies to the LOADED candidate
3276
3259
  * document — startable, a required subject entry accepts its `_type`, and
3277
- * `applicableWhen` passes. All matches, name ascending; advisory — a start
3260
+ * `start.filter` passes. All matches, name ascending; advisory — a start
3278
3261
  * picker's filter, never enforcement. */
3279
3262
  definitionsForDocument: (
3280
3263
  args: DefinitionsForDocumentArgs,
@@ -3482,6 +3465,26 @@ export declare function evaluateMutationGuard(args: {
3482
3465
  context: MutationContext;
3483
3466
  }): Promise<boolean>;
3484
3467
 
3468
+ /**
3469
+ * Evaluate one `start.filter` in the start-filter context: `document` (may be
3470
+ * absent — root reads then fail closed) as the GROQ root, the
3471
+ * {@link StartFilterScope} bindings plus `$definition`, and — only when
3472
+ * `analyzeCondition` says the filter reads the dataset — the scope's fetched
3473
+ * slice as `*`. Cheap pure evaluation otherwise: no I/O rides a filter that
3474
+ * never scans. GROQ null ("can't decide") is `false` — every consumer of
3475
+ * this verdict fails closed; a parse/evaluation THROW is a malformed
3476
+ * predicate, not an unevaluable one — rethrown loud, naming the definition
3477
+ * (only writable by bypassing deploy validation), so every read surface that
3478
+ * evaluates the filter reports the same context. A failed slice FETCH
3479
+ * propagates as itself: transport trouble, never definition blame.
3480
+ */
3481
+ export declare function evaluateStartFilter(args: {
3482
+ filter: string;
3483
+ definition: Pick<ApplicabilitySource, "name">;
3484
+ document?: CandidateDocument | undefined;
3485
+ scope?: StartFilterScope | undefined;
3486
+ }): Promise<boolean>;
3487
+
3485
3488
  /**
3486
3489
  * Well-known {@link ExecutionContext.kind} values. The field is a free
3487
3490
  * string — these are the shipped vocabulary, not a closed set.
@@ -3528,6 +3531,39 @@ export declare interface ExecutionContext {
3528
3531
  id?: string;
3529
3532
  }
3530
3533
 
3534
+ /**
3535
+ * Executor classifications — who, if anyone, an activity waits on
3536
+ * (derived; see `./activity-kind.ts`).
3537
+ */
3538
+ export declare const EXECUTOR_CLASSIFICATION_DISPLAY: {
3539
+ autonomous: {
3540
+ title: string;
3541
+ description: string;
3542
+ };
3543
+ interactive: {
3544
+ title: string;
3545
+ description: string;
3546
+ };
3547
+ "off-system": {
3548
+ title: string;
3549
+ description: string;
3550
+ };
3551
+ hybrid: {
3552
+ title: string;
3553
+ description: string;
3554
+ };
3555
+ };
3556
+
3557
+ export declare const EXECUTOR_CLASSIFICATIONS: readonly [
3558
+ "autonomous",
3559
+ "interactive",
3560
+ "off-system",
3561
+ "hybrid",
3562
+ ];
3563
+
3564
+ export declare type ExecutorClassification =
3565
+ (typeof EXECUTOR_CLASSIFICATIONS)[number];
3566
+
3531
3567
  export { explainCondition };
3532
3568
 
3533
3569
  export { ExplainConditionArgs };
@@ -3759,10 +3795,11 @@ declare type FieldSourceInternal =
3759
3795
 
3760
3796
  /**
3761
3797
  * The field tree of a persisted value — every leaf replaced by its type name
3762
- * (`null` kept distinct from `object`), object keys sorted, arrays
3763
- * element-wise so discriminated variants stay visible. The comparison form
3764
- * the model-surface gates pin per model version, and the form ops tooling
3765
- * can diff a live document against.
3798
+ * (`null` kept distinct from `object`), object keys sorted by UTF-16 code
3799
+ * unit (locale-independent, so the pinned ledgers canonicalise identically
3800
+ * on every machine), arrays element-wise so discriminated variants stay
3801
+ * visible. The comparison form the model-surface gates pin per model
3802
+ * version, and the form ops tooling can diff a live document against.
3766
3803
  */
3767
3804
  export declare function fieldTreeShape(value: unknown): unknown;
3768
3805
 
@@ -3806,9 +3843,8 @@ export declare class FieldValueShapeError extends WorkflowError<"field-value-sha
3806
3843
  }
3807
3844
 
3808
3845
  /**
3809
- * The subset that holds a value when the engine evaluates filters without a
3810
- * caller (the cascade path: transition filters, activity `filter`/
3811
- * `completeWhen`/`failWhen`).
3846
+ * The subset that holds a value in the cascade gates (transition `when`s,
3847
+ * activity filters, a cascade-fired action's `when`/`filter`).
3812
3848
  */
3813
3849
  export declare const FILTER_SCOPE_VARS: readonly string[];
3814
3850
 
@@ -4380,10 +4416,6 @@ export declare const HISTORY_DISPLAY: {
4380
4416
  title: string;
4381
4417
  description: string;
4382
4418
  };
4383
- activityActivated: {
4384
- title: string;
4385
- description: string;
4386
- };
4387
4419
  activityStatusChanged: {
4388
4420
  title: string;
4389
4421
  description: string;
@@ -4475,14 +4507,6 @@ declare type HistoryEvent =
4475
4507
  reason?: string;
4476
4508
  actor?: Actor;
4477
4509
  }
4478
- | {
4479
- _key: string;
4480
- _type: "activityActivated";
4481
- at: string;
4482
- stage: StageName;
4483
- activity: ActivityName;
4484
- actor?: Actor;
4485
- }
4486
4510
  | {
4487
4511
  _key: string;
4488
4512
  _type: "activityStatusChanged";
@@ -4507,6 +4531,12 @@ declare type HistoryEvent =
4507
4531
  * person/agent/service/engine axis. Absent when no actor was supplied.
4508
4532
  */
4509
4533
  driverKind?: DriverKind;
4534
+ /**
4535
+ * The engine fired this action in a cascade (its `when` turned true) —
4536
+ * {@link actor} is the cascading token that happened to execute it,
4537
+ * not a caller who invoked `fireAction`.
4538
+ */
4539
+ triggered?: true;
4510
4540
  }
4511
4541
  | {
4512
4542
  _key: string;
@@ -4617,16 +4647,15 @@ declare type HistoryEvent =
4617
4647
  _type: "opApplied";
4618
4648
  at: string;
4619
4649
  stage: StageName;
4620
- /** The boundary that ran the op. For an action/transition/activation,
4621
- * exactly one of activity/action/transition is set; for a direct edit
4650
+ /** The boundary that ran the op. For an action fire (caller- or
4651
+ * cascade-fired), `activity` + `action` are set; for a direct edit
4622
4652
  * (the edit seam), `edit` is set and `activity` carries the field's activity when
4623
4653
  * the edited field is activity-scope; for an effect's completion ops,
4624
4654
  * `effect` names the effect. */
4625
4655
  activity?: ActivityName;
4626
4656
  action?: ActionName;
4627
- transition?: string;
4628
4657
  /** Set when the op was a direct edit through the edit seam (`editField`),
4629
- * not an action/transition/activation. */
4658
+ * not an action. */
4630
4659
  edit?: true;
4631
4660
  /** Set when the op came from an effect handler's completion (the state
4632
4661
  * half of an effect); names the effect. */
@@ -4673,6 +4702,15 @@ export declare interface HydratedSnapshot {
4673
4702
  knownIds: Set<string>;
4674
4703
  }
4675
4704
 
4705
+ /**
4706
+ * The in-flight arm — the one spelling of "not completed/aborted" every
4707
+ * list surface's `includeCompleted` filter negates (the engine stamps
4708
+ * `completedAt` on entry into any terminal stage, aborts included). A
4709
+ * sibling of {@link tagScopeFilter} for list builders that compose their
4710
+ * own conditions.
4711
+ */
4712
+ export declare function inFlightFilter(): string;
4713
+
4676
4714
  /**
4677
4715
  * Initial value for an `input`-sourced entry — what a caller supplies at
4678
4716
  * `startInstance` (or `setStage`). Same discriminator shape as
@@ -4706,15 +4744,12 @@ export declare type InsightSite =
4706
4744
  requirement: string;
4707
4745
  }
4708
4746
  | {
4709
- kind: "complete-when";
4710
- activity: string;
4711
- }
4712
- | {
4713
- kind: "fail-when";
4747
+ kind: "action";
4714
4748
  activity: string;
4749
+ action: string;
4715
4750
  }
4716
4751
  | {
4717
- kind: "action";
4752
+ kind: "action-when";
4718
4753
  activity: string;
4719
4754
  action: string;
4720
4755
  }
@@ -4823,7 +4858,7 @@ export declare interface InstanceSession {
4823
4858
  * replace the target's staged rows (last write wins); appends accumulate.
4824
4859
  * Tolerant where commits are loud: a target that doesn't resolve in the
4825
4860
  * current stage (it moved under a mounted editor), a closed edit window
4826
- * (a pending activity's field before activation), or a value that doesn't
4861
+ * (a skipped activity's field), or a value that doesn't
4827
4862
  * fit the field's shape yet (a half-typed date) stages an INERT preview —
4828
4863
  * no echo, no throw; the commit at the semantic boundary is the loud
4829
4864
  * surface. Never persisted — commit via {@link InstanceSession.editField}. */
@@ -4908,6 +4943,13 @@ export declare function instanceWatchesDocument(
4908
4943
  document: GdrUri,
4909
4944
  ): boolean;
4910
4945
 
4946
+ /** The trigger split: a `when` action is cascade-fired; without one it is
4947
+ * fireAction-fired. The single spelling of that test — structural over
4948
+ * `when` so authoring and stored shapes both qualify. */
4949
+ export declare function isCascadeFired(action: {
4950
+ when?: string | undefined;
4951
+ }): boolean;
4952
+
4911
4953
  /**
4912
4954
  * A claim whose lease has lapsed no longer protects the entry. A claim
4913
4955
  * without `leaseExpiresAt` (persisted before leases existed) counts as
@@ -4922,11 +4964,11 @@ export { isComparisonOp };
4922
4964
 
4923
4965
  /**
4924
4966
  * The full applicability derivation for one definition against one loaded
4925
- * document: startable ∧ {@link acceptsDocumentType} ∧ `applicableWhen`.
4967
+ * document: startable ∧ {@link acceptsDocumentType} ∧ `start.filter`.
4926
4968
  * "Deployed" is the caller's premise — feed it deployed definitions (the
4927
4969
  * engine verb `definitionsForDocument` does). Throws when `document` carries
4928
- * no `_type` — that's a ref or a projection, not a loaded document. An
4929
- * `applicableWhen` that doesn't PARSE also throws, naming the definition —
4970
+ * no `_type` — that's a ref or a projection, not a loaded document. A
4971
+ * `start.filter` that doesn't PARSE also throws, naming the definition —
4930
4972
  * that's a malformed definition (only writable by bypassing deploy
4931
4973
  * validation), and silently excluding it would make it vanish from every
4932
4974
  * picker with nothing screaming; only an evaluation result of GROQ null
@@ -4935,8 +4977,22 @@ export { isComparisonOp };
4935
4977
  export declare function isDefinitionApplicable(args: {
4936
4978
  definition: ApplicabilitySource;
4937
4979
  document: CandidateDocument;
4980
+ /** Caller-side filter bindings — omit for the bare candidate-doc context. */
4981
+ scope?: StartFilterScope;
4938
4982
  }): Promise<boolean>;
4939
4983
 
4984
+ /**
4985
+ * Whether an entry was scoped OUT at stage entry — the `filter` existence
4986
+ * gate skipped it before it ever started. Distinct from an action-resolved
4987
+ * `skipped` (real, started work whose entry carries `startedAt`): under
4988
+ * filter-existence semantics render surfaces hide the former and keep the
4989
+ * latter. The ONE spelling of that split.
4990
+ */
4991
+ export declare function isFilterScopedOut(entry: {
4992
+ status: ActivityStatus;
4993
+ startedAt?: string | undefined;
4994
+ }): boolean;
4995
+
4940
4996
  /** Type filter for GDR shape. */
4941
4997
  export declare function isGdr(value: unknown): value is GlobalDocumentReference;
4942
4998
 
@@ -4974,7 +5030,7 @@ export declare function isNotesEntry(
4974
5030
  /**
4975
5031
  * Whether a human may start this definition standalone (the default). A
4976
5032
  * `lifecycle: 'child'` definition is spawn-only — instantiated by a parent via
4977
- * `activity.subworkflows`, so consumers exclude it from top-level start pickers.
5033
+ * an action's `spawn`, so consumers exclude it from top-level start pickers.
4978
5034
  * Advisory: the engine does not enforce it (see the `required`-field backstop
4979
5035
  * for load-bearing input fields). Accepts any definition-shaped value (authored,
4980
5036
  * stored, deployed, or a projected list row).
@@ -4983,6 +5039,18 @@ export declare function isStartableDefinition(definition: {
4983
5039
  lifecycle?: WorkflowLifecycle | undefined;
4984
5040
  }): boolean;
4985
5041
 
5042
+ /**
5043
+ * The SUBJECT-ENTRY RULE: a required `doc.ref` / `doc.refs` input entry is
5044
+ * what makes a definition "about" a subject document. One predicate shared by
5045
+ * applicability's type matching (`acceptsDocumentType`), the autonomous-start
5046
+ * deploy invariant, and the root-read deploy check (a root-reading
5047
+ * `start.filter` needs a subject entry to bind a candidate root) — so
5048
+ * "counts as a subject" can't drift between them.
5049
+ */
5050
+ export declare function isSubjectEntry(
5051
+ entry: Pick<FieldEntry, "required" | "type">,
5052
+ ): boolean;
5053
+
4986
5054
  /**
4987
5055
  * The environment denial process shells (CLI, MCP server) feed
4988
5056
  * {@link createTelemetryIntake}: CI and `DO_NOT_TRACK` are trueish
@@ -5058,18 +5126,18 @@ export declare function latestDeployedDefinitions<
5058
5126
 
5059
5127
  /**
5060
5128
  * Advisory producer/consumer check for a deployed definition: every
5061
- * `$effects['<name>'].<key>` read whose `<name>` is a declared effect that
5062
- * declares its `outputs` but does not list `<key>`. Returns human-readable
5063
- * warning strings (empty when clean) — deploy surfaces them, it never rejects.
5064
- * (Runtime completion is where declared `outputs` are ENFORCED; this only warns
5065
- * the author at deploy about a consumer read of a key no producer declares.)
5129
+ * `$effects['<name>'].<key>` read whose `<name>` is not a declared effect,
5130
+ * or is one whose declared `outputs` do not list `<key>`. Returns
5131
+ * human-readable warning strings (empty when clean) — deploy surfaces them,
5132
+ * it never rejects. (Runtime completion is where declared `outputs` are
5133
+ * ENFORCED; this only warns the author at deploy about a consumer read no
5134
+ * producer declares.)
5066
5135
  *
5067
- * Advisory-strength by design: it flags reads against DECLARED effects only. A
5068
- * name that is not a declared effect is left alone it may be a `startInstance`
5069
- * `effectsContext` seed key or a `subworkflows.context` handoff key, runtime
5070
- * producers the static definition cannot see. An effect that declares no
5071
- * `outputs` produces nothing (an empty allowlist), so a keyed read of it is
5072
- * flagged like any undeclared key.
5136
+ * `$effects` derives solely from completed effects' outputs the start
5137
+ * seed and spawn handoff live in `$context` so every producer IS a
5138
+ * declared effect and an unknown name is warnable, not tolerated. An
5139
+ * effect that declares no `outputs` produces nothing (an empty allowlist),
5140
+ * so a keyed read of it is flagged like any undeclared key.
5073
5141
  *
5074
5142
  * Reads are collected from the primary consumer sites: condition GROQ
5075
5143
  * ({@link conditionSitesOf}), effect binding GROQ, and guard reads (the
@@ -5171,8 +5239,8 @@ export declare type MissingHandlerPolicy =
5171
5239
  * read in {@link resolveInputValue}, but is stricter: a present-but-null/
5172
5240
  * undefined value counts as absent here (a required field needs a real
5173
5241
  * value), whereas {@link resolveInputValue} passes a null fill straight
5174
- * through. Exported so pre-flight validators (e.g. a start gate) share the
5175
- * engine's own rule instead of mirroring it.
5242
+ * through. Exported so pre-flight validators (e.g. mapping validation) share
5243
+ * the engine's own rule instead of mirroring it.
5176
5244
  */
5177
5245
  export declare function missingRequiredInputs(args: {
5178
5246
  entryDefs: readonly FieldEntry[];
@@ -5446,6 +5514,19 @@ export declare function parentRef(
5446
5514
  instance: Pick<WorkflowInstance, "ancestors">,
5447
5515
  ): GlobalDocumentReference | undefined;
5448
5516
 
5517
+ /**
5518
+ * Parse one incoming definition at the deploy/diff boundary (`caller` prefixes
5519
+ * the error). Accepts authored content or a fetched definition document — the
5520
+ * document envelope is stripped (the inverse of the deploy serialisation, so a
5521
+ * fetched document round-trips to `unchanged` instead of fingerprinting its
5522
+ * envelope as content), then the remainder strict-parses against the stored
5523
+ * schema: any unknown key anywhere in the tree fails loud.
5524
+ */
5525
+ export declare function parseDefinitionInput(
5526
+ def: Record<string, unknown>,
5527
+ caller: string,
5528
+ ): WorkflowDefinition;
5529
+
5449
5530
  /**
5450
5531
  * The ONE way to read an instance's frozen {@link WorkflowInstance.definitionSnapshot}
5451
5532
  * back into a {@link WorkflowDefinition} — wraps the parse so a corrupt
@@ -5601,6 +5682,26 @@ export declare function processShellUserProperties<
5601
5682
  runtimeVersion: string;
5602
5683
  };
5603
5684
 
5685
+ /**
5686
+ * Project a store-resolved doc onto its watch ref's identity, the way the
5687
+ * lake's perspective reads do: the published-form id becomes `_id` (the form
5688
+ * the session keys its overlay and snapshot by), and a draft/version
5689
+ * representation's stored id rides along as `_originalId` — session-side
5690
+ * conditions (including the `_originalId in path("versions.**")` shape) then
5691
+ * read exactly what the engine's own hydration ({@link contentDocQuery})
5692
+ * returns. Strict by construction: only the ids in
5693
+ * {@link watchRefRepresentations} are accepted — an id that merely *ends* in
5694
+ * the watched id (another doc's dotted id under a version prefix), a release
5695
+ * the perspective doesn't read, or a draft the perspective makes invisible is
5696
+ * a store routing bug, and projecting it would make content the engine's read
5697
+ * can never see impersonate the watched doc silently, so it throws instead.
5698
+ */
5699
+ export declare function projectToWatchRef(args: {
5700
+ doc: SanityDocument;
5701
+ ref: SubscriptionDocument;
5702
+ perspective: WorkflowPerspective | undefined;
5703
+ }): SanityDocument;
5704
+
5604
5705
  export declare interface QueryArgs {
5605
5706
  groq: string;
5606
5707
  params?: Record<string, unknown>;
@@ -5621,6 +5722,18 @@ export { quoted };
5621
5722
  */
5622
5723
  export declare function readsRaw(ref: { type: string }): boolean;
5623
5724
 
5725
+ /**
5726
+ * Whether a GROQ expression reads its ROOT document — the candidate document
5727
+ * a `start.filter` binds as root. A bare attribute access (`_type == 'task'`)
5728
+ * or `@` in the OUTER scope reads the root; the same inside a construct that
5729
+ * rebinds the implicit `this` per element (`*[...]` filters, projections,
5730
+ * `map`/pipe traversals) addresses THOSE items, so it doesn't. `^` (Parent)
5731
+ * climbs scopes — one that escapes past the outermost scope lands back on the
5732
+ * root and counts, wherever it is nested. A malformed expression reads
5733
+ * nothing here ({@link conditionSyntaxIssues} owns the parse error).
5734
+ */
5735
+ export declare function readsRootDocument(groq: string): boolean;
5736
+
5624
5737
  /** Make a GDR pointer to a Canvas-resource doc. */
5625
5738
  export declare function refCanvas<TType extends string = string>({
5626
5739
  resourceId,
@@ -5720,8 +5833,8 @@ export declare function remediationsFor(
5720
5833
  /**
5721
5834
  * A verb that would unstick a {@link StuckCause} — the *what to do about it*
5722
5835
  * half of a diagnosis. Surface-neutral identifiers; a consumer maps each to
5723
- * its own command or button. `retry-effect`, `drain-effects` and `reset-activity`
5724
- * are not yet callable engine operations — see {@link SuggestedRemediation.available}.
5836
+ * its own command or button. `retry-effect` and `reset-activity` are not yet
5837
+ * callable engine operations — see {@link SuggestedRemediation.available}.
5725
5838
  */
5726
5839
  export declare type RemediationVerb =
5727
5840
  | "retry-effect"
@@ -6057,6 +6170,78 @@ declare interface StageGuardArgs {
6057
6170
 
6058
6171
  export declare type StageName = string;
6059
6172
 
6173
+ /**
6174
+ * The vars a definition's `start.filter` reads — the start-filter dialect,
6175
+ * not the rendered condition scope (no {@link ConditionVarBinding}: these
6176
+ * bind only while the filter is evaluated on the READ side — the
6177
+ * `definitionsForDocument` derivation and the Studio start control).
6178
+ * `startInstance` never evaluates the filter. An absent binding evaluates to
6179
+ * GROQ null, so a read of it fails closed: a picker with no `initialFields`
6180
+ * in hand hides a `$fields`-reading definition rather than guessing. Bound in
6181
+ * one place: `startFilterParams` in the applicability evaluator.
6182
+ */
6183
+ export declare const START_FILTER_VARS: readonly {
6184
+ name: string;
6185
+ description: string;
6186
+ }[];
6187
+
6188
+ declare const START_KINDS: readonly ["interactive", "autonomous"];
6189
+
6190
+ export declare type StartBlock = StartFields & {
6191
+ kind: StartKind;
6192
+ };
6193
+
6194
+ /**
6195
+ * The start-time seed a caller supplies at `startInstance`, stored as
6196
+ * {@link WorkflowInstance.context} entries and read back as
6197
+ * `$context.<name>`. Written only at start — a completed effect's
6198
+ * `outputs` live on the run row and read as `$effects`, a separate bag.
6199
+ *
6200
+ * Each value may be any JSON — a scalar, a {@link GlobalDocumentReference}, or
6201
+ * an arbitrary object/array. Scalars and GDRs store as their typed
6202
+ * `context` entries; anything else stores as one `context.json` entry.
6203
+ */
6204
+ export declare type StartContext = Record<string, unknown>;
6205
+
6206
+ /** Type-mirror of {@link startFields}: how standalone runs of this workflow
6207
+ * begin. Stored requires `kind` (desugar fills the `'interactive'` default);
6208
+ * authoring may omit it — so each variant declares it. */
6209
+ declare type StartFields = {
6210
+ filter?: string | undefined;
6211
+ };
6212
+
6213
+ /**
6214
+ * The caller-side half of the start-filter context — everything the
6215
+ * evaluating surface knows that the definition doesn't. Every member is
6216
+ * optional because the surfaces genuinely differ (a picker holds no
6217
+ * `initialFields`; a pure consumer may hold no clock): an absent binding
6218
+ * evaluates to GROQ null, so a filter reading it FAILS CLOSED rather than
6219
+ * guessing. The vars themselves are inventoried in `START_FILTER_VARS`.
6220
+ */
6221
+ export declare interface StartFilterScope {
6222
+ /** The engine's tag partition — binds `$tag`. */
6223
+ tag?: string | undefined;
6224
+ /** ISO clock reading — binds `$now`. */
6225
+ now?: string | undefined;
6226
+ /**
6227
+ * The candidate initialFields by entry name — binds `$fields`. Document
6228
+ * references bind as their GDR envelopes (`$fields.<entry>.id` is the GDR
6229
+ * URI). A surface that holds the caller's inputs (the Studio start control)
6230
+ * supplies them; a per-doc picker does not.
6231
+ */
6232
+ fields?: Record<string, unknown> | undefined;
6233
+ /**
6234
+ * The WORKFLOW resource's dataset, for filters that read it (`*[...]` or a
6235
+ * deref) — invoked lazily, only when `analyzeCondition` says the filter
6236
+ * needs it. A slice is fine as long as it covers what filters scan;
6237
+ * `definitionsForDocument` supplies EVERY instance of the tag, completed
6238
+ * included — `*` carries no hidden predicate, so authors qualify in-flight
6239
+ * themselves (`!defined(completedAt)`). Absent ⇒ a dataset-reading filter
6240
+ * fails closed (this surface cannot see the dataset, so it cannot decide).
6241
+ */
6242
+ fetchDataset?: (() => Promise<unknown[]>) | undefined;
6243
+ }
6244
+
6060
6245
  export declare interface StartInstanceArgs {
6061
6246
  /** The definition's `name` — which deployed workflow to instantiate. */
6062
6247
  definition: string;
@@ -6079,16 +6264,17 @@ export declare interface StartInstanceArgs {
6079
6264
  initialFields?: InitialFieldValue[];
6080
6265
  ancestors?: GlobalDocumentReference[];
6081
6266
  /**
6082
- * Stable named params for effect handlers, set at start time. The
6083
- * runtime resolves effect bindings against these to materialise
6084
- * handler params at queue time. **Not read by transition filters.**
6267
+ * The instance's start seed stable named values set once at start (or
6268
+ * handed down by a parent's `spawn.context`) and never mutated after.
6269
+ * Effect bindings and conditions read them as `$context.<name>`; the
6270
+ * `$effects` bag is separate (completed effects' outputs only).
6085
6271
  *
6086
6272
  * Each value may be any JSON — a scalar, a {@link GlobalDocumentReference},
6087
6273
  * or an arbitrary object/array. Scalars and GDRs store as their typed
6088
- * `effectsContext` entries; anything else stores as one `effectsContext.json`
6089
- * entry, so all forms read back the same under `$effects.<name>`.
6274
+ * `context` entries; anything else stores as one `context.json`
6275
+ * entry, so all forms read back the same under `$context.<name>`.
6090
6276
  */
6091
- effectsContext?: EffectsContext;
6277
+ context?: StartContext;
6092
6278
  /** Caller-supplied id; auto-generated otherwise. */
6093
6279
  instanceId?: string;
6094
6280
  /**
@@ -6118,6 +6304,41 @@ export declare interface StartInstanceArgs {
6118
6304
  perspective?: WorkflowPerspective;
6119
6305
  }
6120
6306
 
6307
+ /**
6308
+ * Who initiates a standalone run of this workflow: a person picking it from a
6309
+ * start surface (`'interactive'`, the default) or a system reacting to a
6310
+ * document event (`'autonomous'`). PURE CLASSIFICATION — consumers use it to
6311
+ * shape their surfaces (hide autonomous workflows from human pickers, list
6312
+ * interactive ones for editors); `startInstance` is one verb and one code
6313
+ * path for every kind, and an interactive start of an autonomous workflow is
6314
+ * legal.
6315
+ */
6316
+ export declare type StartKind = (typeof START_KINDS)[number];
6317
+
6318
+ /**
6319
+ * The declared {@link StartKind} of a definition, defaulting the absent
6320
+ * `start` block to `'interactive'` — the one reading rule for every consumer,
6321
+ * so definitions deployed before the block existed classify unchanged.
6322
+ * Classification only: the engine never gates on it.
6323
+ */
6324
+ export declare function startKindOf(definition: {
6325
+ start?:
6326
+ | {
6327
+ kind?: StartKind | undefined;
6328
+ }
6329
+ | undefined;
6330
+ }): StartKind;
6331
+
6332
+ /**
6333
+ * Why a definition can't be started standalone, or `undefined` when it can.
6334
+ * Advisory — the engine itself does not refuse ({@link isStartableDefinition})
6335
+ * — but a start surface has no way to supply the parent context a spawn-only
6336
+ * child expects, so it fails fast with this message instead.
6337
+ */
6338
+ export declare function startRefusal(definition: {
6339
+ lifecycle?: WorkflowLifecycle | undefined;
6340
+ }): string | undefined;
6341
+
6121
6342
  /**
6122
6343
  * Declared editability of a field — the generic edit seam's gate. Default
6123
6344
  * (absent) is NOT editable: a field is op-only engine working memory unless the
@@ -6468,7 +6689,7 @@ declare const StoredOpSchema: v.VariantSchema<
6468
6689
  ]
6469
6690
  >;
6470
6691
  readonly status: v.PicklistSchema<
6471
- readonly ["pending", "active", "done", "skipped", "failed"],
6692
+ readonly ["active", "done", "skipped", "failed"],
6472
6693
  `Invalid option: expected one of ${string}`
6473
6694
  >;
6474
6695
  },
@@ -6507,7 +6728,7 @@ export declare type StuckCause =
6507
6728
  kind: "no-transition-fires";
6508
6729
  }
6509
6730
  /**
6510
- * Every activity resolved, but an exit transition's filter is *unevaluable*
6731
+ * Every activity resolved, but an exit transition's `when` is *unevaluable*
6511
6732
  * (GROQ `null` — a referenced operand is missing/unreadable), so selection
6512
6733
  * halts. Unlike {@link StuckCause} `no-transition-fires` this is recoverable:
6513
6734
  * the cascade re-fires once the operand resolves (e.g. the subject is
@@ -6582,6 +6803,12 @@ export declare interface SubworkflowEntry {
6582
6803
  _key: string;
6583
6804
  /** The spawning activity's name. */
6584
6805
  activity: ActivityName;
6806
+ /**
6807
+ * The spawning ACTION's name — rows key per (activity entry, spawning
6808
+ * action), so two spawn actions on one activity can never cross-adopt
6809
+ * each other's children.
6810
+ */
6811
+ action: string;
6585
6812
  /** The child definition's `name` — adoption never crosses definitions. */
6586
6813
  definition: string;
6587
6814
  /**
@@ -6705,8 +6932,8 @@ declare const SubworkflowsSchema: v.StrictObjectSchema<
6705
6932
  >;
6706
6933
  /**
6707
6934
  * Extra values evaluated in the parent's rendered scope at spawn time and
6708
- * delivered into each subworkflow's `$effects` bag — the parent→child
6709
- * handoff, read exactly like an effect output.
6935
+ * delivered into each subworkflow's `$context` bag — the parent→child
6936
+ * handoff.
6710
6937
  */
6711
6938
  readonly context: v.OptionalSchema<
6712
6939
  v.RecordSchema<
@@ -6728,13 +6955,13 @@ declare const SubworkflowsSchema: v.StrictObjectSchema<
6728
6955
  >;
6729
6956
  /**
6730
6957
  * What happens to still-live children when their cohort's scope stops
6731
- * applying — the spawning stage exits, or a re-entry's `forEach` no longer
6958
+ * applying — the spawning stage exits, or a re-fire's `forEach` no longer
6732
6959
  * discovers their row. `'detach'` (the default) lets them run to
6733
6960
  * completion outside the gate; `'abort'` kills them (recursively). The
6734
6961
  * engine never destroys in-flight work implicitly — `'abort'` is always
6735
6962
  * an authored choice. Note this governs only the CHILDREN's fate; whether
6736
- * the parent may move at all is what gates (`completeWhen`, transition
6737
- * filters over `$subworkflows`) decide.
6963
+ * the parent may move at all is what gates (conditions over
6964
+ * `$subworkflows`) decide.
6738
6965
  */
6739
6966
  readonly onExit: v.OptionalSchema<
6740
6967
  v.PicklistSchema<
@@ -6910,46 +7137,42 @@ export declare interface TodoListItem {
6910
7137
  dueDate?: string | null;
6911
7138
  }
6912
7139
 
6913
- export declare type Transition = TransitionFields<TransitionOp> & {
6914
- filter: string;
7140
+ export declare type Transition = TransitionFields & {
7141
+ when: string;
6915
7142
  };
6916
7143
 
6917
7144
  export declare interface TransitionEvaluation {
6918
7145
  transition: Transition;
6919
7146
  /**
6920
- * Whether the transition's filter is definitively satisfied at read time.
6921
- * Projected caller-free, exactly as the engine's cascade evaluates it — the
6922
- * evaluation's actor and grants never participate.
7147
+ * Whether the transition's `when` trigger is definitively satisfied at read
7148
+ * time. Projected caller-free, exactly as the engine's cascade evaluates
7149
+ * it — the evaluation's actor and grants never participate.
6923
7150
  */
6924
- filterSatisfied: boolean;
7151
+ whenSatisfied: boolean;
6925
7152
  /**
6926
- * The filter evaluated to GROQ `null` — a referenced operand was missing or
6927
- * incomparable, so it couldn't be decided. `filterSatisfied` is `false`, but
7153
+ * The trigger evaluated to GROQ `null` — a referenced operand was missing or
7154
+ * incomparable, so it couldn't be decided. `whenSatisfied` is `false`, but
6928
7155
  * this is a *recoverable hold*, not a deliberate `false`: the engine halts
6929
7156
  * selection (it won't fall through to a later transition) and the cascade
6930
7157
  * re-fires once the operand resolves. Lets a diagnosis tell an undecidable
6931
7158
  * hold apart from a genuine routing dead-end.
6932
7159
  */
6933
7160
  unevaluable: boolean;
6934
- /** Derived state of the transition's filter — the atoms standing between
6935
- * here and the next stage. `filterSatisfied`/`unevaluable` are projections
7161
+ /** Derived state of the transition's `when` trigger — the atoms standing between
7162
+ * here and the next stage. `whenSatisfied`/`unevaluable` are projections
6936
7163
  * of `insight.outcome`; one evaluation feeds all three. */
6937
7164
  insight: ConditionInsight;
6938
7165
  }
6939
7166
 
6940
- /** Type-mirror of {@link transitionFields} minus `filter` — stored requires it,
7167
+ /** Type-mirror of {@link transitionFields} minus `when` — stored requires it,
6941
7168
  * authoring omits it (desugar fills the default), so each variant declares it. */
6942
- declare type TransitionFields<TOp> = {
7169
+ declare type TransitionFields = {
6943
7170
  name: string;
6944
7171
  title?: string | undefined;
6945
7172
  description?: string | undefined;
6946
7173
  to: string;
6947
- ops?: TOp[] | undefined;
6948
- effects?: Effect[] | undefined;
6949
7174
  };
6950
7175
 
6951
- export declare type TransitionOp = FieldOp;
6952
-
6953
7176
  /**
6954
7177
  * Parse a GDR URI, returning `undefined` instead of throwing when the string
6955
7178
  * is not a GDR (or is malformed). The "is this a GDR, and if so its parts"
@@ -6973,8 +7196,8 @@ export declare function unsatisfiedTransitionSummaries(
6973
7196
 
6974
7197
  /**
6975
7198
  * Validate a (stored, desugared) definition before deploy: parse-check every
6976
- * GROQ string (malformed predicates, conditions, bindings, `completeWhen`/
6977
- * `failWhen`) and re-run the cross-field invariants. `defineWorkflow` already
7199
+ * GROQ string (malformed predicates, conditions, bindings, triggers) and
7200
+ * re-run the cross-field invariants. `defineWorkflow` already
6978
7201
  * ran the invariants at authoring time, but deploy must reject what authoring
6979
7202
  * rejects — a stored-shape definition handed straight to the verb (raw JSON,
6980
7203
  * a foreign tool) would otherwise bypass every invariant.
@@ -7096,16 +7319,18 @@ export declare interface WatchSet {
7096
7319
  /**
7097
7320
  * The instance's effective read perspective (a release stack like
7098
7321
  * `[releaseName]` or `[releaseName, "drafts"]`), already resolved at
7099
- * `startInstance`. `undefined` means raw/published.
7322
+ * `startInstance`. `undefined` means content reads use the
7323
+ * drafts-preferring {@link DEFAULT_CONTENT_PERSPECTIVE}.
7100
7324
  *
7101
7325
  * The engine does not form `versions.<release>.<id>` ids — it has no
7102
7326
  * such concept (it reads content through `client.fetch({perspective})`
7103
7327
  * for queries). A reactive consumer applies this perspective when it
7104
- * subscribes: a **content** doc must be resolved to its version /
7105
- * draft / published form (e.g. Studio `editState`'s version param, or
7106
- * the SDK's `getVersionId`), while instance / ancestor / `system.release`
7107
- * docs are always raw. The `type` on each {@link SubscriptionDocument}
7108
- * tells the consumer which is which.
7328
+ * subscribes: a **content** doc resolves under the release
7329
+ * {@link contentReleaseName} names (e.g. Studio `editState`'s version
7330
+ * param, or the SDK's `getVersionId`), falling back to the draft only
7331
+ * when {@link contentDraftFallback} allows it, then published while
7332
+ * instance / ancestor / `system.release` docs are always raw. The `type`
7333
+ * on each {@link SubscriptionDocument} tells the consumer which is which.
7109
7334
  */
7110
7335
  perspective?: WorkflowPerspective;
7111
7336
  }
@@ -7131,7 +7356,7 @@ export declare const workflow: {
7131
7356
  * never patches a deployed version, so a definition can't change out from
7132
7357
  * under the instances pinned to it. `startInstance` picks the highest
7133
7358
  * version by default. The engine figures out the dependency order itself
7134
- * (children before parents that spawn them via `subworkflows.definition`)
7359
+ * (children before parents that spawn them via `action.spawn.definition`)
7135
7360
  * and reports a per-definition outcome (`created` / `unchanged`).
7136
7361
  *
7137
7362
  * Refs may point inside the batch OR at already-deployed definitions
@@ -7161,20 +7386,26 @@ export declare const workflow: {
7161
7386
  /**
7162
7387
  * Spawn a new workflow instance from a deployed definition.
7163
7388
  *
7164
- * Pins the snapshot at start-time, seeds `effectsContext`, enters
7165
- * the initial stage (which builds activityStatus, queues onEnter
7166
- * effects, auto-activates activities). Then cascades auto-transitions
7167
- * until stable. Starting always changes state (`changed: true`)
7168
- * `cascaded` reports how far the new instance auto-advanced.
7389
+ * Throws only on its own input contract — a missing `required` input
7390
+ * ({@link RequiredFieldNotProvidedError}) or a value that doesn't fit its
7391
+ * declared kind. It does NOT evaluate the definition's `start.filter`: that
7392
+ * is a read-side visibility rule (see `definitionsForDocument`), so a
7393
+ * caller who supplies everything needed starts, full stop.
7394
+ *
7395
+ * Pins the snapshot at start-time, seeds the `context` bag, and enters
7396
+ * the initial stage — fields resolve and every in-scope activity is
7397
+ * born active. Then cascades until stable, so the initial stage's
7398
+ * `when: 'true'` triggers have fired by the time this returns. Starting
7399
+ * always changes state (`changed: true`) — `cascaded` reports how far
7400
+ * the new instance auto-advanced.
7169
7401
  */
7170
7402
  startInstance: (
7171
7403
  rawArgs: Clocked<Telemetered<StartInstanceArgs & EngineScopeArgs>>,
7172
7404
  ) => Promise<OperationResult>;
7173
7405
  /**
7174
- * Fire an action against an activity. If the activity is pending, it is
7175
- * auto-invoked first (pending active) so callers don't have to know
7176
- * the lifecycle. Cascades auto-transitions and propagates to ancestors
7177
- * after the action commits.
7406
+ * Fire an action against an active activity. Cascades and propagates to
7407
+ * ancestors after the action commits. A cascade-fired (`when`) action is
7408
+ * rejected — the cascade is its only firing path.
7178
7409
  *
7179
7410
  * This is the universal "something happened" call. Editors fire it.
7180
7411
  * Runtimes fire it in response to webhooks, effect completions, and
@@ -7202,11 +7433,11 @@ export declare const workflow: {
7202
7433
  rawArgs: Clocked<Telemetered<EditFieldArgs & EngineScopeArgs>>,
7203
7434
  ) => Promise<OperationResult>;
7204
7435
  /**
7205
- * Report a queued effect's outcome. Drains it from `pendingEffects`,
7206
- * appends an `effectHistory` entry, and (if `outputs` are supplied
7207
- * and the effect succeeded) upserts those values into
7208
- * `effectsContext` by keyso downstream effect bindings can
7209
- * reference them. Any `ops` the handler returned (`field.*`) are
7436
+ * Report a queued effect's outcome. Drains it from `pendingEffects` and
7437
+ * appends an `effectHistory` entry whose `outputs` (when supplied on a
7438
+ * successful run) are what downstream effect bindings and conditions
7439
+ * read as `$effects['<name>'].<output>`the start-only `context` bag
7440
+ * is never touched. Any `ops` the handler returned (`field.*`) are
7210
7441
  * validated and applied to the instance in the same commit, through the
7211
7442
  * same op applier an action's field ops use. Cascades after. A completion
7212
7443
  * that applies always changes state (the effect drains + history is
@@ -7222,17 +7453,16 @@ export declare const workflow: {
7222
7453
  rawArgs: Clocked<Telemetered<CompleteEffectArgs & EngineScopeArgs>>,
7223
7454
  ) => Promise<OperationResult>;
7224
7455
  /**
7225
- * Re-evaluate auto-transitions and resolve due waits until stable.
7456
+ * Run the cascade until stable triggered actions fire, transitions move.
7226
7457
  *
7227
7458
  * Used by the runtime after any event that might affect the workflow
7228
- * but isn't itself an activity action: a subject doc was patched, a sibling
7229
- * workflow completed, the clock crossed a `completeWhen` deadline, etc.
7459
+ * but isn't itself an action fire: a subject doc was patched, a sibling
7460
+ * workflow completed, the clock crossed a deadline a `when` reads, etc.
7230
7461
  * The runtime doesn't need to know what changed — it just nudges
7231
7462
  * affected instances and the engine re-evaluates. `changed` reports
7232
7463
  * whether the nudge wrote anything: a fired transition, but also a
7233
- * persisted activity-gate flip (`completeWhen`/`failWhen`) that didn't
7234
- * unlock a transition yet — so it's derived from the instance's `_rev`,
7235
- * not from `cascaded` alone.
7464
+ * hop that fired triggered actions without unlocking a transition yet —
7465
+ * so it's derived from the instance's `_rev`, not from `cascaded` alone.
7236
7466
  */
7237
7467
  tick: (
7238
7468
  rawArgs: Clocked<Telemetered<OperationArgs & EngineScopeArgs>>,
@@ -7398,9 +7628,13 @@ export declare const workflow: {
7398
7628
  * The startable half of {@link workflow.instancesForDocument}: every
7399
7629
  * deployed definition that APPLIES to `document` — what a start picker for
7400
7630
  * it should offer. Loads the latest deployed version of each definition
7401
- * visible to the engine's tag and filters it through the pure derivation
7631
+ * visible to the engine's tag and filters it through the derivation
7402
7632
  * ({@link applicableDefinitions}): startable ∧ a required subject entry
7403
- * accepts the doc's `_type` ∧ `applicableWhen` passes.
7633
+ * accepts the doc's `_type` ∧ `start.filter` passes — evaluated in the
7634
+ * start-filter context with `$tag`/`$definition`/`$now` bound and the
7635
+ * tag's instance slice (completed included) backing dataset reads. A picker holds no
7636
+ * `initialFields`, so `$fields` stays unbound here and a filter reading it
7637
+ * fails closed (the definition is not surfaced).
7404
7638
  *
7405
7639
  * Takes the LOADED candidate document, not a ref — applicability evaluates
7406
7640
  * its content, under whatever perspective the caller read it with. Surfaces
@@ -7408,7 +7642,7 @@ export declare const workflow: {
7408
7642
  * auto-picking is consumer policy. Advisory like every engine-side check.
7409
7643
  */
7410
7644
  definitionsForDocument: (
7411
- rawArgs: DefinitionsForDocumentArgs & EngineScopeArgs,
7645
+ rawArgs: Clocked<DefinitionsForDocumentArgs & EngineScopeArgs>,
7412
7646
  ) => Promise<DeployedDefinition[]>;
7413
7647
  /**
7414
7648
  * Permission helpers — Sanity ACL grants evaluated against documents
@@ -7858,7 +8092,7 @@ declare const WorkflowConfigSchema: v.ObjectSchema<
7858
8092
  description?: string | undefined;
7859
8093
  groups?: Group[] | undefined;
7860
8094
  lifecycle?: WorkflowLifecycle | undefined;
7861
- applicableWhen?: string | undefined;
8095
+ start?: StartBlock | undefined;
7862
8096
  initialStage: string;
7863
8097
  fields?: FieldEntry[] | undefined;
7864
8098
  stages: Stage[];
@@ -7876,7 +8110,7 @@ declare const WorkflowConfigSchema: v.ObjectSchema<
7876
8110
  description?: string | undefined;
7877
8111
  groups?: Group[] | undefined;
7878
8112
  lifecycle?: WorkflowLifecycle | undefined;
7879
- applicableWhen?: string | undefined;
8113
+ start?: StartBlock | undefined;
7880
8114
  initialStage: string;
7881
8115
  fields?: FieldEntry[] | undefined;
7882
8116
  stages: Stage[];
@@ -7942,7 +8176,7 @@ declare const WorkflowConfigSchema: v.ObjectSchema<
7942
8176
  description?: string | undefined;
7943
8177
  groups?: Group[] | undefined;
7944
8178
  lifecycle?: WorkflowLifecycle | undefined;
7945
- applicableWhen?: string | undefined;
8179
+ start?: StartBlock | undefined;
7946
8180
  initialStage: string;
7947
8181
  fields?: FieldEntry[] | undefined;
7948
8182
  stages: Stage[];
@@ -8002,7 +8236,7 @@ declare const WorkflowConfigSchema: v.ObjectSchema<
8002
8236
  description?: string | undefined;
8003
8237
  groups?: Group[] | undefined;
8004
8238
  lifecycle?: WorkflowLifecycle | undefined;
8005
- applicableWhen?: string | undefined;
8239
+ start?: StartBlock | undefined;
8006
8240
  initialStage: string;
8007
8241
  fields?: FieldEntry[] | undefined;
8008
8242
  stages: Stage[];
@@ -8073,9 +8307,9 @@ export declare interface WorkflowDefinitionDeployedData {
8073
8307
  * scopes, sorted. */
8074
8308
  fieldKinds: FieldKind[];
8075
8309
  guardCount: number;
8076
- /** Effects declared across activities, actions, and transitions. */
8310
+ /** Effects declared across the definition's actions. */
8077
8311
  effectCount: number;
8078
- /** Activities carrying a `subworkflows` block. */
8312
+ /** Actions carrying a `spawn` block. */
8079
8313
  subworkflowCount: number;
8080
8314
  lifecycle: WorkflowLifecycle;
8081
8315
  }
@@ -8114,7 +8348,7 @@ export declare type WorkflowDefinitionInput<T> = string extends keyof T
8114
8348
  * mints the next version.
8115
8349
  */
8116
8350
  declare const WorkflowDefinitionSchema: v.GenericSchema<
8117
- WorkflowFields<FieldEntry, Stage>
8351
+ WorkflowFields<FieldEntry, Stage, StartBlock>
8118
8352
  >;
8119
8353
 
8120
8354
  export declare type WorkflowDeployment = WorkflowConfig["deployments"][number];
@@ -8175,6 +8409,7 @@ export declare type WorkflowErrorKind =
8175
8409
  | "partial-guard-deploy"
8176
8410
  | "concurrent-fire-action"
8177
8411
  | "concurrent-edit-field"
8412
+ | "concurrent-complete-effect"
8178
8413
  | "cascade-limit"
8179
8414
  | "field-value-shape"
8180
8415
  | "model-version-ahead"
@@ -8235,14 +8470,14 @@ export declare interface WorkflowFieldEditedData extends InstanceScopedEventData
8235
8470
  mode: EditMode;
8236
8471
  }
8237
8472
 
8238
- /** Type-mirror of {@link workflowFields}, parameterised over field/stage. */
8239
- declare type WorkflowFields<TField, TStage> = {
8473
+ /** Type-mirror of {@link workflowFields}, parameterised over field/stage/start. */
8474
+ declare type WorkflowFields<TField, TStage, TStart> = {
8240
8475
  name: string;
8241
8476
  title: string;
8242
8477
  description?: string | undefined;
8243
8478
  groups?: Group[] | undefined;
8244
8479
  lifecycle?: WorkflowLifecycle | undefined;
8245
- applicableWhen?: string | undefined;
8480
+ start?: TStart | undefined;
8246
8481
  initialStage: string;
8247
8482
  fields?: TField[] | undefined;
8248
8483
  stages: TStage[];
@@ -8307,10 +8542,11 @@ export declare interface WorkflowInstance extends SanityDocument {
8307
8542
  */
8308
8543
  fields: ResolvedFieldEntry[];
8309
8544
  /**
8310
- * Stable named params the runtime hands to effect handlers via binding
8311
- * resolution. Set at `startInstance`. **Not read by transition filters.**
8545
+ * The start seed: named values set once at `startInstance` (or by a
8546
+ * parent's `spawn.context`) and never mutated after. Conditions and
8547
+ * effect bindings read them as `$context.<name>`.
8312
8548
  */
8313
- effectsContext: EffectsContextEntry[];
8549
+ context: ContextEntry[];
8314
8550
  /**
8315
8551
  * Chain of ancestor workflow instances, root-first. Each entry is a
8316
8552
  * GDR pointing at a {@link WORKFLOW_INSTANCE_TYPE} document in the