@sanity/workflow-engine 0.13.0 → 0.14.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.cts CHANGED
@@ -13,17 +13,33 @@ export declare function abortReason(
13
13
 
14
14
  export declare type Action = ActionFields<Op>;
15
15
 
16
- export declare class ActionDisabledError extends Error {
17
- readonly reason: DisabledReason;
16
+ /**
17
+ * Thrown by `fireAction` when the requested action's verdict is
18
+ * `allowed: false` for any reason other than a guard denial (that one is
19
+ * {@link MutationGuardDeniedError} across all verbs). Carries the structured
20
+ * verdict so UIs render the same reason they would have shown on the
21
+ * disabled control, instead of parsing a string.
22
+ */
23
+ export declare class ActionDisabledError extends WorkflowError<"action-disabled"> {
24
+ readonly reason: ActionDisabledReason;
18
25
  readonly activity: ActivityName;
19
26
  readonly action: ActionName;
20
27
  constructor(args: {
21
28
  activity: ActivityName;
22
29
  action: ActionName;
23
- reason: DisabledReason;
30
+ reason: ActionDisabledReason;
24
31
  });
25
32
  }
26
33
 
34
+ /** The verdicts {@link ActionDisabledError} can carry — every {@link DisabledReason}
35
+ * except `mutation-guard-denied`, which escalates to {@link MutationGuardDeniedError}. */
36
+ export declare type ActionDisabledReason = Exclude<
37
+ DisabledReason,
38
+ {
39
+ kind: "mutation-guard-denied";
40
+ }
41
+ >;
42
+
27
43
  export declare interface ActionEvaluation {
28
44
  action: Action;
29
45
  allowed: boolean;
@@ -89,7 +105,7 @@ declare const ActionParamSchema: v.StrictObjectSchema<
89
105
  * declared `params[]` — missing required fields or wrong primitive
90
106
  * type. The action does not commit; the engine has not mutated state.
91
107
  */
92
- export declare class ActionParamsInvalidError extends Error {
108
+ export declare class ActionParamsInvalidError extends WorkflowError<"action-params-invalid"> {
93
109
  readonly action: string;
94
110
  readonly activity: ActivityName;
95
111
  readonly issues: {
@@ -215,7 +231,7 @@ export declare interface ActivityEvaluation {
215
231
  /**
216
232
  * The activity's effective {@link ActivityKind} — the explicit {@link Activity.kind}, or
217
233
  * the shape-derived default when omitted. Advisory: a label so a consumer can
218
- * render each activity as what it is (decision / wait / effect / off-system).
234
+ * render each activity as what it is (`user` / `service` / `script` / `manual` / `receive`).
219
235
  */
220
236
  kind: ActivityKind;
221
237
  /** Whether this activity is the current actor's responsibility right now. */
@@ -259,8 +275,16 @@ export declare type ActivityName = string;
259
275
 
260
276
  export declare type ActivityStatus = (typeof ACTIVITY_STATUSES)[number];
261
277
 
278
+ /**
279
+ * Who is acting, as asserted by the caller — advisory provenance, not an
280
+ * authenticated principal. The engine resolves it from the client's token by
281
+ * default (`/users/me`), but every acting verb accepts an `access.actor`
282
+ * override and nothing verifies the asserted id against the token performing
283
+ * the writes. Only the lake's own token identity is authenticated; hard
284
+ * enforcement lives there.
285
+ */
262
286
  export declare interface Actor {
263
- kind: "user" | "ai" | "system";
287
+ kind: ActorKind;
264
288
  id: string;
265
289
  /**
266
290
  * Free-form role names — typically a copy of Sanity's `user.roles[].name`
@@ -279,6 +303,10 @@ export declare interface Actor {
279
303
  onBehalfOf?: string;
280
304
  }
281
305
 
306
+ export declare const ACTOR_KINDS: readonly ["person", "agent", "system"];
307
+
308
+ export declare type ActorKind = (typeof ACTOR_KINDS)[number];
309
+
282
310
  /**
283
311
  * One member of an `assignees`-kind entry's value — and the value of the
284
312
  * singular `assignee` kind. The WHO-FOR spec the inbox reverse-query and the
@@ -335,7 +363,7 @@ export declare type AuthoringEditable = v.InferOutput<
335
363
  /**
336
364
  * Authoring editability adds the `role[]` convenience: a non-empty role list
337
365
  * desugars to the same `count($actor.roles[@ in [...]]) > 0` membership
338
- * predicate `action.roles` produces. `true` opens the slot to anyone in its
366
+ * predicate `action.roles` produces. `true` opens the field to anyone in its
339
367
  * window; a bare string is a raw predicate.
340
368
  */
341
369
  declare const AuthoringEditableSchema: v.UnionSchema<
@@ -387,6 +415,292 @@ declare const AuthoringFieldRefSchema: v.StrictObjectSchema<
387
415
  undefined
388
416
  >;
389
417
 
418
+ export declare type AuthoringGuard = v.InferOutput<typeof AuthoringGuardSchema>;
419
+
420
+ declare const AuthoringGuardSchema: v.StrictObjectSchema<
421
+ {
422
+ name: v.SchemaWithPipe<
423
+ readonly [
424
+ v.StringSchema<undefined>,
425
+ v.MinLengthAction<string, 1, "must be a non-empty string">,
426
+ ]
427
+ >;
428
+ title: v.OptionalSchema<v.StringSchema<undefined>, undefined>;
429
+ description: v.OptionalSchema<v.StringSchema<undefined>, undefined>;
430
+ match: v.StrictObjectSchema<
431
+ {
432
+ /** Subject `_type`(s); empty matches any type. */
433
+ types: v.OptionalSchema<
434
+ v.ArraySchema<
435
+ v.SchemaWithPipe<
436
+ readonly [
437
+ v.StringSchema<undefined>,
438
+ v.MinLengthAction<string, 1, "must be a non-empty string">,
439
+ ]
440
+ >,
441
+ undefined
442
+ >,
443
+ undefined
444
+ >;
445
+ /** Target docs as field reads (or the instance itself), resolved at deploy to bare ids + the resource. */
446
+ idRefs: v.OptionalSchema<
447
+ v.ArraySchema<
448
+ v.VariantSchema<
449
+ "type",
450
+ [
451
+ v.StrictObjectSchema<
452
+ {
453
+ readonly type: v.LiteralSchema<"self", undefined>;
454
+ },
455
+ undefined
456
+ >,
457
+ v.StrictObjectSchema<
458
+ {
459
+ readonly type: v.LiteralSchema<"now", undefined>;
460
+ },
461
+ undefined
462
+ >,
463
+ v.StrictObjectSchema<
464
+ {
465
+ readonly type: v.LiteralSchema<"fieldRead", undefined>;
466
+ readonly field: v.SchemaWithPipe<
467
+ readonly [
468
+ v.StringSchema<undefined>,
469
+ v.RegexAction<string, string>,
470
+ ]
471
+ >;
472
+ readonly path: v.OptionalSchema<
473
+ v.SchemaWithPipe<
474
+ readonly [
475
+ v.SchemaWithPipe<
476
+ readonly [
477
+ v.StringSchema<undefined>,
478
+ v.MinLengthAction<
479
+ string,
480
+ 1,
481
+ "must be a non-empty string"
482
+ >,
483
+ ]
484
+ >,
485
+ v.CheckAction<
486
+ string,
487
+ "a guard read path cannot contain a line break"
488
+ >,
489
+ ]
490
+ >,
491
+ undefined
492
+ >;
493
+ },
494
+ undefined
495
+ >,
496
+ v.StrictObjectSchema<
497
+ {
498
+ readonly type: v.LiteralSchema<"effectsRead", undefined>;
499
+ readonly effect: v.SchemaWithPipe<
500
+ readonly [
501
+ v.SchemaWithPipe<
502
+ readonly [
503
+ v.StringSchema<undefined>,
504
+ v.MinLengthAction<
505
+ string,
506
+ 1,
507
+ "must be a non-empty string"
508
+ >,
509
+ ]
510
+ >,
511
+ v.CheckAction<
512
+ string,
513
+ "an effect name cannot contain `'`"
514
+ >,
515
+ ]
516
+ >;
517
+ readonly path: v.OptionalSchema<
518
+ v.SchemaWithPipe<
519
+ readonly [
520
+ v.SchemaWithPipe<
521
+ readonly [
522
+ v.StringSchema<undefined>,
523
+ v.MinLengthAction<
524
+ string,
525
+ 1,
526
+ "must be a non-empty string"
527
+ >,
528
+ ]
529
+ >,
530
+ v.CheckAction<
531
+ string,
532
+ "a guard read path cannot contain a line break"
533
+ >,
534
+ ]
535
+ >,
536
+ undefined
537
+ >;
538
+ },
539
+ undefined
540
+ >,
541
+ ],
542
+ undefined
543
+ >,
544
+ undefined
545
+ >,
546
+ undefined
547
+ >;
548
+ /** Glob id patterns (bare, resource-local). */
549
+ idPatterns: v.OptionalSchema<
550
+ v.ArraySchema<
551
+ v.SchemaWithPipe<
552
+ readonly [
553
+ v.StringSchema<undefined>,
554
+ v.MinLengthAction<string, 1, "must be a non-empty string">,
555
+ ]
556
+ >,
557
+ undefined
558
+ >,
559
+ undefined
560
+ >;
561
+ actions: v.SchemaWithPipe<
562
+ readonly [
563
+ v.ArraySchema<
564
+ v.PicklistSchema<
565
+ readonly ["create", "update", "delete", "publish", "unpublish"],
566
+ `Invalid option: expected one of ${string}`
567
+ >,
568
+ undefined
569
+ >,
570
+ v.MinLengthAction<
571
+ ("create" | "update" | "delete" | "publish" | "unpublish")[],
572
+ 1,
573
+ "a guard must match at least one action"
574
+ >,
575
+ ]
576
+ >;
577
+ },
578
+ undefined
579
+ >;
580
+ /**
581
+ * Lake GROQ predicate — a distinct eval context reading
582
+ * `document.before`/`document.after`, `mutation`, `guard`, and
583
+ * `identity()`. Bare ids/fields only. Omitted or empty means
584
+ * UNCONDITIONAL DENY.
585
+ */
586
+ predicate: v.OptionalSchema<v.StringSchema<undefined>, undefined>;
587
+ /**
588
+ * Projected workflow fields the predicate reads as `guard.metadata.*` —
589
+ * the only bridge from the lake eval context (which cannot see `$fields`)
590
+ * to workflow fields. Each value is a deploy-time read — a typed
591
+ * {@link GuardRead} when authoring, the printed string spelling once
592
+ * stored — resolved into a bare value at deploy and re-synced by the
593
+ * post-field-op guard refresh.
594
+ */
595
+ metadata: v.OptionalSchema<
596
+ v.RecordSchema<
597
+ v.SchemaWithPipe<
598
+ readonly [
599
+ v.StringSchema<undefined>,
600
+ v.MinLengthAction<string, 1, "must be a non-empty string">,
601
+ ]
602
+ >,
603
+ v.VariantSchema<
604
+ "type",
605
+ [
606
+ v.StrictObjectSchema<
607
+ {
608
+ readonly type: v.LiteralSchema<"self", undefined>;
609
+ },
610
+ undefined
611
+ >,
612
+ v.StrictObjectSchema<
613
+ {
614
+ readonly type: v.LiteralSchema<"now", undefined>;
615
+ },
616
+ undefined
617
+ >,
618
+ v.StrictObjectSchema<
619
+ {
620
+ readonly type: v.LiteralSchema<"fieldRead", undefined>;
621
+ readonly field: v.SchemaWithPipe<
622
+ readonly [
623
+ v.StringSchema<undefined>,
624
+ v.RegexAction<string, string>,
625
+ ]
626
+ >;
627
+ readonly path: v.OptionalSchema<
628
+ v.SchemaWithPipe<
629
+ readonly [
630
+ v.SchemaWithPipe<
631
+ readonly [
632
+ v.StringSchema<undefined>,
633
+ v.MinLengthAction<
634
+ string,
635
+ 1,
636
+ "must be a non-empty string"
637
+ >,
638
+ ]
639
+ >,
640
+ v.CheckAction<
641
+ string,
642
+ "a guard read path cannot contain a line break"
643
+ >,
644
+ ]
645
+ >,
646
+ undefined
647
+ >;
648
+ },
649
+ undefined
650
+ >,
651
+ v.StrictObjectSchema<
652
+ {
653
+ readonly type: v.LiteralSchema<"effectsRead", undefined>;
654
+ readonly effect: v.SchemaWithPipe<
655
+ readonly [
656
+ v.SchemaWithPipe<
657
+ readonly [
658
+ v.StringSchema<undefined>,
659
+ v.MinLengthAction<
660
+ string,
661
+ 1,
662
+ "must be a non-empty string"
663
+ >,
664
+ ]
665
+ >,
666
+ v.CheckAction<string, "an effect name cannot contain `'`">,
667
+ ]
668
+ >;
669
+ readonly path: v.OptionalSchema<
670
+ v.SchemaWithPipe<
671
+ readonly [
672
+ v.SchemaWithPipe<
673
+ readonly [
674
+ v.StringSchema<undefined>,
675
+ v.MinLengthAction<
676
+ string,
677
+ 1,
678
+ "must be a non-empty string"
679
+ >,
680
+ ]
681
+ >,
682
+ v.CheckAction<
683
+ string,
684
+ "a guard read path cannot contain a line break"
685
+ >,
686
+ ]
687
+ >,
688
+ undefined
689
+ >;
690
+ },
691
+ undefined
692
+ >,
693
+ ],
694
+ undefined
695
+ >,
696
+ undefined
697
+ >,
698
+ undefined
699
+ >;
700
+ },
701
+ undefined
702
+ >;
703
+
390
704
  export declare type AuthoringManualTarget = v.InferOutput<
391
705
  typeof AuthoringManualTargetSchema
392
706
  >;
@@ -546,7 +860,12 @@ declare const AuthoringOpSchema: v.VariantSchema<
546
860
  },
547
861
  undefined
548
862
  >;
549
- readonly where: v.GenericSchema<OpPredicateInternal>;
863
+ readonly where: v.SchemaWithPipe<
864
+ readonly [
865
+ v.StringSchema<undefined>,
866
+ v.MinLengthAction<string, 1, "must be a non-empty string">,
867
+ ]
868
+ >;
550
869
  readonly value: v.GenericSchema<ValueExprInternal>;
551
870
  },
552
871
  undefined
@@ -572,7 +891,12 @@ declare const AuthoringOpSchema: v.VariantSchema<
572
891
  },
573
892
  undefined
574
893
  >;
575
- readonly where: v.GenericSchema<OpPredicateInternal>;
894
+ readonly where: v.SchemaWithPipe<
895
+ readonly [
896
+ v.StringSchema<undefined>,
897
+ v.MinLengthAction<string, 1, "must be a non-empty string">,
898
+ ]
899
+ >;
576
900
  },
577
901
  undefined
578
902
  >,
@@ -660,7 +984,10 @@ declare const AuthoringOpSchema: v.VariantSchema<
660
984
  * - `status` → a `status.set` op on the firing activity, appended **after**
661
985
  * the authored ops (deliberately never implied: a forgotten explicit
662
986
  * `status` is a visible stall, an implied default silently completes
663
- * claim-like actions).
987
+ * claim-like actions). Status is the health axis: a decision action
988
+ * (decline, send back) resolves `done` and writes the decision into a
989
+ * field the transition filter reads — `failed` is for work that
990
+ * genuinely could not complete.
664
991
  */
665
992
  declare type AuthoringRawAction = ActionFields<AuthoringOp> & {
666
993
  roles?: string[] | undefined;
@@ -673,6 +1000,7 @@ export declare type AuthoringStage = StageFields<
673
1000
  AuthoringFieldEntry,
674
1001
  AuthoringActivity,
675
1002
  AuthoringTransition,
1003
+ AuthoringGuard,
676
1004
  AuthoringEditable
677
1005
  >;
678
1006
 
@@ -788,7 +1116,12 @@ declare const AuthoringTransitionOpSchema: v.VariantSchema<
788
1116
  },
789
1117
  undefined
790
1118
  >;
791
- readonly where: v.GenericSchema<OpPredicateInternal>;
1119
+ readonly where: v.SchemaWithPipe<
1120
+ readonly [
1121
+ v.StringSchema<undefined>,
1122
+ v.MinLengthAction<string, 1, "must be a non-empty string">,
1123
+ ]
1124
+ >;
792
1125
  readonly value: v.GenericSchema<ValueExprInternal>;
793
1126
  },
794
1127
  undefined
@@ -814,7 +1147,12 @@ declare const AuthoringTransitionOpSchema: v.VariantSchema<
814
1147
  },
815
1148
  undefined
816
1149
  >;
817
- readonly where: v.GenericSchema<OpPredicateInternal>;
1150
+ readonly where: v.SchemaWithPipe<
1151
+ readonly [
1152
+ v.StringSchema<undefined>,
1153
+ v.MinLengthAction<string, 1, "must be a non-empty string">,
1154
+ ]
1155
+ >;
818
1156
  },
819
1157
  undefined
820
1158
  >,
@@ -903,14 +1241,6 @@ export declare interface AvailableActionsResult {
903
1241
  actions: AvailableAction[];
904
1242
  }
905
1243
 
906
- declare type Bound<
907
- Args extends {
908
- client: WorkflowClient;
909
- tag: string;
910
- workflowResource: WorkflowResource;
911
- },
912
- > = Omit<Args, "client" | "tag" | "workflowResource">;
913
-
914
1244
  /**
915
1245
  * Build a snapshot from a set of loaded docs. Pure transform.
916
1246
  *
@@ -940,12 +1270,17 @@ export declare function buildSnapshot(args: {
940
1270
  * The cascade aborts at the limit rather than the engine hanging; the
941
1271
  * instance is left at whatever stage the last completed pass reached.
942
1272
  */
943
- export declare class CascadeLimitError extends Error {
1273
+ export declare class CascadeLimitError extends WorkflowError<"cascade-limit"> {
944
1274
  readonly instanceId: string;
945
1275
  readonly limit: number;
946
1276
  constructor(args: { instanceId: string; limit: number });
947
1277
  }
948
1278
 
1279
+ export declare interface ChildrenArgs extends InstanceRefArgs {
1280
+ /** Restrict to children spawned by this activity on the parent. */
1281
+ activity?: string;
1282
+ }
1283
+
949
1284
  /**
950
1285
  * The action half of the mirrored claim pair. `field` references an
951
1286
  * author-declared actor-valued entry (the pair's other half), resolved
@@ -969,7 +1304,7 @@ declare type ClaimAction = {
969
1304
  /**
970
1305
  * Authoring fields accept the raw entries plus the `claim` sugar type — the
971
1306
  * field half of the mirrored claim pair. Expansion: an `actor` working-
972
- * memory slot (no `initialValue`; the claim action's op fills it), strictly
1307
+ * memory field (no `initialValue`; the claim action's op fills it), strictly
973
1308
  * within this entry.
974
1309
  */
975
1310
  declare type ClaimField = {
@@ -1016,6 +1351,16 @@ declare type Clocked<T> = T & {
1016
1351
  clock?: Clock;
1017
1352
  };
1018
1353
 
1354
+ /**
1355
+ * A compiled lake read — what the engine's query builders return and what a
1356
+ * reactive adapter's live-query store subscribes with, so the stateless and
1357
+ * reactive paths run the same GROQ.
1358
+ */
1359
+ export declare interface CompiledQuery {
1360
+ query: string;
1361
+ params: Record<string, string>;
1362
+ }
1363
+
1019
1364
  /** Assemble a persisted guard doc from resolved pieces. */
1020
1365
  export declare function compileGuard(args: CompileGuardArgs): MutationGuardDoc;
1021
1366
 
@@ -1070,7 +1415,7 @@ export declare function computeDiffEntries({
1070
1415
  * lost the optimistic-locking race on every attempt. Same contract — re-read
1071
1416
  * and retry, or investigate a write storm; nothing committed on the final try.
1072
1417
  */
1073
- export declare class ConcurrentEditFieldError extends Error {
1418
+ export declare class ConcurrentEditFieldError extends WorkflowError<"concurrent-edit-field"> {
1074
1419
  readonly instanceId: string;
1075
1420
  readonly target: {
1076
1421
  scope: FieldScope;
@@ -1097,7 +1442,7 @@ export declare class ConcurrentEditFieldError extends Error {
1097
1442
  * whether to retry later or report a write storm; nothing was committed
1098
1443
  * on the final attempt.
1099
1444
  */
1100
- export declare class ConcurrentFireActionError extends Error {
1445
+ export declare class ConcurrentFireActionError extends WorkflowError<"concurrent-fire-action"> {
1101
1446
  readonly instanceId: string;
1102
1447
  readonly activity: ActivityName;
1103
1448
  readonly action: string;
@@ -1110,8 +1455,69 @@ export declare class ConcurrentFireActionError extends Error {
1110
1455
  });
1111
1456
  }
1112
1457
 
1458
+ /**
1459
+ * A raw GROQ string evaluated over the rendered scope: the engine-bound
1460
+ * variables inventoried in {@link CONDITION_VARS} (each annotated with the
1461
+ * context that binds it) plus the author's nullary `predicates` as `$<name>`
1462
+ * booleans. Evaluation runs against the instance's in-memory snapshot —
1463
+ * never a `_type` scan over the lake (rejected at deploy).
1464
+ *
1465
+ * There is no `{ref, args}` wrapper: parameterized reuse is a define-time
1466
+ * TypeScript function producing a condition string (see the {@link groq} tag).
1467
+ */
1113
1468
  export declare type Condition = string;
1114
1469
 
1470
+ /**
1471
+ * Every variable the engine binds for conditions, in one place. The
1472
+ * deploy-time shadow check ({@link RESERVED_CONDITION_VARS}) and the docs on
1473
+ * {@link Condition} derive from this list — extend it here when the engine
1474
+ * grows a binding, never in a comment elsewhere.
1475
+ */
1476
+ export declare const CONDITION_VARS: readonly ConditionVar[];
1477
+
1478
+ export declare interface ConditionVar {
1479
+ /** The GROQ param name, read as `$<name>`. */
1480
+ name: string;
1481
+ binding: ConditionVarBinding;
1482
+ description: string;
1483
+ }
1484
+
1485
+ /**
1486
+ * The condition-variable inventory — the single source of truth for every
1487
+ * `$var` the engine binds when it evaluates a {@link Condition}.
1488
+ *
1489
+ * Three evaluation contexts read a definition's GROQ:
1490
+ *
1491
+ * 1. **Rendered condition scope** — every condition site in a definition
1492
+ * (transition filters, `completeWhen`/`failWhen`, action filters, effect
1493
+ * bindings, `subworkflows` reads, where-op `where`s, editability
1494
+ * predicates, author predicates). {@link CONDITION_VARS} is its inventory;
1495
+ * each entry's `binding` says when the var actually holds a value. The
1496
+ * where-op context is the one closed subset — its bound set is statically
1497
+ * fixed and deploy-enforced (see the op-where scope's param-name list in
1498
+ * the op applier).
1499
+ * 2. **Filter evaluation without a caller** — the engine's cascade evaluates
1500
+ * transition filters and `completeWhen`/`failWhen` with no caller, so only
1501
+ * the `'always'`-bound subset carries values there ({@link FILTER_SCOPE_VARS}).
1502
+ * Caller-bound vars evaluate to `undefined` and fail closed.
1503
+ * 3. **Guard predicates** — NOT conditions. A lake mutation guard's
1504
+ * `predicate` is groq-js **delta-mode** GROQ over a document mutation:
1505
+ * `before()`/`after()`/`identity()` are dialect natives, and the wire
1506
+ * format binds the identifiers in {@link GUARD_PREDICATE_VARS}. None of
1507
+ * the condition vars exist there.
1508
+ */
1509
+ /**
1510
+ * When a condition var holds a value:
1511
+ *
1512
+ * - `'always'` — bound in every condition evaluation, derived from the
1513
+ * instance and its snapshot.
1514
+ * - `'caller'` — rides the acting caller; without one the var is `undefined`
1515
+ * (conditions referencing it fail closed). Author predicates may not read
1516
+ * these — they pre-evaluate once per instance, caller-free.
1517
+ * - `'spawn'` — bound only at `subworkflows` sites.
1518
+ */
1519
+ export declare type ConditionVarBinding = "always" | "caller" | "spawn";
1520
+
1115
1521
  /**
1116
1522
  * The Content Release a watched doc resolves under, or `undefined` for a raw
1117
1523
  * read — how a reactive adapter turns the watch-set's perspective into the
@@ -1135,39 +1541,52 @@ export declare function contentReleaseName(args: {
1135
1541
  perspective: WorkflowPerspective | undefined;
1136
1542
  }): string | undefined;
1137
1543
 
1544
+ /**
1545
+ * A caller broke a public-API contract — a call the engine rejects
1546
+ * before touching the lake: an invalid `tag`, a `workflow.query` GROQ that
1547
+ * never binds `$tag`, a bare id where a GDR URI is required, an action,
1548
+ * activity, or field the definition never declared. Fix the call site;
1549
+ * retrying cannot succeed.
1550
+ */
1551
+ export declare class ContractViolationError extends WorkflowError<"contract-violation"> {
1552
+ constructor(message: string);
1553
+ }
1554
+
1138
1555
  /**
1139
1556
  * Construct an engine bound to a workflow resource + tag. The returned
1140
- * object exposes the same verbs as the `workflow.*` namespace, minus
1141
- * the boilerplate config arguments (client / tag / workflowResource)
1142
- * which are pinned at construction. The `tag` is required — see
1143
- * {@link validateTag} for the accepted shape.
1557
+ * object exposes the `workflow.*` verbs minus the {@link EngineScopeArgs}
1558
+ * scope (client / tag / workflowResource / resourceClients), which is
1559
+ * pinned at construction. The `tag` is required — see {@link validateTag}
1560
+ * for the accepted shape.
1561
+ *
1562
+ * Parity with the namespace is exact, with these deliberate exceptions:
1563
+ *
1564
+ * - Engine-only: {@link Engine.session} and
1565
+ * {@link Engine.subscriptionDocumentsForInstance} (need the pinned
1566
+ * binding), {@link Engine.drainEffects} and
1567
+ * {@link Engine.verifyDeployedDefinitions} (need the construction-time
1568
+ * `effectHandlers` / `missingHandler` / `loggerFactory`).
1569
+ * - Namespace-only: `workflow.permissions` — pure grant helpers that need
1570
+ * no engine scope.
1144
1571
  *
1145
- * Effect handlers + missingHandler are stored for future drain wiring
1146
- * (Step 10). They have no effect on `fireAction` / `tick` /
1147
- * `completeEffect` today — those still expect the runtime to dispatch
1148
- * effects and report back via `completeEffect`.
1572
+ * Effect handlers + missingHandler feed {@link Engine.drainEffects}
1573
+ * (dispatch of unclaimed pending effects) and
1574
+ * {@link Engine.verifyDeployedDefinitions} (the startup audit of
1575
+ * deployed effect names). They don't change `fireAction` / `tick` /
1576
+ * `completeEffect` — the runtime still decides when to drain and
1577
+ * reports outcomes via `completeEffect`.
1149
1578
  */
1150
1579
  export declare function createEngine(args: CreateEngineArgs): Engine;
1151
1580
 
1152
- export declare interface CreateEngineArgs {
1153
- client: WorkflowClient;
1154
- workflowResource: WorkflowResource;
1155
- /**
1156
- * Engine-scope environment partition (e.g. `"test"`, `"prod"`). Every
1157
- * definition/instance the engine writes is stamped with this tag and
1158
- * every read is scoped to it. Required and never defaulted — the engine
1159
- * enforces nothing, so the partition is the only thing keeping reads and
1160
- * writes off the wrong environment.
1161
- */
1162
- tag: string;
1163
- /**
1164
- * Optional routing for cross-resource reads. When the engine needs
1165
- * a doc whose GDR points at a resource other than its own, it calls
1166
- * the resolver; if the resolver returns a client, that one is used.
1167
- * Otherwise the engine's default `client` is used (best for
1168
- * single-resource setups — most demos).
1169
- */
1170
- resourceClients?: ResourceClientResolver;
1581
+ /**
1582
+ * The {@link EngineScopeArgs} scope pinned at construction, plus the
1583
+ * engine-only extras (`effectHandlers` / `missingHandler` / `loggerFactory`
1584
+ * feed `drainEffects` + `verifyDeployedDefinitions`). The `tag` partition is
1585
+ * required and never defaulted the engine enforces nothing, so the
1586
+ * partition is the only thing keeping reads and writes off the wrong
1587
+ * environment.
1588
+ */
1589
+ export declare interface CreateEngineArgs extends EngineScopeArgs {
1171
1590
  effectHandlers?: Record<string, EffectHandler>;
1172
1591
  missingHandler?: MissingHandlerPolicy;
1173
1592
  loggerFactory?: LoggerFactory;
@@ -1213,14 +1632,52 @@ export declare const DEFAULT_CONTENT_PERSPECTIVE = "drafts";
1213
1632
  */
1214
1633
  export declare const defaultLoggerFactory: LoggerFactory;
1215
1634
 
1216
- export declare interface DeleteDefinitionArgs {
1635
+ declare interface DefinitionGuardsQueryArgs {
1217
1636
  client: WorkflowClient;
1218
- /** Engine-scope environment partition — required. See {@link validateTag} + `tags.ts`. */
1219
- tag: string;
1220
- /** The Sanity resource the engine's own data lives in. */
1637
+ clientForGdr: (parsed: ParsedGdr) => WorkflowClient;
1221
1638
  workflowResource: WorkflowResource;
1222
- /** Cross-resource routing — see `StartInstanceArgs.resourceClients`. */
1223
- resourceClients?: ResourceClientResolver;
1639
+ definition: string;
1640
+ /** Every deployed version of {@link DefinitionGuardsQueryArgs.definition}. */
1641
+ definitions: WorkflowDefinition[];
1642
+ }
1643
+
1644
+ /** What blocks a `deleteDefinition`, so a consumer can render the remediation:
1645
+ * abort-in-place via `cascade`, or delete/redeploy the referrer first. */
1646
+ export declare type DefinitionInUseBlocker =
1647
+ | {
1648
+ reason: "non-terminal-instances";
1649
+ instanceIds: string[];
1650
+ }
1651
+ | {
1652
+ reason: "spawn-referrers";
1653
+ referrers: {
1654
+ definition: string;
1655
+ version: number;
1656
+ }[];
1657
+ };
1658
+
1659
+ /**
1660
+ * `deleteDefinition` refused because the definition is still in use — either
1661
+ * non-terminal instances are pinned to it (pass `cascade` to abort them in
1662
+ * place first) or a surviving deployed definition still spawn-references a
1663
+ * targeted version (delete or redeploy the referrer first). `blockedBy` says
1664
+ * which, with the blocking ids, so a consumer can render the remediation.
1665
+ */
1666
+ export declare class DefinitionInUseError extends WorkflowError<"definition-in-use"> {
1667
+ readonly definition: string;
1668
+ readonly blockedBy: DefinitionInUseBlocker;
1669
+ constructor(args: { definition: string; blockedBy: DefinitionInUseBlocker });
1670
+ }
1671
+
1672
+ /** No deployed workflow definition matches the requested name (and version,
1673
+ * when given) under this engine's tag. */
1674
+ export declare class DefinitionNotFoundError extends WorkflowError<"definition-not-found"> {
1675
+ readonly definition: string;
1676
+ readonly version?: number;
1677
+ constructor(args: { definition: string; version?: number });
1678
+ }
1679
+
1680
+ export declare interface DeleteDefinitionArgs {
1224
1681
  /** The definition's `name` — delete addresses the workflow, not a doc id. */
1225
1682
  definition: string;
1226
1683
  /** Delete only this deployed version. Default: every deployed version. */
@@ -1256,6 +1713,26 @@ export declare interface DeleteDefinitionResult {
1256
1713
  deletedGuardCount: number;
1257
1714
  }
1258
1715
 
1716
+ /**
1717
+ * Human label per denying guard — the authored `name` when present, else the
1718
+ * raw guard id. The one display convention for rendering a denial to a
1719
+ * person; the payload keeps the raw ids for operators locating the guard doc.
1720
+ */
1721
+ export declare function deniedGuardLabels(
1722
+ denied: readonly DeniedGuardRef[],
1723
+ ): string[];
1724
+
1725
+ /**
1726
+ * One denying guard, as carried by both the read-side verdict
1727
+ * (`mutation-guard-denied` in {@link DisabledReason}) and the thrown
1728
+ * {@link MutationGuardDeniedError} — one shape for the same denial, so a
1729
+ * consumer renders it once.
1730
+ */
1731
+ export declare interface DeniedGuardRef {
1732
+ guardId: string;
1733
+ name?: string;
1734
+ }
1735
+
1259
1736
  /**
1260
1737
  * Run every guard whose `match` applies and collect those that DENY. Empty
1261
1738
  * result ⇒ allowed (optimistically).
@@ -1271,22 +1748,13 @@ export declare function denyingGuards(args: {
1271
1748
 
1272
1749
  export declare interface DeployDefinitionResult {
1273
1750
  /** The definition's `name`. */
1274
- definition: string;
1751
+ name: string;
1275
1752
  /** The deploy-assigned version this deploy created or matched. */
1276
1753
  version: number;
1277
1754
  status: "created" | "unchanged";
1278
1755
  }
1279
1756
 
1280
1757
  export declare interface DeployDefinitionsArgs {
1281
- client: WorkflowClient;
1282
- /** Engine-scope environment partition — required. See {@link validateTag} + `tags.ts`. */
1283
- tag: string;
1284
- /**
1285
- * The Sanity resource the engine's own data lives in. Used to mint
1286
- * GDR URIs for every doc the engine writes (definitions, instances,
1287
- * ancestor refs). Mirrors `@sanity/client`'s `ClientConfigResource`.
1288
- */
1289
- workflowResource: WorkflowResource;
1290
1758
  /**
1291
1759
  * Resource-alias bindings for this deploy (alias name → physical resource).
1292
1760
  * Every `@<alias>:` reference in a definition is expanded to its bound
@@ -1321,7 +1789,7 @@ export declare type DeployedDefinition = WorkflowDefinition & {
1321
1789
  /**
1322
1790
  * Deploy every guard for a stage being entered (idempotent upsert), but only
1323
1791
  * while the instance is still committed to that stage. A deploy that lost the
1324
- * race to a newer transition would otherwise re-enforce a stage the instance
1792
+ * race to a newer transition would otherwise re-lock a stage the instance
1325
1793
  * already left — a stale lock the newer transition's retract can't see. A
1326
1794
  * vanished instance (`undefined`) likewise no-ops: `undefined !== stageName`.
1327
1795
  *
@@ -1462,13 +1930,23 @@ export declare function diffEntry({
1462
1930
  target: DeployTarget;
1463
1931
  }): DiffEntry;
1464
1932
 
1933
+ /**
1934
+ * Why an action is disabled for this actor right now — the read-side verdict.
1935
+ *
1936
+ * Verdict↔exception mapping (what `fireAction` throws when the verdict says
1937
+ * no): the `mutation-guard-denied` arm escalates to
1938
+ * {@link MutationGuardDeniedError} — the one guard-denial error, shared by
1939
+ * every verb; every other arm is thrown as {@link ActionDisabledError}
1940
+ * carrying the verdict as `reason`. The edit seam mirrors this: see
1941
+ * {@link EditDisabledReason} and {@link EditFieldDeniedError}.
1942
+ */
1465
1943
  export declare type DisabledReason =
1466
1944
  | {
1467
1945
  /**
1468
1946
  * The action's condition evaluated falsy for this actor — the ONE
1469
- * engine-side gate (advisory: hard enforcement is the lake ACL +
1470
- * guards). Sugar like `roles` desugared into this condition, so a
1471
- * role miss surfaces here too.
1947
+ * engine-side gate (advisory, like every engine check). Sugar like
1948
+ * `roles` desugared into this condition, so a role miss surfaces
1949
+ * here too.
1472
1950
  */
1473
1951
  kind: "filter-failed";
1474
1952
  filter: string;
@@ -1484,13 +1962,13 @@ export declare type DisabledReason =
1484
1962
  }
1485
1963
  | {
1486
1964
  /**
1487
- * A live lake mutation guard denies the instance write every action
1488
- * commit performs. Advisory pre-flight of the lake's own enforcement;
1489
- * carries the denying guard ids.
1965
+ * A deployed mutation guard denies the instance write every action
1966
+ * commit performs. Advisory pre-flight the engine's optimistic
1967
+ * evaluation; `denied` is the same {@link DeniedGuardRef} shape the
1968
+ * thrown {@link MutationGuardDeniedError} carries.
1490
1969
  */
1491
1970
  kind: "mutation-guard-denied";
1492
- guardIds: string[];
1493
- detail?: string;
1971
+ denied: DeniedGuardRef[];
1494
1972
  }
1495
1973
  | {
1496
1974
  kind: "instance-completed";
@@ -1509,19 +1987,6 @@ export declare type DisabledReason =
1509
1987
  unmetRequirements: string[];
1510
1988
  };
1511
1989
 
1512
- export declare interface DispatchResult {
1513
- /** The instance after the operation + all cascading auto-transitions. */
1514
- instance: WorkflowInstance;
1515
- /** Number of auto-transitions that fired during the cascade. */
1516
- cascaded: number;
1517
- /** Whether the originally-requested intent fired. */
1518
- fired: boolean;
1519
- /** Engine primitives (`workflow.op.field.*` / `status.set`) that ran
1520
- * during the action commit. Surfaced for caller-side assertions and
1521
- * audit. */
1522
- ranOps?: OpAppliedSummary[];
1523
- }
1524
-
1525
1990
  /**
1526
1991
  * Single combined map for callers that don't care which family the
1527
1992
  * key belongs to (e.g. an audit row showing any `_type`).
@@ -1567,6 +2032,13 @@ declare const DOCUMENT_VALUE_PERMISSIONS: readonly ["create", "read", "update"];
1567
2032
  export declare type DocumentValuePermission =
1568
2033
  (typeof DOCUMENT_VALUE_PERMISSIONS)[number];
1569
2034
 
2035
+ export declare interface DrainEffectsArgs extends InstanceRefArgs {
2036
+ /** Override the drainer's identity (e.g. impersonate a real user whose
2037
+ * grants the dispatch should respect). Defaults to a
2038
+ * `{ kind: "system", id: "engine.drainEffects" }` actor. */
2039
+ access?: WorkflowAccessOverride;
2040
+ }
2041
+
1570
2042
  export declare interface DrainEffectsResult {
1571
2043
  drained: PendingEffect[];
1572
2044
  failed: PendingEffect[];
@@ -1607,9 +2079,9 @@ export declare const DRIVER_KINDS: readonly [
1607
2079
  export declare type DriverKind = (typeof DRIVER_KINDS)[number];
1608
2080
 
1609
2081
  /**
1610
- * Classify the actor that drove an action for the audit-trail glyph: a human is
1611
- * a `person`, an LLM is an `agent`, and a `system` actor is the `engine` itself
1612
- * ({@link isEngineActor}) or otherwise an external `service`.
2082
+ * Classify the actor that drove an action for the audit-trail glyph. `person`
2083
+ * and `agent` pass through from {@link Actor.kind}; a `system` actor is the
2084
+ * `engine` itself ({@link isEngineActor}) or otherwise an external `service`.
1613
2085
  *
1614
2086
  * Advisory and only as trustworthy as the {@link Actor} it reads — actor
1615
2087
  * identity is itself advisory in this engine (the lake/token is authoritative),
@@ -1620,36 +2092,36 @@ export declare function driverKind(actor: Actor): DriverKind;
1620
2092
  export declare type Editable = v.InferOutput<typeof StoredEditableSchema>;
1621
2093
 
1622
2094
  /**
1623
- * One declared-editable slot in the current scope, projected for an actor: its
2095
+ * One declared-editable field in the current scope, projected for an actor: its
1624
2096
  * resolved value, whether this actor may edit it now (advisory), and the
1625
2097
  * provenance of the current value read off `opApplied` history. The reactive
1626
2098
  * surface a consumer renders as an inline field (the field widget itself is
1627
- * out of scope here — see the slot-component work).
2099
+ * out of scope here — see the field-component work).
1628
2100
  */
1629
- export declare interface EditableSlotEvaluation {
2101
+ export declare interface EditableFieldEvaluation {
1630
2102
  scope: FieldScope;
1631
2103
  /** Present iff `scope === "activity"`. */
1632
2104
  activity?: ActivityName;
1633
2105
  name: string;
1634
2106
  type: FieldKind;
1635
2107
  title?: string;
1636
- /** Current resolved value; `undefined` until the slot is first resolved. */
2108
+ /** Current resolved value; `undefined` until the field is first resolved. */
1637
2109
  value: unknown;
1638
- /** Whether THIS actor may edit the slot right now (window + predicate + guard). */
2110
+ /** Whether THIS actor may edit the field right now (window + predicate + guard). */
1639
2111
  editable: boolean;
1640
2112
  /** Present iff `editable === false`. */
1641
2113
  disabledReason?: EditDisabledReason;
1642
- /** Actor who last wrote the slot (latest `opApplied`); absent if never written. */
2114
+ /** Actor who last wrote the field (latest `opApplied`); absent if never written. */
1643
2115
  setBy?: Actor;
1644
- /** When the slot was last written (ISO); absent if never written. */
2116
+ /** When the field was last written (ISO); absent if never written. */
1645
2117
  setAt?: string;
1646
2118
  }
1647
2119
 
1648
2120
  /**
1649
- * Why an editable slot can't be edited by this actor right now — the edit-seam
1650
- * twin of {@link DisabledReason}. First failing gate wins: the slot must be
1651
- * declared editable, its scope window open, no lake guard denying the instance
1652
- * write, and the who-may-edit predicate satisfied. Reuses the shared
2121
+ * Why an editable field can't be edited by this actor right now — the edit-seam
2122
+ * twin of {@link DisabledReason}. First failing gate wins: the field must be
2123
+ * declared editable, its scope window open, no deployed guard denying the
2124
+ * instance write, and the who-may-edit predicate satisfied. Reuses the shared
1653
2125
  * `mutation-guard-denied` shape — an edit is the same instance-doc `update` an
1654
2126
  * action commit performs, so the same guard pre-flight applies.
1655
2127
  */
@@ -1662,49 +2134,45 @@ export declare type EditDisabledReason =
1662
2134
  completedAt: string;
1663
2135
  }
1664
2136
  | {
1665
- /** The slot's scope window is closed: an activity-scope slot whose activity isn't
2137
+ /** The field's scope window is closed: an activity-scope field whose activity isn't
1666
2138
  * active, or otherwise out of its editable window. */
1667
2139
  kind: "edit-window-closed";
1668
2140
  detail: string;
1669
2141
  }
1670
2142
  | {
1671
- /** The slot's effective `editable` predicate evaluated falsy for this
2143
+ /** The field's effective `editable` predicate evaluated falsy for this
1672
2144
  * actor (a role/predicate miss; the stage tighten-override is folded in). */
1673
2145
  kind: "editor-not-permitted";
1674
2146
  predicate: string;
1675
2147
  }
1676
- | Extract<
1677
- DisabledReason,
1678
- {
1679
- kind: "mutation-guard-denied";
1680
- }
1681
- >;
2148
+ | MutationGuardDenial;
1682
2149
 
1683
2150
  export declare interface EditFieldArgs extends OperationArgs {
1684
2151
  /**
1685
- * Which declared-editable slot to write. Omit `scope` to resolve lexically
2152
+ * Which declared-editable field to write. Omit `scope` to resolve lexically
1686
2153
  * (a `activity` implies activity scope; otherwise the nearest declaring scope, stage
1687
- * before workflow). `activity` is required to address an activity-scope slot.
2154
+ * before workflow). `activity` is required to address an activity-scope field.
1688
2155
  */
1689
2156
  target: EditFieldTarget;
1690
2157
  /**
1691
2158
  * How to write: `set` replaces the value (reassign / reschedule), `append`
1692
- * adds a row to an array slot (a running log / todo list), `unset` clears it.
2159
+ * adds a row to an array field (a running log / todo list), `unset` clears it.
1693
2160
  * Default `set`.
1694
2161
  */
1695
2162
  mode?: EditMode;
1696
2163
  /**
1697
2164
  * The new value (for `set`) or row (for `append`), as plain JSON matching the
1698
- * slot's kind. Validated against the slot kind in the op path; omit for
2165
+ * field's kind. Validated against the field kind in the op path; omit for
1699
2166
  * `unset`.
1700
2167
  */
1701
2168
  value?: unknown;
1702
2169
  }
1703
2170
 
1704
2171
  /** Edit-seam twin of {@link ActionDisabledError}: thrown by `editField` when
1705
- * the slot can't be edited by the caller. Carries the structured reason. */
1706
- export declare class EditFieldDeniedError extends Error {
1707
- readonly reason: EditDisabledReason;
2172
+ * the field can't be edited by the caller except a guard denial, which is
2173
+ * {@link MutationGuardDeniedError} across all verbs. Carries the structured reason. */
2174
+ export declare class EditFieldDeniedError extends WorkflowError<"edit-field-denied"> {
2175
+ readonly reason: EditFieldDeniedReason;
1708
2176
  readonly target: {
1709
2177
  scope: FieldScope;
1710
2178
  field: string;
@@ -1716,31 +2184,39 @@ export declare class EditFieldDeniedError extends Error {
1716
2184
  field: string;
1717
2185
  activity?: string;
1718
2186
  };
1719
- reason: EditDisabledReason;
2187
+ reason: EditFieldDeniedReason;
1720
2188
  });
1721
2189
  }
1722
2190
 
2191
+ /** The verdicts {@link EditFieldDeniedError} can carry — every {@link EditDisabledReason}
2192
+ * except `mutation-guard-denied`, which escalates to {@link MutationGuardDeniedError}. */
2193
+ export declare type EditFieldDeniedReason = Exclude<
2194
+ EditDisabledReason,
2195
+ {
2196
+ kind: "mutation-guard-denied";
2197
+ }
2198
+ >;
2199
+
1723
2200
  export declare interface EditFieldTarget {
1724
- /** Omit to resolve lexically (activity slot if `activity` set, else stage then workflow). */
2201
+ /** Omit to resolve lexically (activity field if `activity` set, else stage then workflow). */
1725
2202
  scope?: FieldScope;
1726
2203
  field: string;
1727
- /** Required to address an activity-scope slot. */
2204
+ /** Required to address an activity-scope field. */
1728
2205
  activity?: string;
1729
2206
  }
1730
2207
 
1731
2208
  /**
1732
- * The generic edit seam (EDEX-1319). `editField` writes a declared-editable
1733
- * slot directly — reassign, reschedule, claim-by-hand, append to a log —
2209
+ * The generic edit seam. `editField` writes a declared-editable
2210
+ * field directly — reassign, reschedule, claim-by-hand, append to a log —
1734
2211
  * without a bespoke action per field. It is NOT a raw patch: the edit applies
1735
2212
  * as a `field.*` op through the shared op path (so it stamps `opApplied`
1736
- * provenance + history), gates on the slot's declared editability the same way
2213
+ * provenance + history), gates on the field's declared editability the same way
1737
2214
  * an action gates on its filter, then refreshes the stage's guards and lets the
1738
2215
  * caller cascade. Editing a value a transition reads can and should move the
1739
2216
  * instance — that rippling is intended.
1740
2217
  *
1741
- * Gating is ONE mechanism (advisory, like every engine check): the slot's
1742
- * effective `editable` predicate over the rendered scope. The lake ACL + guards
1743
- * are the only hard locks.
2218
+ * Gating is ONE mechanism (advisory, like every engine check): the field's
2219
+ * effective `editable` predicate over the rendered scope.
1744
2220
  */
1745
2221
  export declare type EditMode = "set" | "append" | "unset";
1746
2222
 
@@ -1799,6 +2275,15 @@ export declare interface EffectHistoryEntry {
1799
2275
  params: Record<string, unknown>;
1800
2276
  origin: EffectOrigin;
1801
2277
  actor?: Actor;
2278
+ /**
2279
+ * `_key` of the stage entry the run was queued under, carried from the
2280
+ * pending entry — the identity that makes the `$effectStatus` read
2281
+ * re-entry-safe (a timestamp tie could not be: same-commit loop-backs and
2282
+ * frozen test clocks stamp identical times). Absent only on rows persisted
2283
+ * before the engine stamped it; those never count as the current entry's
2284
+ * run (fail closed).
2285
+ */
2286
+ stageEntryKey?: string;
1802
2287
  ranAt: string;
1803
2288
  durationMs?: number;
1804
2289
  status: "done" | "failed";
@@ -1817,6 +2302,18 @@ export declare interface EffectHistoryEntry {
1817
2302
 
1818
2303
  export declare type EffectName = string;
1819
2304
 
2305
+ /**
2306
+ * The effect key does not match any pending effect on the instance. Besides a
2307
+ * typo'd key, an at-least-once runtime hits this on a double delivery — the
2308
+ * first completion drained the effect — so a consumer can branch on this kind
2309
+ * to treat the second attempt as already-done rather than as a failure.
2310
+ */
2311
+ export declare class EffectNotFoundError extends WorkflowError<"effect-not-found"> {
2312
+ readonly instanceId: string;
2313
+ readonly effectKey: string;
2314
+ constructor(args: { instanceId: string; effectKey: string });
2315
+ }
2316
+
1820
2317
  /**
1821
2318
  * Thrown when the ops an effect handler returns from its completion don't
1822
2319
  * parse against the stored op schema — a malformed `field.*` / `status.set`
@@ -1825,7 +2322,7 @@ export declare type EffectName = string;
1825
2322
  * a handler is external code, so its returned ops are validated at the
1826
2323
  * completion boundary rather than trusted to be well-formed.
1827
2324
  */
1828
- export declare class EffectOpsInvalidError extends Error {
2325
+ export declare class EffectOpsInvalidError extends WorkflowError<"effect-ops-invalid"> {
1829
2326
  readonly effect: string;
1830
2327
  readonly issues: string[];
1831
2328
  constructor(args: { effect: string; issues: string[] });
@@ -1952,7 +2449,7 @@ export declare type EffectsContextEntry =
1952
2449
  * `$effects['<effect name>'].<output>`.
1953
2450
  */
1954
2451
  export declare function effectsContextMap(
1955
- instance: WorkflowInstance,
2452
+ instance: Pick<WorkflowInstance, "effectsContext">,
1956
2453
  ): Record<string, unknown>;
1957
2454
 
1958
2455
  export declare interface Engine {
@@ -1966,36 +2463,34 @@ export declare interface Engine {
1966
2463
  readonly missingHandler: MissingHandlerPolicy;
1967
2464
  readonly logger: LoggerFactory;
1968
2465
  deployDefinitions: (
1969
- args: Bound<DeployDefinitionsArgs>,
2466
+ args: DeployDefinitionsArgs,
1970
2467
  ) => Promise<DeployDefinitionsResult>;
1971
- startInstance: (args: Bound<StartInstanceArgs>) => Promise<WorkflowInstance>;
1972
- fireAction: (args: Bound<FireActionArgs>) => Promise<DispatchResult>;
1973
- /** Edit a declared-editable field slot directly (the generic edit seam):
2468
+ startInstance: (args: StartInstanceArgs) => Promise<OperationResult>;
2469
+ fireAction: (args: FireActionArgs) => Promise<OperationResult>;
2470
+ /** Edit a declared-editable field directly (the generic edit seam):
1974
2471
  * reassign / reschedule / claim-by-hand / append-to-log, then cascade. */
1975
- editField: (args: Bound<EditFieldArgs>) => Promise<DispatchResult>;
1976
- completeEffect: (args: Bound<CompleteEffectArgs>) => Promise<DispatchResult>;
1977
- tick: (args: Bound<OperationArgs>) => Promise<DispatchResult>;
1978
- evaluateInstance: (
1979
- args: Bound<EvaluateArgs>,
1980
- ) => ReturnType<typeof evaluateInstance>;
2472
+ editField: (args: EditFieldArgs) => Promise<OperationResult>;
2473
+ completeEffect: (args: CompleteEffectArgs) => Promise<OperationResult>;
2474
+ tick: (args: OperationArgs) => Promise<OperationResult>;
2475
+ /** Project the instance from an actor's perspective — per-action verdicts
2476
+ * with structured disabled reasons. Pure read. */
2477
+ evaluate: (args: EvaluateArgs) => Promise<WorkflowEvaluation>;
1981
2478
  /** Diagnose why an instance is or isn't progressing — a classified
1982
2479
  * {@link DiagnoseResult} plus the evaluation it was derived from. */
1983
- diagnose: (args: Bound<EvaluateArgs>) => Promise<DiagnoseResult>;
2480
+ diagnose: (args: EvaluateArgs) => Promise<DiagnoseResult>;
1984
2481
  /** The actions firable on the instance's current stage, each flagged
1985
2482
  * allowed/disabled, plus the evaluation they came from. */
1986
- availableActions: (
1987
- args: Bound<EvaluateArgs>,
1988
- ) => Promise<AvailableActionsResult>;
2483
+ availableActions: (args: EvaluateArgs) => Promise<AvailableActionsResult>;
1989
2484
  /** Admin override — bypass filters/transitions and force the stage. */
1990
- setStage: (args: Bound<SetStageArgs>) => Promise<DispatchResult>;
2485
+ setStage: (args: SetStageArgs) => Promise<OperationResult>;
1991
2486
  /** Admin override — hard-stop an in-flight instance where it stands. */
1992
- abortInstance: (args: Bound<AbortInstanceArgs>) => Promise<DispatchResult>;
2487
+ abortInstance: (args: AbortInstanceArgs) => Promise<OperationResult>;
1993
2488
  /** Admin override — remove a deployed definition (instances are only ever aborted, never deleted). */
1994
2489
  deleteDefinition: (
1995
- args: Bound<DeleteDefinitionArgs>,
2490
+ args: DeleteDefinitionArgs,
1996
2491
  ) => Promise<DeleteDefinitionResult>;
1997
2492
  /** Fetch a workflow instance by id. */
1998
- getInstance: (args: { instanceId: string }) => Promise<WorkflowInstance>;
2493
+ getInstance: (args: InstanceRefArgs) => Promise<WorkflowInstance>;
1999
2494
  /** The reactive {@link WatchSet} for an instance — every document whose
2000
2495
  * change should re-evaluate it (the instance, its ancestors, and the docs
2001
2496
  * named by `doc.ref`/`doc.refs`/`release.ref` field entries on the workflow scope
@@ -2003,27 +2498,19 @@ export declare interface Engine {
2003
2498
  * instance's read perspective. Fetches the instance, then derives. A
2004
2499
  * reactive adapter that already holds the live instance calls the pure
2005
2500
  * `subscriptionDocumentsForInstance` directly instead, to avoid the re-fetch. */
2006
- subscriptionDocumentsForInstance: (args: {
2007
- instanceId: string;
2008
- }) => Promise<WatchSet>;
2501
+ subscriptionDocumentsForInstance: (
2502
+ args: InstanceRefArgs,
2503
+ ) => Promise<WatchSet>;
2009
2504
  /** Opt into reactivity: bind the engine to an instance doc and get a stateful
2010
2505
  * {@link InstanceSession}. Push the docs it lists in `subscriptionDocuments`
2011
2506
  * via `update`, then `evaluate`/`tick`/`fireAction` against the held state —
2012
2507
  * pushed content is never refetched. The session never observes or ticks on
2013
2508
  * its own; the consumer drives it. */
2014
- instance: (
2015
- instanceDoc: WorkflowInstance,
2016
- opts?: {
2017
- access?: WorkflowAccessOverride | undefined;
2018
- grantsFromPath?: string | undefined;
2019
- },
2020
- ) => InstanceSession;
2509
+ session: (args: SessionArgs) => InstanceSession;
2021
2510
  /** Every lake mutation guard this instance registered, unioned across the
2022
2511
  * instance's own resource and the resource of each `doc.ref`/`doc.refs`
2023
2512
  * GDR it holds in state. For coherency refresh and housekeeping. */
2024
- guardsForInstance: (args: {
2025
- instanceId: string;
2026
- }) => Promise<MutationGuardDoc[]>;
2513
+ guardsForInstance: (args: InstanceRefArgs) => Promise<MutationGuardDoc[]>;
2027
2514
  /** Every lake mutation guard a workflow deployed (any version), across the
2028
2515
  * datasources its guards statically name — the workflow resource plus any
2029
2516
  * literal-GDR field entries, unioned over all deployed versions.
@@ -2031,58 +2518,40 @@ export declare interface Engine {
2031
2518
  * (input/runtime-sourced entries) are not reachable here — use
2032
2519
  * {@link Engine.guardsForInstance}. For housekeeping. Takes the
2033
2520
  * definition's `name`. */
2034
- guardsForDefinition: (args: {
2035
- definition: string;
2036
- }) => Promise<MutationGuardDoc[]>;
2521
+ guardsForDefinition: (
2522
+ args: GuardsForDefinitionArgs,
2523
+ ) => Promise<MutationGuardDoc[]>;
2037
2524
  /** Spawned children of a parent instance, optionally filtered by the
2038
2525
  * spawning activity. Sorted by `startedAt` asc. */
2039
- children: (args: {
2040
- instanceId: string;
2041
- activity?: string;
2042
- }) => Promise<WorkflowInstance[]>;
2526
+ children: (args: ChildrenArgs) => Promise<WorkflowInstance[]>;
2043
2527
  /** The reverse of {@link Engine.subscriptionDocumentsForInstance}: every
2044
2528
  * in-flight instance whose watch-set includes `document` (a resource-qualified
2045
2529
  * GDR URI). For a non-reactive, content-change-driven runtime deciding which
2046
2530
  * instances a changed doc should `tick`. Matches the same ref set the forward
2047
2531
  * watch-set uses (self, ancestors, current-stage `doc.ref`/`doc.refs`/`release.ref`)
2048
2532
  * via the shared `collectWatchRefs`. Sorted by `startedAt` asc. */
2049
- instancesForDocument: (args: {
2050
- document: GdrUri;
2051
- }) => Promise<WorkflowInstance[]>;
2533
+ instancesForDocument: (
2534
+ args: InstancesForDocumentArgs,
2535
+ ) => Promise<WorkflowInstance[]>;
2052
2536
  /** GROQ query against the engine's workflow resource. `$tag`
2053
2537
  * is bound for tag-scoped filtering. */
2054
- query: <T = unknown>(args: {
2055
- groq: string;
2056
- params?: Record<string, unknown>;
2057
- }) => Promise<T>;
2538
+ query: <T = unknown>(args: QueryArgs) => Promise<T>;
2058
2539
  /** Snapshot-aware GROQ — runs against the same in-memory view the
2059
- * engine's filters see for the supplied instance. The rendered scope
2060
- * (`$self`, `$fields`, `$parent`, `$ancestors`, `$stage`, `$now`,
2061
- * `$effects`, `$activities`, `$allActivitiesDone`, `$anyActivityFailed`) is bound,
2062
- * ids in GDR URI form to match the snapshot's keying. */
2063
- queryInScope: <T = unknown>(args: {
2064
- instanceId: string;
2065
- groq: string;
2066
- params?: Record<string, unknown>;
2067
- }) => Promise<T>;
2540
+ * engine's filters see for the supplied instance. The rendered scope's
2541
+ * instance-derived vars ({@link FILTER_SCOPE_VARS}) are bound, ids in
2542
+ * GDR URI form to match the snapshot's keying. */
2543
+ queryInScope: <T = unknown>(args: QueryInScopeArgs) => Promise<T>;
2068
2544
  /** List every pending effect on an instance. */
2069
- listPendingEffects: (args: {
2070
- instanceId: string;
2071
- }) => Promise<PendingEffect[]>;
2545
+ listPendingEffects: (args: InstanceRefArgs) => Promise<PendingEffect[]>;
2072
2546
  /** Filter pending effects by claimed status and/or effect names. */
2073
- findPendingEffects: (args: {
2074
- instanceId: string;
2075
- claimed?: boolean;
2076
- names?: string[];
2077
- }) => Promise<PendingEffect[]>;
2547
+ findPendingEffects: (
2548
+ args: FindPendingEffectsArgs,
2549
+ ) => Promise<PendingEffect[]>;
2078
2550
  /** Dispatch unclaimed effects through registered handlers. The
2079
2551
  * drainer's identity defaults to a `{ kind: "system", id: "engine.drainEffects" }`
2080
2552
  * actor; pass `access` to override (e.g. impersonate a real user
2081
2553
  * whose grants you want the dispatch to respect). */
2082
- drainEffects: (args: {
2083
- instanceId: string;
2084
- access?: WorkflowAccessOverride;
2085
- }) => Promise<DrainEffectsResult>;
2554
+ drainEffects: (args: DrainEffectsArgs) => Promise<DrainEffectsResult>;
2086
2555
  /**
2087
2556
  * Inspect every deployed definition in the engine's tag and apply
2088
2557
  * the configured missingHandler policy at `phase: "deploy"` for any
@@ -2096,18 +2565,43 @@ export declare interface Engine {
2096
2565
  verifyDeployedDefinitions: () => Promise<VerifyDeployedDefinitionsResult>;
2097
2566
  }
2098
2567
 
2568
+ /**
2569
+ * The API surface the engine's reads and writes assume. Every client bound to
2570
+ * the engine pins this one version so they cannot drift apart.
2571
+ */
2572
+ export declare const ENGINE_API_VERSION = "2026-04-29";
2573
+
2099
2574
  export declare interface EngineLogger {
2100
2575
  info: (message: string, extra?: Record<string, unknown>) => void;
2101
2576
  warn: (message: string, extra?: Record<string, unknown>) => void;
2102
2577
  error: (message: string, extra?: Record<string, unknown>) => void;
2103
2578
  }
2104
2579
 
2105
- export declare interface EvaluateArgs {
2580
+ /**
2581
+ * The engine-scope bindings pinned once by `createEngine` and carried
2582
+ * explicitly on every raw `workflow.*` call. `Engine` methods never take
2583
+ * these — they were supplied at construction.
2584
+ */
2585
+ export declare interface EngineScopeArgs {
2106
2586
  client: WorkflowClient;
2107
- /** Engine-scope environment partition — required. */
2587
+ /** Engine-scope environment partition — required. See {@link validateTag} + `tags.ts`. */
2108
2588
  tag: string;
2109
- /** Engine workflow resource — required. */
2589
+ /**
2590
+ * The Sanity resource the engine's own data lives in. Used to mint
2591
+ * GDR URIs for every doc the engine writes (definitions, instances,
2592
+ * ancestor refs). Mirrors `@sanity/client`'s `ClientConfigResource`.
2593
+ */
2110
2594
  workflowResource: WorkflowResource;
2595
+ /**
2596
+ * Optional routing for cross-resource reads (subject + ancestor docs that
2597
+ * live in a different Sanity resource than the workflow). Called with a
2598
+ * parsed GDR; return a client for that resource, or undefined to fall back
2599
+ * to `client`. Engine-scope configuration — see `CreateEngineArgs`.
2600
+ */
2601
+ resourceClients?: ResourceClientResolver;
2602
+ }
2603
+
2604
+ export declare interface EvaluateArgs {
2111
2605
  instanceId: string;
2112
2606
  /**
2113
2607
  * Optional access-state override. By default the engine resolves
@@ -2131,16 +2625,6 @@ export declare interface EvaluateArgs {
2131
2625
  * call would mean a network round-trip on every fireAction.
2132
2626
  */
2133
2627
  grantsFromPath?: string;
2134
- /**
2135
- * Optional resource-aware client routing — see
2136
- * `StartInstanceArgs.resourceClients`. When the workflow's subject
2137
- * (or any ancestor) lives in a different resource than the engine's
2138
- * client, this resolver decides which client to read it through.
2139
- * The evaluation hydrates a GDR-keyed snapshot from those reads and
2140
- * runs `_id`-scoped conditions locally in groq-js — same model as the
2141
- * cascade path.
2142
- */
2143
- resourceClients?: (parsed: ParsedGdr) => WorkflowClient | undefined;
2144
2628
  }
2145
2629
 
2146
2630
  /**
@@ -2148,8 +2632,8 @@ export declare interface EvaluateArgs {
2148
2632
  * instance, its definition, the resolved actor/grants, and a snapshot,
2149
2633
  * compute "what can this actor do right now, and why not the rest." No
2150
2634
  * I/O — feed it a fresh snapshot (e.g. rebuilt from a live store on
2151
- * change) for reactive re-evaluation. Best-effort by design: the lake's
2152
- * mutation guards + ACL are the real enforcement.
2635
+ * change) for reactive re-evaluation. Best-effort by design: verdicts are
2636
+ * advisory, not enforcement.
2153
2637
  */
2154
2638
  export declare function evaluateFromSnapshot(
2155
2639
  args: EvaluateFromSnapshotArgs,
@@ -2179,19 +2663,16 @@ export declare interface EvaluateFromSnapshotArgs {
2179
2663
  */
2180
2664
  now?: string;
2181
2665
  /**
2182
- * Live lake mutation guards held for this instance (a reactive adapter's
2666
+ * Live mutation guards held for this instance (a reactive adapter's
2183
2667
  * guard stream). Every action commit is an `update` write to the instance
2184
2668
  * doc, so a guard that matches the instance and denies that write disables
2185
- * every action with `mutation-guard-denied`. Omit to skip the gate the
2186
- * lake still enforces at commit time.
2669
+ * every action with `mutation-guard-denied`. Omit to skip the gate in this
2670
+ * projection the engine's verb paths load live guards and re-check at
2671
+ * commit time ({@link evaluateInstance} fetches them itself).
2187
2672
  */
2188
2673
  guards?: readonly MutationGuardDoc[];
2189
2674
  }
2190
2675
 
2191
- declare function evaluateInstance(
2192
- args: Clocked<EvaluateArgs>,
2193
- ): Promise<WorkflowEvaluation>;
2194
-
2195
2676
  /**
2196
2677
  * Evaluate a guard predicate against a mutation. Returns `true` only when the
2197
2678
  * predicate is strictly `true` (ALLOW). Empty predicate denies. Fail-closed:
@@ -2227,13 +2708,11 @@ declare function fetchGrants(args: {
2227
2708
  signal?: AbortSignal;
2228
2709
  }): Promise<Grant[]>;
2229
2710
 
2230
- declare const FIELD_SCOPES: readonly ["workflow", "stage", "activity"];
2231
-
2232
2711
  /**
2233
2712
  * Field-entry `_type` discriminators. The entry's kind defines what
2234
2713
  * shape `value` takes (single GDR vs array, scalar vs notes log).
2235
2714
  */
2236
- export declare const FIELD_SLOT_DISPLAY: {
2715
+ export declare const FIELD_KIND_DISPLAY: {
2237
2716
  "doc.ref": {
2238
2717
  title: string;
2239
2718
  description: string;
@@ -2296,6 +2775,8 @@ export declare const FIELD_SLOT_DISPLAY: {
2296
2775
  };
2297
2776
  };
2298
2777
 
2778
+ declare const FIELD_SCOPES: readonly ["workflow", "stage", "activity"];
2779
+
2299
2780
  /**
2300
2781
  * The kinds a VALUE can take — scalars aligned to Sanity's names, the
2301
2782
  * reference kinds, the actor/assignee identities, and the two compositional
@@ -2320,11 +2801,21 @@ declare const FIELD_VALUE_KINDS: readonly [
2320
2801
  "array",
2321
2802
  ];
2322
2803
 
2804
+ /** Type-mirror of {@link fieldBase}, parameterised over the `editable` grammar. */
2805
+ declare type FieldBase<TEditable> = {
2806
+ name: string;
2807
+ title?: string | undefined;
2808
+ description?: string | undefined;
2809
+ required?: boolean | undefined;
2810
+ initialValue?: FieldSource | undefined;
2811
+ editable?: TEditable | undefined;
2812
+ };
2813
+
2323
2814
  export declare type FieldEntry = FieldEntryFields<Editable>;
2324
2815
 
2325
2816
  /** Type-mirror of {@link fieldEntryFields}: a raw field entry of the given
2326
2817
  * editability grammar. */
2327
- declare type FieldEntryFields<TEditable> = SlotFields<TEditable> & {
2818
+ declare type FieldEntryFields<TEditable> = FieldBase<TEditable> & {
2328
2819
  type: FieldValueKind;
2329
2820
  fields?: FieldShape[] | undefined;
2330
2821
  of?: FieldShape[] | undefined;
@@ -2392,6 +2883,31 @@ export declare interface FieldValueMap {
2392
2883
  array: Record<string, unknown>[];
2393
2884
  }
2394
2885
 
2886
+ export declare class FieldValueShapeError extends WorkflowError<"field-value-shape"> {
2887
+ readonly entryType: string;
2888
+ readonly entryName: string;
2889
+ readonly issues: string[];
2890
+ constructor(args: {
2891
+ entryType: string;
2892
+ entryName: string;
2893
+ issues: string[];
2894
+ mode: "value" | "item";
2895
+ });
2896
+ }
2897
+
2898
+ /**
2899
+ * The subset that holds a value when the engine evaluates filters without a
2900
+ * caller (the cascade path: transition filters, `completeWhen`/`failWhen`).
2901
+ */
2902
+ export declare const FILTER_SCOPE_VARS: readonly string[];
2903
+
2904
+ export declare interface FindPendingEffectsArgs extends InstanceRefArgs {
2905
+ /** Filter on claim presence. */
2906
+ claimed?: boolean;
2907
+ /** Restrict to specific effect names. */
2908
+ names?: string[];
2909
+ }
2910
+
2395
2911
  export declare interface FireActionArgs extends OperationArgs {
2396
2912
  activity: string;
2397
2913
  action: string;
@@ -2407,7 +2923,7 @@ export declare interface FireActionArgs extends OperationArgs {
2407
2923
  * the current stage's `activityStatus` — typically because the workflow
2408
2924
  * has already advanced past it. Useful for drive scripts and
2409
2925
  * at-least-once delivery semantics: the second call returns the
2410
- * unchanged instance with `fired: false` rather than blowing up.
2926
+ * unchanged instance with `changed: false` rather than blowing up.
2411
2927
  */
2412
2928
  idempotent?: boolean;
2413
2929
  }
@@ -2518,8 +3034,15 @@ export declare type Guard = v.InferOutput<typeof GuardSchema>;
2518
3034
  /**
2519
3035
  * The lake document type for a mutation guard. Single source of truth — both
2520
3036
  * the runtime value (id construction, `compileGuard`, queries) and the
2521
- * {@link MutationGuardDoc} `_type` literal derive from here, so the `temp.`
2522
- * POC prefix drops in exactly one place at cutover.
3037
+ * {@link MutationGuardDoc} `_type` literal derive from here.
3038
+ *
3039
+ * The enforcement story hangs off this type: the lake does not evaluate
3040
+ * this doc type — it is the engine's placeholder for the lake's
3041
+ * forthcoming guard primitive (the lake reserves `system.*`). Until that
3042
+ * primitive ships, deployed guards deny OPTIMISTICALLY engine-side only, on
3043
+ * every project plan, and the lake ACL is the only hard gate. At cutover the
3044
+ * `temp.` prefix drops here, in exactly one place, and deployed guards become
3045
+ * lake-enforced (a breaking type change for already-persisted guard docs).
2523
3046
  */
2524
3047
  export declare const GUARD_DOC_TYPE = "temp.system.guard";
2525
3048
 
@@ -2528,6 +3051,18 @@ export declare const GUARD_LIFTED_PREDICATE = "true";
2528
3051
 
2529
3052
  export declare const GUARD_OWNER = "robot:workflow-engine";
2530
3053
 
3054
+ /**
3055
+ * The identifiers a lake mutation guard's `predicate` reads — the wire
3056
+ * dialect, not the condition scope (so no {@link ConditionVarBinding}: these
3057
+ * bind only when a guard evaluates a mutation). `before()`/`after()`/
3058
+ * `identity()` are groq-js delta-mode natives on top of these. Bound in one
3059
+ * place: `guardPredicateParams` in the guard evaluator.
3060
+ */
3061
+ export declare const GUARD_PREDICATE_VARS: readonly {
3062
+ name: string;
3063
+ description: string;
3064
+ }[];
3065
+
2531
3066
  export declare type GuardAction = v.InferOutput<typeof GuardActionSchema>;
2532
3067
 
2533
3068
  declare const GuardActionSchema: v.PicklistSchema<
@@ -2535,7 +3070,7 @@ declare const GuardActionSchema: v.PicklistSchema<
2535
3070
  `Invalid option: expected one of ${string}`
2536
3071
  >;
2537
3072
 
2538
- export declare type GuardMatch = v.InferOutput<typeof GuardMatchSchema>;
3073
+ export declare type GuardMatch = Guard["match"];
2539
3074
 
2540
3075
  /**
2541
3076
  * Does this guard's `match` apply to a mutation on the given document?
@@ -2554,84 +3089,102 @@ export declare function guardMatches({
2554
3089
  action: MutationGuardAction;
2555
3090
  }): boolean;
2556
3091
 
2557
- declare const GuardMatchSchema: v.StrictObjectSchema<
2558
- {
2559
- /** Subject `_type`(s); empty matches any type. */
2560
- readonly types: v.OptionalSchema<
2561
- v.ArraySchema<
2562
- v.SchemaWithPipe<
2563
- readonly [
2564
- v.StringSchema<undefined>,
2565
- v.MinLengthAction<string, 1, "must be a non-empty string">,
2566
- ]
2567
- >,
2568
- undefined
2569
- >,
3092
+ export declare type GuardRead = v.InferOutput<typeof GuardReadSchema>;
3093
+
3094
+ declare const GuardReadSchema: v.VariantSchema<
3095
+ "type",
3096
+ [
3097
+ v.StrictObjectSchema<
3098
+ {
3099
+ readonly type: v.LiteralSchema<"self", undefined>;
3100
+ },
2570
3101
  undefined
2571
- >;
2572
- /** Target docs as `$fields` reads (or `"$self"`), resolved at deploy to bare ids + the resource. */
2573
- readonly idRefs: v.OptionalSchema<
2574
- v.ArraySchema<
2575
- v.SchemaWithPipe<
2576
- readonly [
2577
- v.StringSchema<undefined>,
2578
- v.MinLengthAction<string, 1, "must be a non-empty string">,
2579
- ]
2580
- >,
2581
- undefined
2582
- >,
3102
+ >,
3103
+ v.StrictObjectSchema<
3104
+ {
3105
+ readonly type: v.LiteralSchema<"now", undefined>;
3106
+ },
3107
+ undefined
3108
+ >,
3109
+ v.StrictObjectSchema<
3110
+ {
3111
+ readonly type: v.LiteralSchema<"fieldRead", undefined>;
3112
+ readonly field: v.SchemaWithPipe<
3113
+ readonly [v.StringSchema<undefined>, v.RegexAction<string, string>]
3114
+ >;
3115
+ readonly path: v.OptionalSchema<
3116
+ v.SchemaWithPipe<
3117
+ readonly [
3118
+ v.SchemaWithPipe<
3119
+ readonly [
3120
+ v.StringSchema<undefined>,
3121
+ v.MinLengthAction<string, 1, "must be a non-empty string">,
3122
+ ]
3123
+ >,
3124
+ v.CheckAction<
3125
+ string,
3126
+ "a guard read path cannot contain a line break"
3127
+ >,
3128
+ ]
3129
+ >,
3130
+ undefined
3131
+ >;
3132
+ },
2583
3133
  undefined
2584
- >;
2585
- /** Glob id patterns (bare, resource-local). */
2586
- readonly idPatterns: v.OptionalSchema<
2587
- v.ArraySchema<
2588
- v.SchemaWithPipe<
3134
+ >,
3135
+ v.StrictObjectSchema<
3136
+ {
3137
+ readonly type: v.LiteralSchema<"effectsRead", undefined>;
3138
+ readonly effect: v.SchemaWithPipe<
2589
3139
  readonly [
2590
- v.StringSchema<undefined>,
2591
- v.MinLengthAction<string, 1, "must be a non-empty string">,
3140
+ v.SchemaWithPipe<
3141
+ readonly [
3142
+ v.StringSchema<undefined>,
3143
+ v.MinLengthAction<string, 1, "must be a non-empty string">,
3144
+ ]
3145
+ >,
3146
+ v.CheckAction<string, "an effect name cannot contain `'`">,
2592
3147
  ]
2593
- >,
2594
- undefined
2595
- >,
2596
- undefined
2597
- >;
2598
- readonly actions: v.SchemaWithPipe<
2599
- readonly [
2600
- v.ArraySchema<
2601
- v.PicklistSchema<
2602
- readonly ["create", "update", "delete", "publish", "unpublish"],
2603
- `Invalid option: expected one of ${string}`
3148
+ >;
3149
+ readonly path: v.OptionalSchema<
3150
+ v.SchemaWithPipe<
3151
+ readonly [
3152
+ v.SchemaWithPipe<
3153
+ readonly [
3154
+ v.StringSchema<undefined>,
3155
+ v.MinLengthAction<string, 1, "must be a non-empty string">,
3156
+ ]
3157
+ >,
3158
+ v.CheckAction<
3159
+ string,
3160
+ "a guard read path cannot contain a line break"
3161
+ >,
3162
+ ]
2604
3163
  >,
2605
3164
  undefined
2606
- >,
2607
- v.MinLengthAction<
2608
- ("create" | "update" | "delete" | "publish" | "unpublish")[],
2609
- 1,
2610
- "a guard must match at least one action"
2611
- >,
2612
- ]
2613
- >;
2614
- },
3165
+ >;
3166
+ },
3167
+ undefined
3168
+ >,
3169
+ ],
2615
3170
  undefined
2616
3171
  >;
2617
3172
 
3173
+ /** Stored guards carry the printed string reads (the deploy resolver's input). */
2618
3174
  declare const GuardSchema: v.StrictObjectSchema<
2619
3175
  {
2620
- readonly name: v.SchemaWithPipe<
3176
+ name: v.SchemaWithPipe<
2621
3177
  readonly [
2622
3178
  v.StringSchema<undefined>,
2623
3179
  v.MinLengthAction<string, 1, "must be a non-empty string">,
2624
3180
  ]
2625
3181
  >;
2626
- readonly title: v.OptionalSchema<v.StringSchema<undefined>, undefined>;
2627
- readonly description: v.OptionalSchema<
2628
- v.StringSchema<undefined>,
2629
- undefined
2630
- >;
2631
- readonly match: v.StrictObjectSchema<
3182
+ title: v.OptionalSchema<v.StringSchema<undefined>, undefined>;
3183
+ description: v.OptionalSchema<v.StringSchema<undefined>, undefined>;
3184
+ match: v.StrictObjectSchema<
2632
3185
  {
2633
3186
  /** Subject `_type`(s); empty matches any type. */
2634
- readonly types: v.OptionalSchema<
3187
+ types: v.OptionalSchema<
2635
3188
  v.ArraySchema<
2636
3189
  v.SchemaWithPipe<
2637
3190
  readonly [
@@ -2643,8 +3196,8 @@ declare const GuardSchema: v.StrictObjectSchema<
2643
3196
  >,
2644
3197
  undefined
2645
3198
  >;
2646
- /** Target docs as `$fields` reads (or `"$self"`), resolved at deploy to bare ids + the resource. */
2647
- readonly idRefs: v.OptionalSchema<
3199
+ /** Target docs as field reads (or the instance itself), resolved at deploy to bare ids + the resource. */
3200
+ idRefs: v.OptionalSchema<
2648
3201
  v.ArraySchema<
2649
3202
  v.SchemaWithPipe<
2650
3203
  readonly [
@@ -2657,7 +3210,7 @@ declare const GuardSchema: v.StrictObjectSchema<
2657
3210
  undefined
2658
3211
  >;
2659
3212
  /** Glob id patterns (bare, resource-local). */
2660
- readonly idPatterns: v.OptionalSchema<
3213
+ idPatterns: v.OptionalSchema<
2661
3214
  v.ArraySchema<
2662
3215
  v.SchemaWithPipe<
2663
3216
  readonly [
@@ -2669,7 +3222,7 @@ declare const GuardSchema: v.StrictObjectSchema<
2669
3222
  >,
2670
3223
  undefined
2671
3224
  >;
2672
- readonly actions: v.SchemaWithPipe<
3225
+ actions: v.SchemaWithPipe<
2673
3226
  readonly [
2674
3227
  v.ArraySchema<
2675
3228
  v.PicklistSchema<
@@ -2694,16 +3247,16 @@ declare const GuardSchema: v.StrictObjectSchema<
2694
3247
  * `identity()`. Bare ids/fields only. Omitted or empty means
2695
3248
  * UNCONDITIONAL DENY.
2696
3249
  */
2697
- readonly predicate: v.OptionalSchema<v.StringSchema<undefined>, undefined>;
3250
+ predicate: v.OptionalSchema<v.StringSchema<undefined>, undefined>;
2698
3251
  /**
2699
3252
  * Projected workflow fields the predicate reads as `guard.metadata.*` —
2700
3253
  * the only bridge from the lake eval context (which cannot see `$fields`)
2701
- * to workflow fields. Values are NOT GROQ: each is a deploy-time read in
2702
- * the guard mini-language `"$self"`, `"$now"`, or
2703
- * `"$fields.<name>[.path]"` — resolved into a bare value at deploy and
2704
- * re-synced by the post-field-op guard refresh.
3254
+ * to workflow fields. Each value is a deploy-time read — a typed
3255
+ * {@link GuardRead} when authoring, the printed string spelling once
3256
+ * stored — resolved into a bare value at deploy and re-synced by the
3257
+ * post-field-op guard refresh.
2705
3258
  */
2706
- readonly metadata: v.OptionalSchema<
3259
+ metadata: v.OptionalSchema<
2707
3260
  v.RecordSchema<
2708
3261
  v.SchemaWithPipe<
2709
3262
  readonly [
@@ -2730,7 +3283,7 @@ declare const GuardSchema: v.StrictObjectSchema<
2730
3283
  * its guards statically name — no live instance required. Guard docs are
2731
3284
  * stamped with the version-less definition, so this spans the datasources
2732
3285
  * declared across ALL deployed versions
2733
- * ({@link GuardsForDefinitionArgs.definitions}), not just the latest.
3286
+ * ({@link DefinitionGuardsQueryArgs.definitions}), not just the latest.
2734
3287
  *
2735
3288
  * A datasource is statically reachable when a guard idRef resolves to a
2736
3289
  * hardcoded GDR literal — directly, or via a `fieldRead` of a field entry whose
@@ -2741,16 +3294,12 @@ declare const GuardSchema: v.StrictObjectSchema<
2741
3294
  * {@link guardsForInstance}. Dedups resources by key, results by `_id`.
2742
3295
  */
2743
3296
  export declare function guardsForDefinition(
2744
- args: GuardsForDefinitionArgs,
3297
+ args: DefinitionGuardsQueryArgs,
2745
3298
  ): Promise<MutationGuardDoc[]>;
2746
3299
 
2747
- declare interface GuardsForDefinitionArgs {
2748
- client: WorkflowClient;
2749
- clientForGdr: (parsed: ParsedGdr) => WorkflowClient;
2750
- workflowResource: WorkflowResource;
3300
+ export declare interface GuardsForDefinitionArgs {
3301
+ /** The definition's `name`. */
2751
3302
  definition: string;
2752
- /** Every deployed version of {@link GuardsForDefinitionArgs.definition}. */
2753
- definitions: WorkflowDefinition[];
2754
3303
  }
2755
3304
 
2756
3305
  /**
@@ -2761,15 +3310,9 @@ declare interface GuardsForDefinitionArgs {
2761
3310
  * boundary.
2762
3311
  */
2763
3312
  export declare function guardsForInstance(
2764
- args: GuardsForInstanceArgs,
3313
+ args: InstanceGuardsQueryArgs,
2765
3314
  ): Promise<MutationGuardDoc[]>;
2766
3315
 
2767
- declare interface GuardsForInstanceArgs {
2768
- client: WorkflowClient;
2769
- clientForGdr: (parsed: ParsedGdr) => WorkflowClient;
2770
- instance: WorkflowInstance;
2771
- }
2772
-
2773
3316
  /** Every guard in one resource, regardless of which workflow registered it. */
2774
3317
  export declare function guardsForResource(
2775
3318
  client: WorkflowClient,
@@ -2963,8 +3506,8 @@ export declare type HistoryEntry =
2963
3506
  stage: StageName;
2964
3507
  /** The boundary that ran the op. For an action/transition/activation,
2965
3508
  * exactly one of activity/action/transition is set; for a direct edit
2966
- * (the edit seam), `edit` is set and `activity` carries the slot's activity when
2967
- * the edited slot is activity-scope; for an effect's completion ops,
3509
+ * (the edit seam), `edit` is set and `activity` carries the field's activity when
3510
+ * the edited field is activity-scope; for an effect's completion ops,
2968
3511
  * `effect` names the effect. */
2969
3512
  activity?: ActivityName;
2970
3513
  action?: ActionName;
@@ -3038,18 +3581,38 @@ export declare type InitialFieldValue = {
3038
3581
  * datasources for housekeeping. Matches lifted guards too (predicate
3039
3582
  * `"true"`) — the consumer decides how to render a lifted guard.
3040
3583
  */
3041
- export declare function instanceGuardQuery(instanceId: string): {
3042
- query: string;
3043
- params: Record<string, string>;
3044
- };
3584
+ export declare function instanceGuardQuery(instanceId: string): CompiledQuery;
3585
+
3586
+ declare interface InstanceGuardsQueryArgs {
3587
+ client: WorkflowClient;
3588
+ clientForGdr: (parsed: ParsedGdr) => WorkflowClient;
3589
+ instance: WorkflowInstance;
3590
+ }
3591
+
3592
+ /**
3593
+ * The instance id does not resolve to a workflow instance this engine can
3594
+ * see — the document is missing, or it belongs to another engine's tag
3595
+ * partition. Both arms share this class and kind (an invisible instance is
3596
+ * not-found to this caller); the message says which arm it was.
3597
+ */
3598
+ export declare class InstanceNotFoundError extends WorkflowError<"instance-not-found"> {
3599
+ readonly instanceId: string;
3600
+ constructor(args: { instanceId: string; detail?: string });
3601
+ }
3602
+
3603
+ /** Args for the verbs that address an instance without further input. */
3604
+ export declare interface InstanceRefArgs {
3605
+ instanceId: string;
3606
+ }
3045
3607
 
3046
3608
  export declare interface InstanceSession {
3047
3609
  /** The watch-set to feed via {@link InstanceSession.update}, derived from the
3048
3610
  * held instance. Recompute after the instance changes (a new stage changes it). */
3049
3611
  readonly subscriptionDocuments: WatchSet;
3050
3612
  /** Replace the held content with the current values the consumer observed
3051
- * (last-write-wins, scoped). A doc whose id is the instance itself updates
3052
- * the held instance. Buffered if a commit is in flight. */
3613
+ * (last-write-wins, scoped). A self-doc updates the held instance only when
3614
+ * its `_updatedAt` is strictly newer an older or timestamp-equal echo is
3615
+ * ignored. Buffered if a commit is in flight. */
3053
3616
  update(docs: LoadedDoc[]): void;
3054
3617
  /** Replace the held live guards (the consumer's guard stream,
3055
3618
  * last-write-wins). Guards are a separate stream from the watch-set:
@@ -3064,20 +3627,55 @@ export declare interface InstanceSession {
3064
3627
  evaluate(): Promise<WorkflowEvaluation>;
3065
3628
  /** Advance the instance against the held content: cascade auto-transitions,
3066
3629
  * deploy guards, queue effects, commit with `ifRevisionId`. */
3067
- tick(): Promise<DispatchResult>;
3630
+ tick(): Promise<OperationResult>;
3068
3631
  /** Fire an action against an activity, gated on the held content, then cascade. */
3069
3632
  fireAction(args: {
3070
3633
  activity: string;
3071
3634
  action: string;
3072
3635
  params?: Record<string, unknown>;
3073
- }): Promise<DispatchResult>;
3074
- /** Edit a declared-editable slot against the held content (the generic edit
3636
+ }): Promise<OperationResult>;
3637
+ /** Edit a declared-editable field against the held content (the generic edit
3075
3638
  * seam), gated on the held projection, then cascade. */
3076
3639
  editField(args: {
3077
3640
  target: EditFieldTarget;
3078
3641
  mode?: EditMode;
3079
3642
  value?: unknown;
3080
- }): Promise<DispatchResult>;
3643
+ }): Promise<OperationResult>;
3644
+ }
3645
+
3646
+ export declare interface InstancesForDocumentArgs {
3647
+ /** A resource-qualified GDR URI; a bare id is rejected. */
3648
+ document: GdrUri;
3649
+ }
3650
+
3651
+ /**
3652
+ * The instance-list GROQ for a {@link InstancesQueryFilter}, ordered by
3653
+ * `startedAt` ascending. Adapters subscribe to it; {@link workflow.query}
3654
+ * -style one-shot reads fetch it — both see the same rows.
3655
+ */
3656
+ export declare function instancesQuery(args: {
3657
+ tag: string;
3658
+ filter?: InstancesQueryFilter;
3659
+ }): CompiledQuery;
3660
+
3661
+ /**
3662
+ * Narrows an instance-list read. All conditions AND together; an empty
3663
+ * filter means "every in-flight instance in the engine's resource".
3664
+ */
3665
+ export declare interface InstancesQueryFilter {
3666
+ /**
3667
+ * Only instances that may reference this document (resource-qualified GDR
3668
+ * URI). This is a lake-side PREFILTER — a deliberate superset that also
3669
+ * matches exited-stage refs; narrow the fetched rows to the exact reactive
3670
+ * watch-set with {@link instanceWatchesDocument}.
3671
+ */
3672
+ document?: GdrUri;
3673
+ /** Version-less definition `name` the instances were started from. */
3674
+ definition?: string;
3675
+ /** Current stage name. */
3676
+ stage?: string;
3677
+ /** Include completed/aborted instances (default: in-flight only). */
3678
+ includeCompleted?: boolean;
3081
3679
  }
3082
3680
 
3083
3681
  /**
@@ -3100,16 +3698,26 @@ export declare function instanceWatchesDocument(
3100
3698
  /** Type filter for GDR shape. */
3101
3699
  export declare function isGdr(value: unknown): value is GlobalDocumentReference;
3102
3700
 
3701
+ /**
3702
+ * Whether a guard has been lifted (retracted to the unconditional-allow
3703
+ * predicate). A lift patches the predicate and keeps the doc, so lifted
3704
+ * guards still appear in guard queries and streams — this is the
3705
+ * discriminator a consumer filters or renders by.
3706
+ */
3707
+ export declare function isGuardLifted(
3708
+ guard: Pick<MutationGuardDoc, "predicate">,
3709
+ ): boolean;
3710
+
3103
3711
  /**
3104
3712
  * Whether a human may start this definition standalone (the default). A
3105
- * `role: 'child'` definition is spawn-only — instantiated by a parent via
3713
+ * `lifecycle: 'child'` definition is spawn-only — instantiated by a parent via
3106
3714
  * `activity.subworkflows`, so consumers exclude it from top-level start pickers.
3107
3715
  * Advisory: the engine does not enforce it (see the `required`-field backstop
3108
- * for load-bearing input slots). Accepts any definition-shaped value (authored,
3716
+ * for load-bearing input fields). Accepts any definition-shaped value (authored,
3109
3717
  * stored, deployed, or a projected list row).
3110
3718
  */
3111
3719
  export declare function isStartableDefinition(definition: {
3112
- role?: WorkflowRole | undefined;
3720
+ lifecycle?: WorkflowLifecycle | undefined;
3113
3721
  }): boolean;
3114
3722
 
3115
3723
  /**
@@ -3182,6 +3790,17 @@ export declare interface MissingHandlerDrainInfo {
3182
3790
  instanceId: string;
3183
3791
  }
3184
3792
 
3793
+ /**
3794
+ * The `missingHandler: 'fail'` policy tripped: an effect names a handler the
3795
+ * runtime never registered. `info` carries the phase-specific location
3796
+ * (deploy verification vs a drain attempt) so the runtime that opted into
3797
+ * failing can report exactly which handler is missing where.
3798
+ */
3799
+ export declare class MissingHandlerError extends WorkflowError<"missing-effect-handler"> {
3800
+ readonly info: MissingHandlerInfo;
3801
+ constructor(args: { info: MissingHandlerInfo });
3802
+ }
3803
+
3185
3804
  export declare type MissingHandlerInfo =
3186
3805
  | MissingHandlerDeployInfo
3187
3806
  | MissingHandlerDrainInfo;
@@ -3218,7 +3837,11 @@ export declare interface MutationContext {
3218
3837
  } & Record<string, unknown>)
3219
3838
  | null;
3220
3839
  action: MutationGuardAction;
3221
- /** Authenticated caller id, resolved as `identity()` in the predicate. */
3840
+ /**
3841
+ * Caller-asserted actor id, resolved as `identity()` in the predicate.
3842
+ * Advisory — the engine takes the caller's word for who is acting; only
3843
+ * the lake's own token identity is authenticated.
3844
+ */
3222
3845
  identity?: string;
3223
3846
  }
3224
3847
 
@@ -3234,7 +3857,14 @@ export declare interface MutationGuardBody {
3234
3857
  /** Engine-layer: the single datasource this guard belongs to. */
3235
3858
  resourceType: string;
3236
3859
  resourceId: string;
3237
- /** Registering identity — the engine robot. Only owner/admin may modify. */
3860
+ /**
3861
+ * Provenance stamp — who registered the guard (the engine writes its own
3862
+ * marker here). Unenforced: nothing reads `owner`, and there is no
3863
+ * owner/admin modification rule — guard deploy/refresh/retract ride the
3864
+ * caller's token like every other engine write. A lake-enforced guard can
3865
+ * therefore lock the engine's own housekeeping out (self-lockout) until a
3866
+ * dedicated engine execution identity exists.
3867
+ */
3238
3868
  owner: string;
3239
3869
  /**
3240
3870
  * Provenance — the workflow that registered this guard. The lake's own guard
@@ -3254,30 +3884,36 @@ export declare interface MutationGuardBody {
3254
3884
  metadata: Record<string, unknown>;
3255
3885
  }
3256
3886
 
3887
+ /** The `mutation-guard-denied` verdict arm, shared verbatim by
3888
+ * {@link DisabledReason} and {@link EditDisabledReason}. */
3889
+ export declare type MutationGuardDenial = Extract<
3890
+ DisabledReason,
3891
+ {
3892
+ kind: "mutation-guard-denied";
3893
+ }
3894
+ >;
3895
+
3257
3896
  /**
3258
- * Thrown when one or more guards deny a mutation. POC: raised by the engine /
3259
- * bench enforcement layer; carries every denial. Fail-closed: a predicate that
3260
- * errors or is non-true denies.
3897
+ * Thrown when one or more guards deny a mutation raised by the engine's
3898
+ * optimistic pre-flight and the bench's write seam; carries every denial.
3899
+ * Fail-closed: a predicate that errors or is non-true denies.
3900
+ *
3901
+ * The ONE guard-denial error: every verb whose write a guard denies —
3902
+ * `fireAction`, `editField`, `tick`, a session tick, a bench write — throws
3903
+ * this class, never a verb-specific wrapper.
3261
3904
  */
3262
- export declare class MutationGuardDeniedError extends Error {
3263
- readonly denied: Array<{
3264
- guardId: string;
3265
- name?: string;
3266
- }>;
3905
+ export declare class MutationGuardDeniedError extends WorkflowError<"mutation-guard-denied"> {
3906
+ readonly denied: DeniedGuardRef[];
3267
3907
  readonly documentId: string;
3268
3908
  readonly action: MutationGuardAction;
3269
3909
  constructor(args: {
3270
3910
  documentId: string;
3271
3911
  action: MutationGuardAction;
3272
- denied: Array<{
3273
- guardId: string;
3274
- name?: string;
3275
- }>;
3912
+ denied: DeniedGuardRef[];
3276
3913
  });
3277
3914
  /**
3278
- * Build the error straight from the denying guard docs the one mapping
3279
- * from {@link MutationGuardDoc} to the structured `denied` payload, shared
3280
- * by every enforcement site (engine pre-flight, bench write seam).
3915
+ * Build the error straight from the denying guard docs, shared by every
3916
+ * enforcement site (engine pre-flight, bench write seam).
3281
3917
  */
3282
3918
  static fromGuards(args: {
3283
3919
  documentId: string;
@@ -3307,7 +3943,7 @@ export declare interface MutationGuardMatch {
3307
3943
  * { body, actor, at }` (the `actor`/`at` sub-fields match the `audit` op's
3308
3944
  * stamp names, so it pairs with it). Never a stored kind.
3309
3945
  */
3310
- declare type NotesField = SlotFields<AuthoringEditable> & {
3946
+ declare type NotesField = FieldBase<AuthoringEditable> & {
3311
3947
  type: "notes";
3312
3948
  };
3313
3949
 
@@ -3353,13 +3989,6 @@ export declare interface OpAppliedSummary {
3353
3989
  }
3354
3990
 
3355
3991
  export declare interface OperationArgs {
3356
- client: WorkflowClient;
3357
- /** Engine-scope environment partition — required. */
3358
- tag: string;
3359
- /** The Sanity resource the engine's own data lives in. */
3360
- workflowResource: WorkflowResource;
3361
- /** Cross-resource routing — see `StartInstanceArgs.resourceClients`. */
3362
- resourceClients?: ResourceClientResolver;
3363
3992
  instanceId: string;
3364
3993
  /**
3365
3994
  * Optional access-state override. See `StartInstanceArgs.access`
@@ -3373,22 +4002,30 @@ export declare interface OperationArgs {
3373
4002
  idempotencyKey?: string;
3374
4003
  }
3375
4004
 
3376
- export declare type OpPredicate = OpPredicateInternal;
3377
-
3378
- declare type OpPredicateInternal =
3379
- | {
3380
- type: "field";
3381
- field: string;
3382
- equals: ValueExpr;
3383
- }
3384
- | {
3385
- type: "all";
3386
- of: OpPredicateInternal[];
3387
- }
3388
- | {
3389
- type: "any";
3390
- of: OpPredicateInternal[];
3391
- };
4005
+ /**
4006
+ * What a state-changing verb reports back. Every mutating verb —
4007
+ * `startInstance`, `fireAction`, `editField`, `completeEffect`, `tick`,
4008
+ * `setStage`, `abortInstance` — returns this one shape, on the namespace,
4009
+ * the `Engine`, and the reactive session alike.
4010
+ */
4011
+ export declare interface OperationResult {
4012
+ /** The instance after the operation + all cascading auto-transitions. */
4013
+ instance: WorkflowInstance;
4014
+ /** Number of auto-transitions that fired during the cascade. */
4015
+ cascaded: number;
4016
+ /**
4017
+ * Whether this call changed the instance's workflow state. `false` means
4018
+ * the call succeeded but was a no-op: an idempotent re-fire of an already
4019
+ * resolved activity, a `tick` that wrote nothing, a `setStage` already at
4020
+ * the target, an abort of an already-terminal instance. Failures throw —
4021
+ * `changed: false` never signals an error.
4022
+ */
4023
+ changed: boolean;
4024
+ /** Engine primitives (`workflow.op.field.*` / `status.set`) that ran
4025
+ * during the action commit. Surfaced for caller-side assertions and
4026
+ * audit. */
4027
+ ranOps?: OpAppliedSummary[];
4028
+ }
3392
4029
 
3393
4030
  export declare interface ParsedGdr {
3394
4031
  scheme: GdrScheme;
@@ -3416,7 +4053,7 @@ export declare function parseGdr(uri: string): ParsedGdr;
3416
4053
  * invokes {@link deployStageGuards} directly (without that rollback wrapper) can
3417
4054
  * also see it, so it's exported to be catchable by type.
3418
4055
  */
3419
- export declare class PartialGuardDeployError extends Error {
4056
+ export declare class PartialGuardDeployError extends WorkflowError<"partial-guard-deploy"> {
3420
4057
  readonly stageName: string;
3421
4058
  readonly deployed: number;
3422
4059
  constructor(args: { stageName: string; deployed: number; cause: unknown });
@@ -3443,6 +4080,14 @@ export declare interface PendingEffect {
3443
4080
  */
3444
4081
  actor?: Actor;
3445
4082
  queuedAt: string;
4083
+ /**
4084
+ * `_key` of the stage entry this effect was queued under — for a
4085
+ * transition's effects, the entry being entered. Carried onto the
4086
+ * completion's history row, where it is what ties a run to its stage
4087
+ * entry for the `$effectStatus` read. Absent only on entries persisted
4088
+ * before the engine stamped it.
4089
+ */
4090
+ stageEntryKey?: string;
3446
4091
  /**
3447
4092
  * Presence = a drainer is dispatching this entry. Absence = the entry
3448
4093
  * is unclaimed and eligible for drain. Entries in terminal states
@@ -3467,6 +4112,13 @@ export declare interface PendingEffectClaim {
3467
4112
  claimedBy: Actor;
3468
4113
  }
3469
4114
 
4115
+ export declare interface QueryArgs {
4116
+ groq: string;
4117
+ params?: Record<string, unknown>;
4118
+ }
4119
+
4120
+ export declare interface QueryInScopeArgs extends InstanceRefArgs, QueryArgs {}
4121
+
3470
4122
  /**
3471
4123
  * Whether a watched ref reads RAW — never perspective-scoped. The
3472
4124
  * instance, its ancestors (both instance docs), and `release.ref`
@@ -3554,11 +4206,11 @@ export declare type RemediationVerb =
3554
4206
  /**
3555
4207
  * Thrown when a workflow is started (or a child spawned) without a value for
3556
4208
  * a field entry marked `required`. Mirrors {@link ActionParamsInvalidError}:
3557
- * the engine has NOT created the instance — a missing load-bearing slot
4209
+ * the engine has NOT created the instance — a missing load-bearing field
3558
4210
  * (e.g. the subject of a review) screams here rather than silently defaulting
3559
4211
  * to `null`/`[]` and birthing a half-formed instance mid-process.
3560
4212
  */
3561
- export declare class RequiredFieldNotProvidedError extends Error {
4213
+ export declare class RequiredFieldNotProvidedError extends WorkflowError<"required-field-not-provided"> {
3562
4214
  readonly definition?: string;
3563
4215
  readonly missing: {
3564
4216
  name: string;
@@ -3573,6 +4225,14 @@ export declare class RequiredFieldNotProvidedError extends Error {
3573
4225
  });
3574
4226
  }
3575
4227
 
4228
+ /**
4229
+ * Names an author's predicate may not use — engine-owned and author names
4230
+ * share one namespace, so a predicate redefining a binding would silently
4231
+ * shadow engine behaviour. Rejected at deploy; derived from
4232
+ * {@link CONDITION_VARS}.
4233
+ */
4234
+ export declare const RESERVED_CONDITION_VARS: readonly string[];
4235
+
3576
4236
  /**
3577
4237
  * Resolve the engine's `WorkflowAccess` for a client. Override wins
3578
4238
  * outright; otherwise both halves are fetched in parallel and
@@ -3654,6 +4314,15 @@ export declare type ResolvedFieldEntry = {
3654
4314
  */
3655
4315
  export declare type ResourceAliases = Record<string, WorkflowResource>;
3656
4316
 
4317
+ /**
4318
+ * Collapse a deployment's `resourceAliases` bindings into the engine's
4319
+ * {@link ResourceAliases} map (handle name → physical resource) — the shape
4320
+ * {@link deployDefinitions} consumes.
4321
+ */
4322
+ export declare function resourceAliasesToMap(
4323
+ resourceAliases: WorkflowDeployment["resourceAliases"],
4324
+ ): ResourceAliases;
4325
+
3657
4326
  /**
3658
4327
  * Resolver for cross-resource reads. The engine has ONE `client` bound
3659
4328
  * to its own resource (where definition / instance
@@ -3665,7 +4334,7 @@ export declare type ResourceAliases = Record<string, WorkflowResource>;
3665
4334
  * The resolver receives the parsed pieces, not the raw URI, so it can
3666
4335
  * pattern-match on scheme + resource id without re-parsing.
3667
4336
  */
3668
- declare type ResourceClientResolver = (
4337
+ export declare type ResourceClientResolver = (
3669
4338
  parsed: ParsedGdr,
3670
4339
  ) => WorkflowClient | undefined;
3671
4340
 
@@ -3691,7 +4360,7 @@ declare interface ResourceRefArgs {
3691
4360
  * on it: an aborted instance keeps its `currentStage` (no stage move), so the
3692
4361
  * `abortedAt` stamp is what licenses lifting the stage it still occupies. The
3693
4362
  * gate is `abortedAt`, not `completedAt` — normal completion parks the
3694
- * instance on a structurally terminal stage whose guards must stay enforced.
4363
+ * instance on a structurally terminal stage whose guards must stay live.
3695
4364
  * Skip if it is still live on the stage (a concurrent loop-back re-entered
3696
4365
  * the stage and must keep its lock) or gone (leave the lock as the orphan
3697
4366
  * seam rather than silently unlocking a vanished instance — the same
@@ -3756,6 +4425,15 @@ declare const RoleAliasesSchema: v.RecordSchema<
3756
4425
  undefined
3757
4426
  >;
3758
4427
 
4428
+ export declare interface SessionArgs {
4429
+ /** The instance document to bind — typically the consumer's live-store value. */
4430
+ instance: WorkflowInstance;
4431
+ /** Optional access-state override — see `StartInstanceArgs.access`. */
4432
+ access?: WorkflowAccessOverride | undefined;
4433
+ /** URL path for grant resolution — see `StartInstanceArgs.grantsFromPath`. */
4434
+ grantsFromPath?: string | undefined;
4435
+ }
4436
+
3759
4437
  export declare interface SetStageArgs extends OperationArgs {
3760
4438
  /** Stage id to force the instance into. */
3761
4439
  targetStage: string;
@@ -3774,20 +4452,11 @@ export declare interface SetStageArgs extends OperationArgs {
3774
4452
  */
3775
4453
  export declare const silentLogger: EngineLogger;
3776
4454
 
3777
- /** Type-mirror of {@link slotFields}, parameterised over the `editable` grammar. */
3778
- declare type SlotFields<TEditable> = {
3779
- name: string;
3780
- title?: string | undefined;
3781
- description?: string | undefined;
3782
- required?: boolean | undefined;
3783
- initialValue?: FieldSource | undefined;
3784
- editable?: TEditable | undefined;
3785
- };
3786
-
3787
4455
  export declare type Stage = StageFields<
3788
4456
  FieldEntry,
3789
4457
  Activity,
3790
4458
  Transition,
4459
+ Guard,
3791
4460
  Editable
3792
4461
  >;
3793
4462
 
@@ -3808,14 +4477,14 @@ export declare interface StageEvaluation {
3808
4477
  transitions: TransitionEvaluation[];
3809
4478
  }
3810
4479
 
3811
- /** Type-mirror of {@link stageFields}, parameterised over field/activity/transition/editable. */
3812
- declare type StageFields<TField, TActivity, TTransition, TEditable> = {
4480
+ /** Type-mirror of {@link stageFields}, parameterised over field/activity/transition/guard/editable. */
4481
+ declare type StageFields<TField, TActivity, TTransition, TGuard, TEditable> = {
3813
4482
  name: string;
3814
4483
  title?: string | undefined;
3815
4484
  description?: string | undefined;
3816
4485
  activities?: TActivity[] | undefined;
3817
4486
  transitions?: TTransition[] | undefined;
3818
- guards?: Guard[] | undefined;
4487
+ guards?: TGuard[] | undefined;
3819
4488
  fields?: TField[] | undefined;
3820
4489
  editable?: Record<string, TEditable> | undefined;
3821
4490
  };
@@ -3833,18 +4502,6 @@ declare interface StageGuardArgs {
3833
4502
  export declare type StageName = string;
3834
4503
 
3835
4504
  export declare interface StartInstanceArgs {
3836
- client: WorkflowClient;
3837
- /** Engine-scope environment partition — required. */
3838
- tag: string;
3839
- /** The Sanity resource the engine's own data lives in. */
3840
- workflowResource: WorkflowResource;
3841
- /**
3842
- * Optional routing for cross-resource reads (subject + ancestor
3843
- * docs that live in a different Sanity resource than the workflow).
3844
- * Called with a parsed GDR; return a client for that resource, or
3845
- * undefined to fall back to `client`. See `CreateEngineArgs`.
3846
- */
3847
- resourceClients?: ResourceClientResolver;
3848
4505
  /** The definition's `name` — which deployed workflow to instantiate. */
3849
4506
  definition: string;
3850
4507
  /** Optional explicit version. Defaults to the highest deployed version. */
@@ -3892,10 +4549,11 @@ export declare interface StartInstanceArgs {
3892
4549
  access?: WorkflowAccessOverride;
3893
4550
  /**
3894
4551
  * URL path on the supplied client where the engine fetches the
3895
- * actor's ACL grants when `access.grants` isn't supplied. Required
3896
- * for the permission gate in production; omitting it means the
3897
- * gate is skipped (graceful degradation; the real Sanity write
3898
- * boundary still enforces).
4552
+ * actor's ACL grants when `access.grants` isn't supplied. Grants
4553
+ * feed the advisory `$can.*` params action conditions can read;
4554
+ * omitting this leaves the rendered `$can` undefined (conditions
4555
+ * referencing it fail closed, nothing else is gated engine-side —
4556
+ * the real Sanity write boundary still enforces).
3899
4557
  *
3900
4558
  * Canvas-style: `/canvases/<resourceId>/acl`.
3901
4559
  * Project/dataset: `/projects/<id>/datasets/<ds>/acl`.
@@ -3916,13 +4574,13 @@ export declare interface StartInstanceArgs {
3916
4574
  }
3917
4575
 
3918
4576
  /**
3919
- * Declared editability of a field slot — the generic edit seam's gate. Default
3920
- * (absent) is NOT editable: a slot is op-only engine working memory unless the
4577
+ * Declared editability of a field — the generic edit seam's gate. Default
4578
+ * (absent) is NOT editable: a field is op-only engine working memory unless the
3921
4579
  * modeler opens it. The stored form is `true` (editable by anyone within the
3922
- * slot's scope window) or a GROQ predicate over the rendered scope (`$actor`,
4580
+ * field's scope window) or an EDIT CONDITION rendered-scope GROQ (`$actor`,
3923
4581
  * `$can`, `$fields`, `$assigned`), checked like an action filter to decide
3924
4582
  * who-may-edit. ADVISORY like every engine gate — it disables the inline field
3925
- * and explains; real immutability needs a lake {@link Guard}.
4583
+ * and explains; a {@link Guard} declares the intended write-lock.
3926
4584
  */
3927
4585
  declare const StoredEditableSchema: v.UnionSchema<
3928
4586
  [
@@ -4032,7 +4690,12 @@ declare const StoredFieldOpSchema: v.VariantSchema<
4032
4690
  },
4033
4691
  undefined
4034
4692
  >;
4035
- readonly where: v.GenericSchema<OpPredicateInternal>;
4693
+ readonly where: v.SchemaWithPipe<
4694
+ readonly [
4695
+ v.StringSchema<undefined>,
4696
+ v.MinLengthAction<string, 1, "must be a non-empty string">,
4697
+ ]
4698
+ >;
4036
4699
  readonly value: v.GenericSchema<ValueExprInternal>;
4037
4700
  },
4038
4701
  undefined
@@ -4055,7 +4718,12 @@ declare const StoredFieldOpSchema: v.VariantSchema<
4055
4718
  },
4056
4719
  undefined
4057
4720
  >;
4058
- readonly where: v.GenericSchema<OpPredicateInternal>;
4721
+ readonly where: v.SchemaWithPipe<
4722
+ readonly [
4723
+ v.StringSchema<undefined>,
4724
+ v.MinLengthAction<string, 1, "must be a non-empty string">,
4725
+ ]
4726
+ >;
4059
4727
  },
4060
4728
  undefined
4061
4729
  >,
@@ -4208,7 +4876,12 @@ declare const StoredOpSchema: v.VariantSchema<
4208
4876
  },
4209
4877
  undefined
4210
4878
  >;
4211
- readonly where: v.GenericSchema<OpPredicateInternal>;
4879
+ readonly where: v.SchemaWithPipe<
4880
+ readonly [
4881
+ v.StringSchema<undefined>,
4882
+ v.MinLengthAction<string, 1, "must be a non-empty string">,
4883
+ ]
4884
+ >;
4212
4885
  readonly value: v.GenericSchema<ValueExprInternal>;
4213
4886
  },
4214
4887
  undefined
@@ -4231,7 +4904,12 @@ declare const StoredOpSchema: v.VariantSchema<
4231
4904
  },
4232
4905
  undefined
4233
4906
  >;
4234
- readonly where: v.GenericSchema<OpPredicateInternal>;
4907
+ readonly where: v.SchemaWithPipe<
4908
+ readonly [
4909
+ v.StringSchema<undefined>,
4910
+ v.MinLengthAction<string, 1, "must be a non-empty string">,
4911
+ ]
4912
+ >;
4235
4913
  },
4236
4914
  undefined
4237
4915
  >,
@@ -4441,7 +5119,7 @@ export declare type TerminalActivityStatus =
4441
5119
  * { label, status, assignee?, dueDate? }`; a plain checklist is this used with
4442
5120
  * `{label, status}` only (open ↔ done). Never a stored kind.
4443
5121
  */
4444
- declare type TodoListField = SlotFields<AuthoringEditable> & {
5122
+ declare type TodoListField = FieldBase<AuthoringEditable> & {
4445
5123
  type: "todoList";
4446
5124
  };
4447
5125
 
@@ -4541,12 +5219,12 @@ declare type ValueExprInternal =
4541
5219
 
4542
5220
  /**
4543
5221
  * The guards allowed to influence this instance's verdicts, read from the
4544
- * engine's own datasource only. A guard enforces solely within the datasource
5222
+ * engine's own datasource only. A guard applies solely within the datasource
4545
5223
  * it physically lives in, and `resourceType`/`resourceId` are plain document
4546
5224
  * fields any writer in that datasource can set — so a verdict load must be
4547
5225
  * physically scoped: a guard doc in a watched content dataset that
4548
5226
  * self-declares the engine's resource id must never reach a verdict. This
4549
- * keeps the advisory layer consistent (verdicts are UX, the lake enforces);
5227
+ * keeps the advisory layer consistent (verdicts are UX, not enforcement);
4550
5228
  * it is not itself a security boundary. Runs the same query the reactive
4551
5229
  * adapters subscribe with ({@link instanceGuardQuery}), so the stateless and
4552
5230
  * reactive paths agree.
@@ -4605,7 +5283,9 @@ export declare interface WatchSet {
4605
5283
  }
4606
5284
 
4607
5285
  /**
4608
- * The four-method workflow API.
5286
+ * The workflow verbs, bound as one object — write path, admin
5287
+ * overrides, pure reads, and permission helpers. The module doc above
5288
+ * describes the model.
4609
5289
  */
4610
5290
  export declare const workflow: {
4611
5291
  /**
@@ -4627,7 +5307,7 @@ export declare const workflow: {
4627
5307
  * Cycles in the dependency graph error before any write happens.
4628
5308
  */
4629
5309
  deployDefinitions: (
4630
- args: DeployDefinitionsArgs,
5310
+ args: DeployDefinitionsArgs & EngineScopeArgs,
4631
5311
  ) => Promise<DeployDefinitionsResult>;
4632
5312
  /**
4633
5313
  * Remove a deployed workflow definition (all versions, or one via
@@ -4637,7 +5317,7 @@ export declare const workflow: {
4637
5317
  * full contract (spawn-referrer check, guard-doc housekeeping).
4638
5318
  */
4639
5319
  deleteDefinition: (
4640
- args: Clocked<DeleteDefinitionArgs>,
5320
+ args: Clocked<DeleteDefinitionArgs & EngineScopeArgs>,
4641
5321
  ) => Promise<DeleteDefinitionResult>;
4642
5322
  /**
4643
5323
  * Spawn a new workflow instance from a deployed definition.
@@ -4645,11 +5325,12 @@ export declare const workflow: {
4645
5325
  * Pins the snapshot at start-time, seeds `effectsContext`, enters
4646
5326
  * the initial stage (which builds activityStatus, queues onEnter
4647
5327
  * effects, auto-activates activities). Then cascades auto-transitions
4648
- * until stable. Returns the resulting instance.
5328
+ * until stable. Starting always changes state (`changed: true`) —
5329
+ * `cascaded` reports how far the new instance auto-advanced.
4649
5330
  */
4650
5331
  startInstance: (
4651
- args: Clocked<StartInstanceArgs>,
4652
- ) => Promise<WorkflowInstance>;
5332
+ args: Clocked<StartInstanceArgs & EngineScopeArgs>,
5333
+ ) => Promise<OperationResult>;
4653
5334
  /**
4654
5335
  * Fire an action against an activity. If the activity is pending, it is
4655
5336
  * auto-invoked first (pending → active) so callers don't have to know
@@ -4660,23 +5341,27 @@ export declare const workflow: {
4660
5341
  * Runtimes fire it in response to webhooks, effect completions, and
4661
5342
  * timer firings. External signals never bypass this.
4662
5343
  */
4663
- fireAction: (args: Clocked<FireActionArgs>) => Promise<DispatchResult>;
5344
+ fireAction: (
5345
+ args: Clocked<FireActionArgs & EngineScopeArgs>,
5346
+ ) => Promise<OperationResult>;
4664
5347
  /**
4665
- * Edit a declared-editable field slot directly — reassign, reschedule,
5348
+ * Edit a declared-editable field directly — reassign, reschedule,
4666
5349
  * claim-by-hand, append to a running log — through the generic edit seam,
4667
- * instead of a bespoke action per field. Soft-gates on the slot's declared
5350
+ * instead of a bespoke action per field. Soft-gates on the field's declared
4668
5351
  * editability (the same projection a UI renders), applies the edit as a
4669
5352
  * `field.*` op (so provenance + history are stamped by the op path),
4670
5353
  * refreshes the stage's guards, then cascades — an edit to a value a
4671
5354
  * transition reads can and should move the instance. Advisory like every
4672
- * engine gate; the lake ACL + guards are the only hard locks.
5355
+ * engine gate.
4673
5356
  *
4674
5357
  * Each call is a discrete COMMIT (a history entry, a guard refresh, a
4675
5358
  * cascade, an `ifRevisionId` write), not a draft patch — so an inline-field
4676
5359
  * UI must bind it to a deliberate boundary (blur / Enter / Save / debounce),
4677
5360
  * never an `onChange` per keystroke.
4678
5361
  */
4679
- editField: (args: Clocked<EditFieldArgs>) => Promise<DispatchResult>;
5362
+ editField: (
5363
+ args: Clocked<EditFieldArgs & EngineScopeArgs>,
5364
+ ) => Promise<OperationResult>;
4680
5365
  /**
4681
5366
  * Report a queued effect's outcome. Drains it from `pendingEffects`,
4682
5367
  * appends an `effectHistory` entry, and (if `outputs` are supplied
@@ -4684,11 +5369,13 @@ export declare const workflow: {
4684
5369
  * `effectsContext` by key — so downstream effect bindings can
4685
5370
  * reference them. Any `ops` the handler returned (`field.*`) are
4686
5371
  * validated and applied to the instance in the same commit, through the
4687
- * same op applier an action's field ops use. Cascades after.
5372
+ * same op applier an action's field ops use. Cascades after. A completion
5373
+ * always changes state (the effect drains + history is appended), so
5374
+ * `changed` is always `true` — a bad `effectKey`/status throws instead.
4688
5375
  */
4689
5376
  completeEffect: (
4690
- args: Clocked<CompleteEffectArgs>,
4691
- ) => Promise<DispatchResult>;
5377
+ args: Clocked<CompleteEffectArgs & EngineScopeArgs>,
5378
+ ) => Promise<OperationResult>;
4692
5379
  /**
4693
5380
  * Re-evaluate auto-transitions and resolve due waits until stable.
4694
5381
  *
@@ -4696,48 +5383,50 @@ export declare const workflow: {
4696
5383
  * but isn't itself an activity action: a subject doc was patched, a sibling
4697
5384
  * workflow completed, the clock crossed a `completeWhen` deadline, etc.
4698
5385
  * The runtime doesn't need to know what changed — it just nudges
4699
- * affected instances and the engine re-evaluates.
5386
+ * affected instances and the engine re-evaluates. `changed` reports
5387
+ * whether the nudge wrote anything: a fired transition, but also a
5388
+ * persisted activity-gate flip (`completeWhen`/`failWhen`) that didn't
5389
+ * unlock a transition yet — so it's derived from the instance's `_rev`,
5390
+ * not from `cascaded` alone.
4700
5391
  */
4701
- tick: (args: Clocked<OperationArgs>) => Promise<DispatchResult>;
5392
+ tick: (
5393
+ args: Clocked<OperationArgs & EngineScopeArgs>,
5394
+ ) => Promise<OperationResult>;
4702
5395
  /**
4703
5396
  * Admin override — force the instance into `targetStage` regardless
4704
5397
  * of filters or declared transitions. ACL gating should be enforced
4705
- * upstream; this verb performs the mechanical move.
5398
+ * upstream; this verb performs the mechanical move. `changed: false`
5399
+ * means the move was a no-op (already at the target / terminal).
4706
5400
  */
4707
- setStage: (args: Clocked<SetStageArgs>) => Promise<DispatchResult>;
5401
+ setStage: (
5402
+ args: Clocked<SetStageArgs & EngineScopeArgs>,
5403
+ ) => Promise<OperationResult>;
4708
5404
  /**
4709
5405
  * Admin override — hard-stop an in-flight instance where it stands.
4710
5406
  * No stage move, no transition effects, pending effects cancelled;
4711
5407
  * see {@link abortAndPropagate} for the abort + ancestor-propagation
4712
- * contract (propagated, not cascaded — the instance is terminal).
5408
+ * contract (propagated, not cascaded — the instance is terminal, so
5409
+ * `cascaded` is always `0`; ancestor movement is reported on the
5410
+ * ancestors, not here). `changed: false` means the instance was
5411
+ * already terminal.
4713
5412
  */
4714
- abortInstance: (args: Clocked<AbortInstanceArgs>) => Promise<DispatchResult>;
5413
+ abortInstance: (
5414
+ args: Clocked<AbortInstanceArgs & EngineScopeArgs>,
5415
+ ) => Promise<OperationResult>;
4715
5416
  /**
4716
5417
  * Fetch a workflow instance by id, scoped to the engine's tag.
4717
5418
  * Throws when the instance doesn't exist or isn't visible to this
4718
5419
  * engine.
4719
5420
  */
4720
- getInstance: (args: {
4721
- client: WorkflowClient;
4722
- tag: string;
4723
- workflowResource: WorkflowResource;
4724
- instanceId: string;
4725
- }) => Promise<WorkflowInstance>;
4726
- guardsForInstance: (args: {
4727
- client: WorkflowClient;
4728
- tag: string;
4729
- workflowResource: WorkflowResource;
4730
- instanceId: string;
4731
- resourceClients?: ResourceClientResolver;
4732
- }) => Promise<MutationGuardDoc[]>;
4733
- guardsForDefinition: (args: {
4734
- client: WorkflowClient;
4735
- tag: string;
4736
- workflowResource: WorkflowResource;
4737
- /** The definition's `name`. */
4738
- definition: string;
4739
- resourceClients?: ResourceClientResolver;
4740
- }) => Promise<MutationGuardDoc[]>;
5421
+ getInstance: (
5422
+ args: InstanceRefArgs & EngineScopeArgs,
5423
+ ) => Promise<WorkflowInstance>;
5424
+ guardsForInstance: (
5425
+ args: InstanceRefArgs & EngineScopeArgs,
5426
+ ) => Promise<MutationGuardDoc[]>;
5427
+ guardsForDefinition: (
5428
+ args: GuardsForDefinitionArgs & EngineScopeArgs,
5429
+ ) => Promise<MutationGuardDoc[]>;
4741
5430
  /**
4742
5431
  * Run a caller-supplied GROQ query with the engine's tag bound as
4743
5432
  * `$tag`. This does NOT rewrite the query — arbitrary GROQ
@@ -4747,13 +5436,7 @@ export declare const workflow: {
4747
5436
  * rejected before it reaches the lake. Caller is responsible for type
4748
5437
  * narrowing the result.
4749
5438
  */
4750
- query: <T = unknown>(args: {
4751
- client: WorkflowClient;
4752
- tag: string;
4753
- workflowResource: WorkflowResource;
4754
- groq: string;
4755
- params?: Record<string, unknown>;
4756
- }) => Promise<T>;
5439
+ query: <T = unknown>(args: QueryArgs & EngineScopeArgs) => Promise<T>;
4757
5440
  /**
4758
5441
  * Snapshot-aware GROQ — runs against the same in-memory view that
4759
5442
  * filters see for a given instance.
@@ -4761,49 +5444,31 @@ export declare const workflow: {
4761
5444
  * Hydrates the instance's snapshot (instance + ancestors + every doc
4762
5445
  * declared by a `doc.ref` / `doc.refs` entry in scope), then
4763
5446
  * evaluates the supplied GROQ in groq-js against that dataset. The
4764
- * rendered scope is auto-bound: `$self`, `$fields`, `$parent`,
4765
- * `$ancestors`, `$stage`, `$now`, `$effects`, `$activities`,
4766
- * `$allActivitiesDone`, `$anyActivityFailed` — ids in GDR URI form to match
4767
- * the snapshot's keying.
5447
+ * rendered scope's instance-derived vars ({@link FILTER_SCOPE_VARS}) are
5448
+ * auto-bound ids in GDR URI form to match the snapshot's keying.
4768
5449
  *
4769
5450
  * Use when an external consumer (a UI, a debug pane, a test) wants
4770
5451
  * to ask "what does the engine see for this workflow right now?"
4771
5452
  * without re-implementing hydration. Pure read — never writes.
4772
5453
  */
4773
5454
  queryInScope: <T = unknown>(
4774
- args: Clocked<{
4775
- client: WorkflowClient;
4776
- tag: string;
4777
- workflowResource: WorkflowResource;
4778
- resourceClients?: ResourceClientResolver;
4779
- instanceId: string;
4780
- groq: string;
4781
- params?: Record<string, unknown>;
4782
- }>,
5455
+ args: Clocked<QueryInScopeArgs & EngineScopeArgs>,
4783
5456
  ) => Promise<T>;
4784
5457
  /**
4785
5458
  * List every pending effect on the instance. Returns the same entries
4786
5459
  * the runtime would see — claimed and unclaimed alike.
4787
5460
  */
4788
- listPendingEffects: (args: {
4789
- client: WorkflowClient;
4790
- tag: string;
4791
- workflowResource: WorkflowResource;
4792
- instanceId: string;
4793
- }) => Promise<PendingEffect[]>;
5461
+ listPendingEffects: (
5462
+ args: InstanceRefArgs & EngineScopeArgs,
5463
+ ) => Promise<PendingEffect[]>;
4794
5464
  /**
4795
5465
  * Filter pending effects on the instance by criteria. `claimed`
4796
5466
  * filters on claim presence; `names` restricts to specific effect
4797
5467
  * names. Both filters compose (AND).
4798
5468
  */
4799
- findPendingEffects: (args: {
4800
- client: WorkflowClient;
4801
- tag: string;
4802
- workflowResource: WorkflowResource;
4803
- instanceId: string;
4804
- claimed?: boolean;
4805
- names?: string[];
4806
- }) => Promise<PendingEffect[]>;
5469
+ findPendingEffects: (
5470
+ args: FindPendingEffectsArgs & EngineScopeArgs,
5471
+ ) => Promise<PendingEffect[]>;
4807
5472
  /**
4808
5473
  * Project the instance from a given actor's perspective. Returns a
4809
5474
  * `WorkflowEvaluation` with per-action verdicts (`allowed` + a
@@ -4812,7 +5477,9 @@ export declare const workflow: {
4812
5477
  * Used by UIs to render disabled-with-reason buttons and by
4813
5478
  * `fireAction` to gate writes via the same logic.
4814
5479
  */
4815
- evaluate: (args: Clocked<EvaluateArgs>) => Promise<WorkflowEvaluation>;
5480
+ evaluate: (
5481
+ args: Clocked<EvaluateArgs & EngineScopeArgs>,
5482
+ ) => Promise<WorkflowEvaluation>;
4816
5483
  /**
4817
5484
  * Diagnose why an instance is or isn't progressing. Projects the
4818
5485
  * instance (the same read as `evaluate`) and classifies it — terminal,
@@ -4822,7 +5489,9 @@ export declare const workflow: {
4822
5489
  * consumer can render the supporting evidence without a second projection.
4823
5490
  * Pure read.
4824
5491
  */
4825
- diagnose: (args: Clocked<EvaluateArgs>) => Promise<DiagnoseResult>;
5492
+ diagnose: (
5493
+ args: Clocked<EvaluateArgs & EngineScopeArgs>,
5494
+ ) => Promise<DiagnoseResult>;
4826
5495
  /**
4827
5496
  * List the actions an actor could fire on an instance's current stage,
4828
5497
  * each flagged `allowed` (with a structured `disabledReason` when not).
@@ -4831,7 +5500,7 @@ export declare const workflow: {
4831
5500
  * consumer can read the instance/stage context. Pure read.
4832
5501
  */
4833
5502
  availableActions: (
4834
- args: Clocked<EvaluateArgs>,
5503
+ args: Clocked<EvaluateArgs & EngineScopeArgs>,
4835
5504
  ) => Promise<AvailableActionsResult>;
4836
5505
  /**
4837
5506
  * Materialised spawned children of a parent instance.
@@ -4845,13 +5514,9 @@ export declare const workflow: {
4845
5514
  *
4846
5515
  * Pass `activity` to restrict to a single spawning activity on the parent.
4847
5516
  */
4848
- children: (args: {
4849
- client: WorkflowClient;
4850
- tag: string;
4851
- workflowResource: WorkflowResource;
4852
- instanceId: string;
4853
- activity?: string;
4854
- }) => Promise<WorkflowInstance[]>;
5517
+ children: (
5518
+ args: ChildrenArgs & EngineScopeArgs,
5519
+ ) => Promise<WorkflowInstance[]>;
4855
5520
  /**
4856
5521
  * Every in-flight instance whose reactive watch-set includes `document` —
4857
5522
  * the reverse of {@link subscriptionDocumentsForInstance}.
@@ -4881,16 +5546,14 @@ export declare const workflow: {
4881
5546
  * (it can't be resource-routed and would silently mismatch). Sorted by
4882
5547
  * `startedAt` ascending.
4883
5548
  */
4884
- instancesForDocument: (args: {
4885
- client: WorkflowClient;
4886
- tag: string;
4887
- workflowResource: WorkflowResource;
4888
- document: GdrUri;
4889
- }) => Promise<WorkflowInstance[]>;
5549
+ instancesForDocument: (
5550
+ args: InstancesForDocumentArgs & EngineScopeArgs,
5551
+ ) => Promise<WorkflowInstance[]>;
4890
5552
  /**
4891
5553
  * Permission helpers — Sanity ACL grants evaluated against documents
4892
5554
  * via GROQ. Used by `workflow.evaluate` to soft-gate actions when the
4893
- * caller supplies grants.
5555
+ * caller supplies grants. Deliberately namespace-only (not mirrored on
5556
+ * `Engine`): pure helpers that need none of the engine's pinned scope.
4894
5557
  */
4895
5558
  permissions: {
4896
5559
  matchesFilter: typeof matchesFilter;
@@ -4914,13 +5577,18 @@ export declare const WORKFLOW_DEFINITION_TYPE = "sanity.workflow.definition";
4914
5577
  */
4915
5578
  export declare const WORKFLOW_INSTANCE_TYPE = "sanity.workflow.instance";
4916
5579
 
4917
- declare const WORKFLOW_ROLES: readonly ["workflow", "child"];
5580
+ declare const WORKFLOW_LIFECYCLES: readonly ["standalone", "child"];
4918
5581
 
4919
5582
  /**
4920
5583
  * The engine's view of "who am I, what can I do?". `actor` is who
4921
- * the engine stamps onto history / `completedBy` / `ValueExpr.actor`.
4922
- * `grants` (when present) gates `permission-denied`; when absent the
4923
- * gate is skipped and the real Sanity write boundary takes over.
5584
+ * the engine stamps onto history / `completedBy` / `ValueExpr.actor` —
5585
+ * caller-asserted advisory provenance (see {@link Actor}), never an
5586
+ * authenticated principal. `grants` (when present) feed the advisory
5587
+ * `$can.*` params action conditions can read; there is no engine-side
5588
+ * permission verdict. When grants are absent the rendered `$can` is
5589
+ * undefined — conditions referencing it fail closed, everything else
5590
+ * is ungated engine-side — and the real Sanity write boundary takes
5591
+ * over.
4924
5592
  *
4925
5593
  * This is the RESOLVED shape — `actor` is guaranteed. For the
4926
5594
  * partial-override shape callers pass on verb args, see
@@ -4932,13 +5600,13 @@ export declare interface WorkflowAccess {
4932
5600
  }
4933
5601
 
4934
5602
  /**
4935
- * Partial override accepted by every public verb's `access?:`
5603
+ * Partial override accepted by every acting verb's `access?:`
4936
5604
  * argument. Any field present wins; missing halves token-resolve.
4937
5605
  *
4938
5606
  * `{ actor, grants }` — bench's all-access default; both halves
4939
5607
  * injected, no token round-trip.
4940
5608
  * `{ actor }` — "act as another user"; grants come from
4941
- * `grantsFromPath` (or the gate is skipped).
5609
+ * `grantsFromPath` (or the rendered `$can` stays undefined).
4942
5610
  * `{ grants }` — "preview with restricted permissions"; actor
4943
5611
  * comes from `/users/me`.
4944
5612
  * omitted entirely — both halves token-resolved.
@@ -5044,6 +5712,396 @@ export declare interface WorkflowCommitOptions {
5044
5712
  visibility?: WorkflowVisibility;
5045
5713
  }
5046
5714
 
5715
+ export declare type WorkflowConfig = v.InferOutput<typeof WorkflowConfigSchema>;
5716
+
5717
+ declare const WorkflowConfigSchema: v.ObjectSchema<
5718
+ {
5719
+ readonly deployments: v.SchemaWithPipe<
5720
+ readonly [
5721
+ v.ArraySchema<
5722
+ v.ObjectSchema<
5723
+ {
5724
+ readonly name: v.SchemaWithPipe<
5725
+ readonly [
5726
+ v.StringSchema<undefined>,
5727
+ v.NonEmptyAction<string, "must not be empty">,
5728
+ ]
5729
+ >;
5730
+ readonly tag: v.SchemaWithPipe<
5731
+ readonly [
5732
+ v.StringSchema<undefined>,
5733
+ v.NonEmptyAction<string, undefined>,
5734
+ v.CheckAction<
5735
+ string,
5736
+ "invalid tag — lowercase letters, digits and dashes only, no leading dash, no dots"
5737
+ >,
5738
+ ]
5739
+ >;
5740
+ readonly workflowResource: v.VariantSchema<
5741
+ "type",
5742
+ [
5743
+ v.ObjectSchema<
5744
+ {
5745
+ readonly type: v.LiteralSchema<"dataset", undefined>;
5746
+ readonly id: v.SchemaWithPipe<
5747
+ readonly [
5748
+ v.SchemaWithPipe<
5749
+ readonly [
5750
+ v.StringSchema<undefined>,
5751
+ v.NonEmptyAction<string, "must not be empty">,
5752
+ ]
5753
+ >,
5754
+ v.CheckAction<
5755
+ string,
5756
+ 'invalid dataset resource id — expected "<projectId>.<dataset>"'
5757
+ >,
5758
+ ]
5759
+ >;
5760
+ },
5761
+ undefined
5762
+ >,
5763
+ v.ObjectSchema<
5764
+ {
5765
+ readonly type: v.LiteralSchema<"canvas", undefined>;
5766
+ readonly id: v.SchemaWithPipe<
5767
+ readonly [
5768
+ v.StringSchema<undefined>,
5769
+ v.NonEmptyAction<string, "must not be empty">,
5770
+ ]
5771
+ >;
5772
+ },
5773
+ undefined
5774
+ >,
5775
+ v.ObjectSchema<
5776
+ {
5777
+ readonly type: v.LiteralSchema<
5778
+ "media-library",
5779
+ undefined
5780
+ >;
5781
+ readonly id: v.SchemaWithPipe<
5782
+ readonly [
5783
+ v.StringSchema<undefined>,
5784
+ v.NonEmptyAction<string, "must not be empty">,
5785
+ ]
5786
+ >;
5787
+ },
5788
+ undefined
5789
+ >,
5790
+ v.ObjectSchema<
5791
+ {
5792
+ readonly type: v.LiteralSchema<"dashboard", undefined>;
5793
+ readonly id: v.SchemaWithPipe<
5794
+ readonly [
5795
+ v.StringSchema<undefined>,
5796
+ v.NonEmptyAction<string, "must not be empty">,
5797
+ ]
5798
+ >;
5799
+ },
5800
+ undefined
5801
+ >,
5802
+ ],
5803
+ undefined
5804
+ >;
5805
+ readonly resourceAliases: v.OptionalSchema<
5806
+ v.SchemaWithPipe<
5807
+ readonly [
5808
+ v.ArraySchema<
5809
+ v.ObjectSchema<
5810
+ {
5811
+ readonly name: v.SchemaWithPipe<
5812
+ readonly [
5813
+ v.SchemaWithPipe<
5814
+ readonly [
5815
+ v.StringSchema<undefined>,
5816
+ v.NonEmptyAction<string, "must not be empty">,
5817
+ ]
5818
+ >,
5819
+ v.CheckAction<
5820
+ string,
5821
+ "invalid resource handle name — lowercase letters, digits and dashes only, no leading dash"
5822
+ >,
5823
+ ]
5824
+ >;
5825
+ readonly resource: v.VariantSchema<
5826
+ "type",
5827
+ [
5828
+ v.ObjectSchema<
5829
+ {
5830
+ readonly type: v.LiteralSchema<
5831
+ "dataset",
5832
+ undefined
5833
+ >;
5834
+ readonly id: v.SchemaWithPipe<
5835
+ readonly [
5836
+ v.SchemaWithPipe<
5837
+ readonly [
5838
+ v.StringSchema<undefined>,
5839
+ v.NonEmptyAction<
5840
+ string,
5841
+ "must not be empty"
5842
+ >,
5843
+ ]
5844
+ >,
5845
+ v.CheckAction<
5846
+ string,
5847
+ 'invalid dataset resource id — expected "<projectId>.<dataset>"'
5848
+ >,
5849
+ ]
5850
+ >;
5851
+ },
5852
+ undefined
5853
+ >,
5854
+ v.ObjectSchema<
5855
+ {
5856
+ readonly type: v.LiteralSchema<
5857
+ "canvas",
5858
+ undefined
5859
+ >;
5860
+ readonly id: v.SchemaWithPipe<
5861
+ readonly [
5862
+ v.StringSchema<undefined>,
5863
+ v.NonEmptyAction<
5864
+ string,
5865
+ "must not be empty"
5866
+ >,
5867
+ ]
5868
+ >;
5869
+ },
5870
+ undefined
5871
+ >,
5872
+ v.ObjectSchema<
5873
+ {
5874
+ readonly type: v.LiteralSchema<
5875
+ "media-library",
5876
+ undefined
5877
+ >;
5878
+ readonly id: v.SchemaWithPipe<
5879
+ readonly [
5880
+ v.StringSchema<undefined>,
5881
+ v.NonEmptyAction<
5882
+ string,
5883
+ "must not be empty"
5884
+ >,
5885
+ ]
5886
+ >;
5887
+ },
5888
+ undefined
5889
+ >,
5890
+ v.ObjectSchema<
5891
+ {
5892
+ readonly type: v.LiteralSchema<
5893
+ "dashboard",
5894
+ undefined
5895
+ >;
5896
+ readonly id: v.SchemaWithPipe<
5897
+ readonly [
5898
+ v.StringSchema<undefined>,
5899
+ v.NonEmptyAction<
5900
+ string,
5901
+ "must not be empty"
5902
+ >,
5903
+ ]
5904
+ >;
5905
+ },
5906
+ undefined
5907
+ >,
5908
+ ],
5909
+ undefined
5910
+ >;
5911
+ },
5912
+ undefined
5913
+ >,
5914
+ undefined
5915
+ >,
5916
+ v.CheckAction<
5917
+ {
5918
+ name: string;
5919
+ resource:
5920
+ | {
5921
+ type: "dataset";
5922
+ id: string;
5923
+ }
5924
+ | {
5925
+ type: "canvas";
5926
+ id: string;
5927
+ }
5928
+ | {
5929
+ type: "media-library";
5930
+ id: string;
5931
+ }
5932
+ | {
5933
+ type: "dashboard";
5934
+ id: string;
5935
+ };
5936
+ }[],
5937
+ "duplicate resource handle name — each binding name must be unique within a deployment"
5938
+ >,
5939
+ ]
5940
+ >,
5941
+ undefined
5942
+ >;
5943
+ readonly definitions: v.SchemaWithPipe<
5944
+ readonly [
5945
+ v.ArraySchema<
5946
+ v.CustomSchema<
5947
+ {
5948
+ name: string;
5949
+ title: string;
5950
+ description?: string | undefined;
5951
+ lifecycle?: WorkflowLifecycle | undefined;
5952
+ initialStage: string;
5953
+ fields?: FieldEntry[] | undefined;
5954
+ stages: Stage[];
5955
+ predicates?: Record<string, string> | undefined;
5956
+ roleAliases?: RoleAliases | undefined;
5957
+ },
5958
+ v.ErrorMessage<v.CustomIssue> | undefined
5959
+ >,
5960
+ undefined
5961
+ >,
5962
+ v.MinLengthAction<
5963
+ {
5964
+ name: string;
5965
+ title: string;
5966
+ description?: string | undefined;
5967
+ lifecycle?: WorkflowLifecycle | undefined;
5968
+ initialStage: string;
5969
+ fields?: FieldEntry[] | undefined;
5970
+ stages: Stage[];
5971
+ predicates?: Record<string, string> | undefined;
5972
+ roleAliases?: RoleAliases | undefined;
5973
+ }[],
5974
+ 1,
5975
+ "a deployment needs at least one definition"
5976
+ >,
5977
+ ]
5978
+ >;
5979
+ },
5980
+ undefined
5981
+ >,
5982
+ undefined
5983
+ >,
5984
+ v.MinLengthAction<
5985
+ {
5986
+ name: string;
5987
+ tag: string;
5988
+ workflowResource:
5989
+ | {
5990
+ type: "dataset";
5991
+ id: string;
5992
+ }
5993
+ | {
5994
+ type: "canvas";
5995
+ id: string;
5996
+ }
5997
+ | {
5998
+ type: "media-library";
5999
+ id: string;
6000
+ }
6001
+ | {
6002
+ type: "dashboard";
6003
+ id: string;
6004
+ };
6005
+ resourceAliases?:
6006
+ | {
6007
+ name: string;
6008
+ resource:
6009
+ | {
6010
+ type: "dataset";
6011
+ id: string;
6012
+ }
6013
+ | {
6014
+ type: "canvas";
6015
+ id: string;
6016
+ }
6017
+ | {
6018
+ type: "media-library";
6019
+ id: string;
6020
+ }
6021
+ | {
6022
+ type: "dashboard";
6023
+ id: string;
6024
+ };
6025
+ }[]
6026
+ | undefined;
6027
+ definitions: {
6028
+ name: string;
6029
+ title: string;
6030
+ description?: string | undefined;
6031
+ lifecycle?: WorkflowLifecycle | undefined;
6032
+ initialStage: string;
6033
+ fields?: FieldEntry[] | undefined;
6034
+ stages: Stage[];
6035
+ predicates?: Record<string, string> | undefined;
6036
+ roleAliases?: RoleAliases | undefined;
6037
+ }[];
6038
+ }[],
6039
+ 1,
6040
+ "a config needs at least one deployment"
6041
+ >,
6042
+ v.CheckAction<
6043
+ {
6044
+ name: string;
6045
+ tag: string;
6046
+ workflowResource:
6047
+ | {
6048
+ type: "dataset";
6049
+ id: string;
6050
+ }
6051
+ | {
6052
+ type: "canvas";
6053
+ id: string;
6054
+ }
6055
+ | {
6056
+ type: "media-library";
6057
+ id: string;
6058
+ }
6059
+ | {
6060
+ type: "dashboard";
6061
+ id: string;
6062
+ };
6063
+ resourceAliases?:
6064
+ | {
6065
+ name: string;
6066
+ resource:
6067
+ | {
6068
+ type: "dataset";
6069
+ id: string;
6070
+ }
6071
+ | {
6072
+ type: "canvas";
6073
+ id: string;
6074
+ }
6075
+ | {
6076
+ type: "media-library";
6077
+ id: string;
6078
+ }
6079
+ | {
6080
+ type: "dashboard";
6081
+ id: string;
6082
+ };
6083
+ }[]
6084
+ | undefined;
6085
+ definitions: {
6086
+ name: string;
6087
+ title: string;
6088
+ description?: string | undefined;
6089
+ lifecycle?: WorkflowLifecycle | undefined;
6090
+ initialStage: string;
6091
+ fields?: FieldEntry[] | undefined;
6092
+ stages: Stage[];
6093
+ predicates?: Record<string, string> | undefined;
6094
+ roleAliases?: RoleAliases | undefined;
6095
+ }[];
6096
+ }[],
6097
+ "duplicate deployment tag — each deployment must use a unique tag"
6098
+ >,
6099
+ ]
6100
+ >;
6101
+ },
6102
+ undefined
6103
+ >;
6104
+
5047
6105
  export declare type WorkflowDefinition = v.InferOutput<
5048
6106
  typeof WorkflowDefinitionSchema
5049
6107
  >;
@@ -5065,6 +6123,59 @@ declare const WorkflowDefinitionSchema: v.GenericSchema<
5065
6123
  WorkflowFields<FieldEntry, Stage>
5066
6124
  >;
5067
6125
 
6126
+ export declare type WorkflowDeployment = WorkflowConfig["deployments"][number];
6127
+
6128
+ /**
6129
+ * Base class of the engine's structured errors. `kind` is the stable
6130
+ * discriminant — render on it; `name` mirrors the concrete class for logs.
6131
+ * Each subclass pins its literal via the `K` parameter, so passing a
6132
+ * mismatched kind to `super` is a compile error. Advisory like every engine
6133
+ * check: catching one of these explains a refusal, it does not enforce
6134
+ * anything.
6135
+ */
6136
+ export declare abstract class WorkflowError<
6137
+ K extends WorkflowErrorKind = WorkflowErrorKind,
6138
+ > extends Error {
6139
+ readonly kind: K;
6140
+ constructor(kind: K, message: string, options?: ErrorOptions);
6141
+ }
6142
+
6143
+ /**
6144
+ * The engine's error model — one base class, one discriminant.
6145
+ *
6146
+ * Every structured error the engine throws at a caller extends
6147
+ * {@link WorkflowError} and carries a {@link WorkflowErrorKind}, so a consumer
6148
+ * can write ONE catch-and-render path: `instanceof WorkflowError`, then switch
6149
+ * on `kind` (or `instanceof` a concrete class to read its typed payload). The
6150
+ * model covers the runtime verbs' refusals, denials, races and lookups.
6151
+ * Three things deliberately stay plain `Error`: deploy/authoring validation
6152
+ * (a structured issue-report design of its own), transient transport
6153
+ * failures (retryable, carrying `cause` — not engine verdicts), and internal
6154
+ * invariant violations (the remediation is a bug report, not a catch branch).
6155
+ *
6156
+ * How thrown errors relate to the read-side verdicts is documented on
6157
+ * {@link DisabledReason}.
6158
+ */
6159
+ export declare type WorkflowErrorKind =
6160
+ | "action-disabled"
6161
+ | "edit-field-denied"
6162
+ | "mutation-guard-denied"
6163
+ | "action-params-invalid"
6164
+ | "effect-ops-invalid"
6165
+ | "required-field-not-provided"
6166
+ | "workflow-state-diverged"
6167
+ | "partial-guard-deploy"
6168
+ | "concurrent-fire-action"
6169
+ | "concurrent-edit-field"
6170
+ | "cascade-limit"
6171
+ | "field-value-shape"
6172
+ | "instance-not-found"
6173
+ | "definition-not-found"
6174
+ | "definition-in-use"
6175
+ | "effect-not-found"
6176
+ | "missing-effect-handler"
6177
+ | "contract-violation";
6178
+
5068
6179
  export declare interface WorkflowEvaluation {
5069
6180
  instance: WorkflowInstance;
5070
6181
  definition: WorkflowDefinition;
@@ -5075,12 +6186,12 @@ export declare interface WorkflowEvaluation {
5075
6186
  /** True if at least one action on any active activity is allowed. */
5076
6187
  canInteract: boolean;
5077
6188
  /**
5078
- * Declared-editable slots in the current scope (workflow + current stage +
6189
+ * Declared-editable fields in the current scope (workflow + current stage +
5079
6190
  * its activities), each with this actor's edit verdict and the current value's
5080
6191
  * provenance. The reactive edit-seam surface; empty when the workflow
5081
- * declares no editable slots.
6192
+ * declares no editable fields.
5082
6193
  */
5083
- editableSlots: EditableSlotEvaluation[];
6194
+ editableFields: EditableFieldEvaluation[];
5084
6195
  }
5085
6196
 
5086
6197
  export declare interface WorkflowFetchOptions {
@@ -5097,7 +6208,7 @@ declare type WorkflowFields<TField, TStage> = {
5097
6208
  name: string;
5098
6209
  title: string;
5099
6210
  description?: string | undefined;
5100
- role?: WorkflowRole | undefined;
6211
+ lifecycle?: WorkflowLifecycle | undefined;
5101
6212
  initialStage: string;
5102
6213
  fields?: TField[] | undefined;
5103
6214
  stages: TStage[];
@@ -5192,6 +6303,11 @@ export declare interface WorkflowInstance extends SanityDocument {
5192
6303
  abortedAt?: string;
5193
6304
  }
5194
6305
 
6306
+ /** How instances of a definition come to exist: started standalone (the
6307
+ * default) or spawned by a parent. `'child'` is spawn-only — see
6308
+ * {@link isStartableDefinition}. */
6309
+ export declare type WorkflowLifecycle = (typeof WORKFLOW_LIFECYCLES)[number];
6310
+
5195
6311
  /**
5196
6312
  * The subset of `@sanity/client` the engine actually needs. The
5197
6313
  * `@sanity-labs/client-fake-for-test` TestClient is
@@ -5257,9 +6373,6 @@ export declare type WorkflowResource =
5257
6373
  id: string;
5258
6374
  };
5259
6375
 
5260
- /** A definition's lifecycle role. `'child'` is spawn-only — see {@link isStartableDefinition}. */
5261
- export declare type WorkflowRole = (typeof WORKFLOW_ROLES)[number];
5262
-
5263
6376
  /**
5264
6377
  * Thrown when a guard deploy fails *after* its state move committed and the
5265
6378
  * engine could not cleanly undo the result — any of: the rollback write itself
@@ -5270,7 +6383,7 @@ export declare type WorkflowRole = (typeof WORKFLOW_ROLES)[number];
5270
6383
  * need manual reconciliation; the engine screams rather than leaving the
5271
6384
  * inconsistency silent.
5272
6385
  */
5273
- export declare class WorkflowStateDivergedError extends Error {
6386
+ export declare class WorkflowStateDivergedError extends WorkflowError<"workflow-state-diverged"> {
5274
6387
  readonly instanceId: string;
5275
6388
  /** The guard-deploy failure that triggered the (attempted) rollback. */
5276
6389
  readonly guardError: unknown;