@sanity/workflow-engine 0.28.0 → 0.30.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.d.ts CHANGED
@@ -57,6 +57,12 @@ export declare function acceptsDocumentType(
57
57
  documentType: string,
58
58
  ): boolean;
59
59
 
60
+ /** A parsed deployment after its reader-model acknowledgement has been
61
+ * validated against the definitions a command will submit. */
62
+ export declare type AcknowledgedWorkflowDeployment = WorkflowDeployment & {
63
+ expectedMinReaderModel: number;
64
+ };
65
+
60
66
  /**
61
67
  * The URL path a resource's ACL is served at — where the engine fetches an
62
68
  * actor's grants for that resource (and the canonical encoding of the shape
@@ -79,6 +85,21 @@ export declare function aclPathForResource(
79
85
  res: WorkflowResource,
80
86
  ): string | undefined;
81
87
 
88
+ /**
89
+ * A stored action. `semantics` is engine-owned advisory meaning, independent
90
+ * of execution and presentation — an array so the vocabulary can grow without
91
+ * reshaping this field. `when`'s presence makes the action CASCADE-FIRED: the
92
+ * engine fires it the moment the condition turns true, at most once per stage
93
+ * visit, and it is never invocable via `fireAction`; absent, the action must
94
+ * be invoked via `fireAction` by any caller holding a token (fire-on-entry is
95
+ * `when: 'true'`). `filter` is existence with GROQ semantics — a non-matching
96
+ * action might as well not exist (invisible to UI and LLMs, never merely
97
+ * disabled); on a `when` action it composes: `filter` scopes whether the
98
+ * automation exists, `when` is its firing trigger. `roles` is kept VERBATIM
99
+ * only when cascade-fired (the pin on which identities may execute the
100
+ * trigger); a fireAction-fired action's `roles` folds into `filter` at
101
+ * desugar instead.
102
+ */
82
103
  export declare type Action = ActionFields<Op, string[]> & {
83
104
  roles?: string[] | undefined;
84
105
  };
@@ -86,6 +107,9 @@ export declare type Action = ActionFields<Op, string[]> & {
86
107
  export declare const ACTION_SEMANTICS: readonly [
87
108
  "decision.accept",
88
109
  "decision.decline",
110
+ "signal.positive",
111
+ "signal.caution",
112
+ "signal.critical",
89
113
  ];
90
114
 
91
115
  /**
@@ -181,14 +205,14 @@ declare type ActionFields<TOp, TGroup> = {
181
205
 
182
206
  export declare type ActionName = string;
183
207
 
184
- export declare type ActionParam = v.InferOutput<typeof ActionParamSchema>;
185
-
186
208
  /**
187
- * Caller-supplied params declared on an action. The engine validates
188
- * incoming `params` against this list before running ops or queuing
189
- * effects: missing required params ActionParamsInvalidError, action
190
- * does not commit. Resolved values feed `ValueExpr.param` lookups.
209
+ * Caller-supplied params declared on an action, validated before running ops
210
+ * or queuing effects: a missing required param throws
211
+ * `ActionParamsInvalidError` and the action does not commit. Resolved values
212
+ * feed `ValueExpr.param` lookups.
191
213
  */
214
+ export declare type ActionParam = v.InferOutput<typeof ActionParamSchema>;
215
+
192
216
  declare const ActionParamSchema: v.SchemaWithPipe<
193
217
  readonly [
194
218
  v.StrictObjectSchema<
@@ -358,19 +382,28 @@ export declare function actionRendering(action: {
358
382
  | undefined;
359
383
  }): "absent" | "automation" | "button";
360
384
 
361
- export declare type ActionSemantic = (typeof ACTION_SEMANTICS)[number];
385
+ export declare type ActionSemantic = DecisionSemantic | Semantic;
362
386
 
363
- /** The fireable-action verdict for one action on an activity — its `allowed`
364
- * state, structured `disabledReason`, and declared params, tagged with the
365
- * owning activity. The per-action atom both projections share:
366
- * {@link availableActions} flattens it across a stage's activities; a consumer
367
- * that keeps per-activity nesting (e.g. the MCP) maps it over an activity's actions
368
- * directly, so the verdict shape has a single source. */
387
+ /** The per-action verdict shape shared by every projection: {@link availableActions} flattens it, a per-activity consumer (e.g. the MCP) maps it directly both must stay on this one builder. */
369
388
  export declare function actionVerdict(
370
389
  activity: ActivityEvaluation,
371
390
  action: ActionEvaluation,
372
391
  ): AvailableAction;
373
392
 
393
+ /**
394
+ * A unit of work carrying no payload of its own — every op, effect, and
395
+ * spawn lives on an action; an activity contributes scoped `fields`
396
+ * (resolved at stage entry), existence (`filter`), advisory readiness
397
+ * (`requirements`), and the off-system marker (`target`, a BPMN Manual Task
398
+ * deep-link, render-only and never gating). All in-scope activities are
399
+ * ACTIVE from stage entry until an action's terminal `status` resolves them —
400
+ * there is no activation moment. `filter` is existence with GROQ semantics,
401
+ * evaluated once against the stage's entry state: a definite `false`
402
+ * excludes the activity from UI, LLMs, and `$allActivitiesDone`.
403
+ * `requirements` are readiness gates orthogonal to `filter` — an unmet one
404
+ * keeps the activity visible but disables its actions with a
405
+ * `requirements-unmet` verdict; distinct from ACL and guards.
406
+ */
374
407
  export declare type Activity = ActivityFields<
375
408
  FieldEntry,
376
409
  Action,
@@ -407,6 +440,12 @@ export declare const ACTIVITY_KIND_DISPLAY: {
407
440
  };
408
441
  };
409
442
 
443
+ /**
444
+ * BPMN-aligned classification of an activity by its EXECUTOR. Purely
445
+ * advisory and always DERIVED from the activity's shape (`target` marks
446
+ * off-system manual work, action shapes decide the rest) — it changes no
447
+ * gating or runtime.
448
+ */
410
449
  export declare const ACTIVITY_KINDS: readonly [
411
450
  "user",
412
451
  "service",
@@ -416,13 +455,10 @@ export declare const ACTIVITY_KINDS: readonly [
416
455
  ];
417
456
 
418
457
  /**
419
- * Leaf enums the const arrays (and their derived union types) that both
420
- * the authoring schema and the engine address by name.
421
- *
422
- * This module imports nothing. It is the schema-free foundation that
423
- * `../define/schema.ts` reads its value constants from, which is what keeps
424
- * the type model and the valibot schema free of an import cycle: the value edge
425
- * `schema.ts → enums.ts` terminates here.
458
+ * An activity is `active` from stage entry (or `skipped` when its `filter`
459
+ * excluded it) until a terminal status resolves it — there is no pre-active
460
+ * state. The authored action `status:` sugar (and the `status.set` op it
461
+ * desugars to) is constrained to {@link TerminalActivityStatus}.
426
462
  */
427
463
  declare const ACTIVITY_STATUSES: readonly [
428
464
  "active",
@@ -478,6 +514,8 @@ export declare interface ActivityEntry {
478
514
 
479
515
  export declare interface ActivityEvaluation {
480
516
  activity: Activity;
517
+ /** The activity's advisory workflow meaning, unchanged from its definition. */
518
+ semantics?: Semantic[] | undefined;
481
519
  status: ActivityStatus;
482
520
  /**
483
521
  * The activity's shape-derived {@link ActivityKind}. Advisory: a label so a
@@ -529,6 +567,7 @@ export declare interface ActivityEvaluation {
529
567
  /** Type-mirror of {@link activityFields}, parameterised over field/action/target/group. */
530
568
  declare type ActivityFields<TField, TAction, TTarget, TGroup> = {
531
569
  name: string;
570
+ semantics?: Semantic[] | undefined;
532
571
  title?: string | undefined;
533
572
  description?: string | undefined;
534
573
  groups?: Group[] | undefined;
@@ -587,8 +626,24 @@ export declare interface Actor {
587
626
  onBehalfOf?: string;
588
627
  }
589
628
 
629
+ /**
630
+ * WHO is acting: a human, an LLM, or automated machinery. The `system` kind
631
+ * covers both the engine's own housekeeping and external services;
632
+ * {@link DriverKind} splits that for the audit-trail glyph.
633
+ */
590
634
  export declare const ACTOR_KINDS: readonly ["person", "agent", "system"];
591
635
 
636
+ /** Runtime counterpart of {@link expandRequiredRoles}; both expand only the required side. */
637
+ export declare function actorFulfillsRole({
638
+ actorRoles,
639
+ required,
640
+ aliases,
641
+ }: {
642
+ actorRoles: readonly string[] | undefined;
643
+ required: string;
644
+ aliases: RoleAliases | undefined;
645
+ }): boolean;
646
+
592
647
  export declare type ActorKind = (typeof ACTOR_KINDS)[number];
593
648
 
594
649
  export declare type ActorResolution<User> =
@@ -646,16 +701,9 @@ export declare function applicableDefinitions<
646
701
  }): Promise<T[]>;
647
702
 
648
703
  /**
649
- * The data-model gate every engine read of an engine-owned document passes
650
- * through point reads, list queries, projections, and snapshot hydration's
651
- * raw reads (the structural exceptionsexistence-only probes and lake-side
652
- * GROQ filters — are declared in DATAMODEL.md). Throws
653
- * {@link ModelVersionAheadError} only when the document's
654
- * {@link minReaderModelOf reader floor} is ahead of
655
- * {@link DATA_MODEL_VERSION}; a doc stamped by a NEWER model whose changes
656
- * were additive keeps its old floor and reads fine — mixed-version fleets
657
- * interoperate across additive evolution. A missing stamp is model 0 and
658
- * always readable.
704
+ * Throws {@link ModelVersionAheadError} only when the document's reader floor exceeds
705
+ * {@link DATA_MODEL_VERSION}. A doc from a NEWER engine whose changes were purely additive
706
+ * keeps its old (lower) floor and still reads fine — only reader-floor-raising changes block a read.
659
707
  */
660
708
  export declare function assertReadableModel<
661
709
  T extends {
@@ -665,8 +713,11 @@ export declare function assertReadableModel<
665
713
 
666
714
  export declare function assertReaderModelAcknowledgement(
667
715
  expectedMinReaderModel: unknown,
668
- context?: string,
669
- ): asserts expectedMinReaderModel is typeof DATA_MODEL_MIN_READER;
716
+ options: {
717
+ requiredMinReaderModel: number;
718
+ context?: string;
719
+ },
720
+ ): asserts expectedMinReaderModel is number;
670
721
 
671
722
  /**
672
723
  * One member of an `assignees`-kind entry's value — and the value of the
@@ -714,6 +765,18 @@ export declare const AUTHORING_DISPLAY: {
714
765
  };
715
766
  };
716
767
 
768
+ /**
769
+ * The stored action fields plus two authoring sugars, or the
770
+ * {@link ClaimAction} pair-half. `roles`: on a fireAction-fired action (no
771
+ * `when`) it desugars into a `count($actor.roles[@ in [...]]) > 0` condition
772
+ * ANDed with `filter`; on a CASCADE-FIRED action it stores VERBATIM instead —
773
+ * the pin on which identities may execute the trigger, since folding it into
774
+ * `filter` would make the action's existence depend on whose token cascades.
775
+ * `roleAliases` widens the membership either way. `status` compiles to a
776
+ * `status.set` op on the firing activity, appended AFTER the authored ops —
777
+ * deliberately never implied, so a forgotten `status` is a visible stall
778
+ * rather than a silently completed action.
779
+ */
717
780
  export declare type AuthoringAction = AuthoringRawAction | ClaimAction;
718
781
 
719
782
  export declare type AuthoringActivity = ActivityFields<
@@ -723,16 +786,16 @@ export declare type AuthoringActivity = ActivityFields<
723
786
  GroupMembership
724
787
  >;
725
788
 
726
- export declare type AuthoringEditable = v.InferOutput<
727
- typeof AuthoringEditableSchema
728
- >;
729
-
730
789
  /**
731
790
  * Authoring editability adds the `role[]` convenience: a non-empty role list
732
791
  * desugars to the same `count($actor.roles[@ in [...]]) > 0` membership
733
792
  * predicate `action.roles` produces. `true` opens the field to anyone in its
734
793
  * window; a bare string is a raw predicate.
735
794
  */
795
+ export declare type AuthoringEditable = v.InferOutput<
796
+ typeof AuthoringEditableSchema
797
+ >;
798
+
736
799
  declare const AuthoringEditableSchema: v.UnionSchema<
737
800
  [
738
801
  v.LiteralSchema<true, undefined>,
@@ -761,6 +824,8 @@ export declare type AuthoringFieldEntry =
761
824
  | TodoListField
762
825
  | NotesField;
763
826
 
827
+ /** A field reference with `scope` optional; desugar resolves it lexically
828
+ * (activity → stage → workflow) into {@link StoredFieldRef}. */
764
829
  declare type AuthoringFieldRef = v.InferOutput<typeof AuthoringFieldRefSchema>;
765
830
 
766
831
  declare const AuthoringFieldRefSchema: v.StrictObjectSchema<
@@ -779,15 +844,12 @@ declare const AuthoringFieldRefSchema: v.StrictObjectSchema<
779
844
  undefined
780
845
  >;
781
846
 
847
+ /** {@link Guard}'s contract as authored: `match.idRefs` and `metadata` carry
848
+ * typed {@link GuardRead} values that deploy resolves to bare ones. */
782
849
  export declare type AuthoringGuard = v.InferOutput<typeof AuthoringGuardSchema>;
783
850
 
784
851
  declare const AuthoringGuardSchema: v.StrictObjectSchema<
785
852
  {
786
- /**
787
- * Lake-id-segment grammar (`^[a-z0-9][a-z0-9-]*$`, deploy-enforced): the
788
- * guard's lake `_id` derives from `(instanceId, name)` at stage entry.
789
- * Unique per definition.
790
- */
791
853
  name: v.SchemaWithPipe<
792
854
  readonly [
793
855
  v.StringSchema<undefined>,
@@ -798,7 +860,6 @@ declare const AuthoringGuardSchema: v.StrictObjectSchema<
798
860
  description: v.OptionalSchema<v.StringSchema<undefined>, undefined>;
799
861
  match: v.StrictObjectSchema<
800
862
  {
801
- /** Subject `_type`(s); empty matches any type. */
802
863
  types: v.OptionalSchema<
803
864
  v.ArraySchema<
804
865
  v.SchemaWithPipe<
@@ -811,7 +872,6 @@ declare const AuthoringGuardSchema: v.StrictObjectSchema<
811
872
  >,
812
873
  undefined
813
874
  >;
814
- /** Target docs as field reads (or the instance itself), resolved at deploy to bare ids + the resource. */
815
875
  idRefs: v.OptionalSchema<
816
876
  v.ArraySchema<
817
877
  v.VariantSchema<
@@ -914,7 +974,6 @@ declare const AuthoringGuardSchema: v.StrictObjectSchema<
914
974
  >,
915
975
  undefined
916
976
  >;
917
- /** Glob id patterns (bare, resource-local). */
918
977
  idPatterns: v.OptionalSchema<
919
978
  v.ArraySchema<
920
979
  v.SchemaWithPipe<
@@ -946,22 +1005,7 @@ declare const AuthoringGuardSchema: v.StrictObjectSchema<
946
1005
  },
947
1006
  undefined
948
1007
  >;
949
- /**
950
- * Lake GROQ predicate — a distinct eval context: delta-mode GROQ
951
- * reading the `before()`/`after()` natives, `mutation`, `guard`, and
952
- * `identity()`. Bare ids/fields only. Polarity: a result of strictly
953
- * `true` ALLOWS the matched mutation; anything else (false, null, an
954
- * evaluation error) DENIES. Omitted or empty means UNCONDITIONAL DENY.
955
- */
956
1008
  predicate: v.OptionalSchema<v.StringSchema<undefined>, undefined>;
957
- /**
958
- * Projected workflow fields the predicate reads as `guard.metadata.*` —
959
- * the only bridge from the lake eval context (which cannot see `$fields`)
960
- * to workflow fields. Each value is a deploy-time read — a typed
961
- * {@link GuardRead} when authoring, the printed string spelling once
962
- * stored — resolved into a bare value at deploy and re-synced by the
963
- * post-field-op guard refresh.
964
- */
965
1009
  metadata: v.OptionalSchema<
966
1010
  v.RecordSchema<
967
1011
  v.SchemaWithPipe<
@@ -1071,6 +1115,8 @@ declare const AuthoringGuardSchema: v.StrictObjectSchema<
1071
1115
  undefined
1072
1116
  >;
1073
1117
 
1118
+ /** Like {@link ManualTarget}, but the `field` variant also accepts a bare
1119
+ * field name; desugar normalises it into {@link AuthoringFieldRef}. */
1074
1120
  export declare type AuthoringManualTarget = v.InferOutput<
1075
1121
  typeof AuthoringManualTargetSchema
1076
1122
  >;
@@ -1130,6 +1176,9 @@ declare const AuthoringManualTargetSchema: v.VariantSchema<
1130
1176
  undefined
1131
1177
  >;
1132
1178
 
1179
+ /** Like {@link Op}, plus: `status.set`'s `activity` is optional (desugar fills
1180
+ * the firing activity), and the `audit` sugar — a stamped append merging
1181
+ * `actor`/`at` {@link ValueExpr} fields into its own value. */
1133
1182
  export declare type AuthoringOp = v.InferOutput<typeof AuthoringOpSchema>;
1134
1183
 
1135
1184
  declare const AuthoringOpSchema: v.VariantSchema<
@@ -1160,6 +1209,31 @@ declare const AuthoringOpSchema: v.VariantSchema<
1160
1209
  },
1161
1210
  undefined
1162
1211
  >,
1212
+ v.StrictObjectSchema<
1213
+ {
1214
+ readonly type: v.LiteralSchema<"field.setIfMissing", undefined>;
1215
+ readonly target: v.StrictObjectSchema<
1216
+ {
1217
+ readonly scope: v.OptionalSchema<
1218
+ v.PicklistSchema<
1219
+ readonly ["workflow", "stage", "activity"],
1220
+ string
1221
+ >,
1222
+ undefined
1223
+ >;
1224
+ readonly field: v.SchemaWithPipe<
1225
+ readonly [
1226
+ v.StringSchema<undefined>,
1227
+ v.MinLengthAction<string, 1, "must be a non-empty string">,
1228
+ ]
1229
+ >;
1230
+ },
1231
+ undefined
1232
+ >;
1233
+ readonly value: v.GenericSchema<ValueExprInternal>;
1234
+ },
1235
+ undefined
1236
+ >,
1163
1237
  v.StrictObjectSchema<
1164
1238
  {
1165
1239
  readonly type: v.LiteralSchema<"field.unset", undefined>;
@@ -1209,6 +1283,62 @@ declare const AuthoringOpSchema: v.VariantSchema<
1209
1283
  },
1210
1284
  undefined
1211
1285
  >,
1286
+ v.StrictObjectSchema<
1287
+ {
1288
+ readonly type: v.LiteralSchema<"field.inc", undefined>;
1289
+ readonly target: v.StrictObjectSchema<
1290
+ {
1291
+ readonly scope: v.OptionalSchema<
1292
+ v.PicklistSchema<
1293
+ readonly ["workflow", "stage", "activity"],
1294
+ string
1295
+ >,
1296
+ undefined
1297
+ >;
1298
+ readonly field: v.SchemaWithPipe<
1299
+ readonly [
1300
+ v.StringSchema<undefined>,
1301
+ v.MinLengthAction<string, 1, "must be a non-empty string">,
1302
+ ]
1303
+ >;
1304
+ },
1305
+ undefined
1306
+ >;
1307
+ readonly value: v.OptionalSchema<
1308
+ v.GenericSchema<ValueExprInternal>,
1309
+ undefined
1310
+ >;
1311
+ },
1312
+ undefined
1313
+ >,
1314
+ v.StrictObjectSchema<
1315
+ {
1316
+ readonly type: v.LiteralSchema<"field.dec", undefined>;
1317
+ readonly target: v.StrictObjectSchema<
1318
+ {
1319
+ readonly scope: v.OptionalSchema<
1320
+ v.PicklistSchema<
1321
+ readonly ["workflow", "stage", "activity"],
1322
+ string
1323
+ >,
1324
+ undefined
1325
+ >;
1326
+ readonly field: v.SchemaWithPipe<
1327
+ readonly [
1328
+ v.StringSchema<undefined>,
1329
+ v.MinLengthAction<string, 1, "must be a non-empty string">,
1330
+ ]
1331
+ >;
1332
+ },
1333
+ undefined
1334
+ >;
1335
+ readonly value: v.OptionalSchema<
1336
+ v.GenericSchema<ValueExprInternal>,
1337
+ undefined
1338
+ >;
1339
+ },
1340
+ undefined
1341
+ >,
1212
1342
  v.StrictObjectSchema<
1213
1343
  {
1214
1344
  readonly type: v.LiteralSchema<"field.updateWhere", undefined>;
@@ -1344,27 +1474,6 @@ declare const AuthoringOpSchema: v.VariantSchema<
1344
1474
  undefined
1345
1475
  >;
1346
1476
 
1347
- /**
1348
- * Authoring action — the stored fields plus two field sugars with one
1349
- * defined expansion each:
1350
- *
1351
- * - `roles` — on a fireAction-fired action (no `when`) it desugars to a
1352
- * `count($actor.roles[@ in [...]]) > 0` membership condition ANDed with
1353
- * the authored `filter` (for a caller, "not yours to fire" and "doesn't
1354
- * exist for you" are the same advisory answer). On a CASCADE-FIRED
1355
- * action it stores VERBATIM — the pin on which identities may execute
1356
- * the trigger; folding it into `filter` would make the action's
1357
- * existence depend on whose token happens to cascade. The definition's
1358
- * `roleAliases` ({@link RoleAliasesSchema}) widen the membership either
1359
- * way.
1360
- * - `status` → a `status.set` op on the firing activity, appended **after**
1361
- * the authored ops (deliberately never implied: a forgotten explicit
1362
- * `status` is a visible stall, an implied default silently completes
1363
- * claim-like actions). Status is the health axis: a decision action
1364
- * (decline, send back) resolves `done` and writes the decision into a
1365
- * field the transition trigger reads — `failed` is for work that
1366
- * genuinely could not complete.
1367
- */
1368
1477
  declare type AuthoringRawAction = ActionFields<AuthoringOp, GroupMembership> & {
1369
1478
  roles?: string[] | undefined;
1370
1479
  status?: TerminalActivityStatus | undefined;
@@ -1492,31 +1601,21 @@ export declare interface AvailableAction {
1492
1601
  params: ActionParam[];
1493
1602
  }
1494
1603
 
1495
- /** Flatten an evaluation's current-stage activities into the actions the actor
1496
- * could fire, each carrying whether it's allowed (and why not). A
1497
- * filter-scoped-out activity does not exist for this visit, so its actions
1498
- * never list — the same {@link ActivityEvaluation.scopedOut} split every
1499
- * other surface applies. */
1604
+ /** Excludes a `scopedOut` activity's actions, matching the same split every other surface applies to filter-scoped-out activities. */
1500
1605
  export declare function availableActions(
1501
1606
  activities: ActivityEvaluation[],
1502
1607
  ): AvailableAction[];
1503
1608
 
1504
- /** The `workflow.availableActions` result the projected actions plus the
1505
- * evaluation they came from, so a consumer can read the instance/stage
1506
- * context without a second projection. */
1609
+ /** Pairs the projected actions with the evaluation they came from, so a consumer reads instance/stage context without a second call. */
1507
1610
  export declare interface AvailableActionsResult {
1508
1611
  evaluation: WorkflowEvaluation;
1509
1612
  actions: AvailableAction[];
1510
1613
  }
1511
1614
 
1512
- /**
1513
- * Type each caller-supplied name→value against the workflow's declared field
1514
- * entries — the engine takes typed {@link InitialFieldValue}s, and a value's
1515
- * type IS its declared entry's kind. Only `input`-sourced entries read caller
1516
- * values, so anything else fails here, naming the fields that ARE settable.
1517
- * The engine repeats this structural validation at its contract boundary;
1518
- * value validation also stays there.
1519
- */
1615
+ /** Builds the start payload's field rows from caller values: accepts only
1616
+ * declared `input`-sourced entries and throws on an unknown or non-input
1617
+ * name. Structural validation only — the engine repeats value-kind
1618
+ * validation at its own start boundary, not here. */
1520
1619
  export declare function buildInitialFields({
1521
1620
  declared,
1522
1621
  values,
@@ -1526,18 +1625,8 @@ export declare function buildInitialFields({
1526
1625
  }): InitialFieldValue[];
1527
1626
 
1528
1627
  /**
1529
- * Build a snapshot from a set of loaded docs. Pure transform.
1530
- *
1531
- * For each `LoadedDoc { doc, resource }`:
1532
- * - The doc's `_id` is rewritten to `gdrFromResource(resource, _id)`.
1533
- * - Every nested `_ref` value (recursively, through objects and arrays)
1534
- * is rewritten the same way: bare ref → URI in the parent's resource.
1535
- * Already-qualified `_ref` URIs (containing `:`) are left alone.
1536
- *
1537
- * Plain string fields, numbers, booleans — anything that isn't an
1538
- * object with a `_ref` field — pass through untouched. The rewriter is
1539
- * structural, not schema-aware: only the `_ref` field on an object is
1540
- * treated as a Sanity reference. Everything else is user data.
1628
+ * Rewrites each doc's `_id` and every nested `_ref` field to GDR URI form,
1629
+ * recursing through objects/arrays; already-URI `_ref`s pass through unchanged.
1541
1630
  */
1542
1631
  export declare function buildSnapshot(args: {
1543
1632
  docs: LoadedDoc[];
@@ -1590,14 +1679,8 @@ export declare interface ChoiceOptions {
1590
1679
 
1591
1680
  export declare type ChoiceValue = string | number;
1592
1681
 
1593
- /**
1594
- * The action half of the mirrored claim pair. `field` references an
1595
- * author-declared actor-valued entry (the pair's other half), resolved
1596
- * lexically. Expansion, strictly within this action: a no-steal
1597
- * `!defined($fields.<field>)` filter ANDed with `roles`/`filter`, plus a
1598
- * `field.set` ← actor op. `ops` and `status` are reserved (the expansion
1599
- * owns them) — strictObject rejects them as unknown keys.
1600
- */
1682
+ /** The action half of the mirrored claim pair: `field` names the actor-valued entry this action claims, resolved lexically, and the expansion
1683
+ * adds a no-steal `!defined($fields.<field>)` filter ANDed with `roles`/`filter` plus a `field.set` actor op. `ops`/`status` are reserved (strictObject rejects them). */
1601
1684
  declare type ClaimAction = {
1602
1685
  type: "claim";
1603
1686
  name: string;
@@ -1611,12 +1694,8 @@ declare type ClaimAction = {
1611
1694
  effects?: Effect[] | undefined;
1612
1695
  };
1613
1696
 
1614
- /**
1615
- * Authoring fields accept the raw entries plus the `claim` sugar type the
1616
- * field half of the mirrored claim pair. Expansion: an `actor` working-
1617
- * memory field (no `initialValue`; the claim action's op fills it), strictly
1618
- * within this entry.
1619
- */
1697
+ /** The field half of the mirrored claim pair, expanding strictly within this entry: an `actor`
1698
+ * working-memory field with no `initialValue` the paired {@link ClaimAction}'s op fills it. */
1620
1699
  declare type ClaimField = {
1621
1700
  type: "claim";
1622
1701
  name: string;
@@ -1683,14 +1762,9 @@ export declare interface ClientProjectUser {
1683
1762
  readonly email?: string;
1684
1763
  readonly imageUrl?: string | null;
1685
1764
  /**
1686
- * Which identity provider the person signs in with (`google`, `github`, or a
1687
- * `saml-<name>` deployment)display only.
1688
- *
1689
- * Both spellings are declared because the two project-user endpoints
1690
- * disagree: the project-hosted `/users/<id>` the adapters read answers
1691
- * `provider`, while the management `/projects/<id>/users/<id>` answers
1692
- * `loginProvider`. Read them through {@link userLoginProvider} rather than
1693
- * picking one.
1765
+ * Display only. Both spellings exist because the two project-user
1766
+ * endpoints disagree on which they answer read through
1767
+ * {@link userLoginProvider} rather than picking one.
1694
1768
  */
1695
1769
  readonly provider?: string;
1696
1770
  readonly loginProvider?: string;
@@ -1788,10 +1862,7 @@ export declare interface CompiledQuery {
1788
1862
  params: Record<string, string | string[]>;
1789
1863
  }
1790
1864
 
1791
- /** Assemble a persisted guard doc from resolved pieces. Deliberately carries
1792
- * NO engine data-model stamp: the guard doc format is the lake's forthcoming
1793
- * contract, not ours to grow fields on — its versioning event is the
1794
- * {@link GUARD_DOC_TYPE} cutover itself (see DATAMODEL.md). */
1865
+ /** Deliberately carries NO engine data-model stamp: the guard doc format is the lake's forthcoming contract, not ours to grow fields on (see DATAMODEL.md). */
1795
1866
  export declare function compileGuard(args: CompileGuardArgs): MutationGuardDoc;
1796
1867
 
1797
1868
  declare interface CompileGuardArgs extends MutationGuardBody {
@@ -1945,10 +2016,23 @@ export declare class ConcurrentFireActionError extends WorkflowError<"concurrent
1945
2016
  export declare type Condition = string;
1946
2017
 
1947
2018
  /**
1948
- * Every variable the engine binds for conditions, in one place. The
1949
- * deploy-time shadow check ({@link RESERVED_CONDITION_VARS}) and the docs on
1950
- * {@link Condition} derive from this list — extend it here when the engine
1951
- * grows a binding, never in a comment elsewhere.
2019
+ * Every variable the engine binds for the RENDERED condition scope (every
2020
+ * condition site: transition `when`s, activity filters, action
2021
+ * `when`s/filters, effect bindings, `spawn` reads, where-op `where`s,
2022
+ * editability predicates, author predicates) the deploy-time shadow check
2023
+ * ({@link RESERVED_CONDITION_VARS}) and the docs on {@link Condition} derive
2024
+ * from this list; extend it here when the engine grows a binding, never in
2025
+ * a comment elsewhere.
2026
+ *
2027
+ * Three other GROQ contexts read a definition and do NOT share this
2028
+ * inventory: cascade gates (transition/activity/cascade-action gates, which
2029
+ * must resolve identically regardless of caller — only the `'always'`-bound
2030
+ * subset carries values, {@link FILTER_SCOPE_VARS}); the start contexts
2031
+ * (`start.filter` is browse-time-pure over a candidate document,
2032
+ * {@link START_FILTER_VARS}; a start `groq` requirement binds `$fields`
2033
+ * instead, {@link START_REQUIREMENT_VARS}); and lake guard predicates, which
2034
+ * are not conditions at all — delta-mode GROQ over a mutation, binding
2035
+ * {@link GUARD_PREDICATE_VARS} instead.
1952
2036
  */
1953
2037
  export declare const CONDITION_VARS: readonly ConditionVar[];
1954
2038
 
@@ -1960,13 +2044,10 @@ export { ConditionClause };
1960
2044
 
1961
2045
  export { ConditionDescription };
1962
2046
 
1963
- /**
1964
- * Every STATIC `$fields.<name>` (or `$fields['<name>']` groq-js normalises
1965
- * both to `AccessAttribute`) read in a condition, from the AST. Dynamic access
1966
- * (`$fields[$var]`) carries no static name and is not collected. A malformed
1967
- * condition reads nothing here ({@link conditionSyntaxIssues} owns the parse
1968
- * error).
1969
- */
2047
+ /** Static `$fields.<name>` / `$fields['<name>']` reads (both normalise to the
2048
+ * same AST node); `$fields[$var]` dynamic access has no static name and is skipped.
2049
+ * A malformed condition reads nothing here rather than throwing the deploy-time
2050
+ * syntax check owns the parse error. */
1970
2051
  export declare function conditionFieldReadNames(
1971
2052
  groq: string,
1972
2053
  ): ReadonlySet<string>;
@@ -2002,43 +2083,6 @@ export declare interface ConditionVar {
2002
2083
  label: string;
2003
2084
  }
2004
2085
 
2005
- /**
2006
- * The condition-variable inventory — the single source of truth for every
2007
- * `$var` the engine binds when it evaluates a {@link Condition}.
2008
- *
2009
- * Four evaluation contexts read a definition's GROQ:
2010
- *
2011
- * 1. **Rendered condition scope** — every condition site in a definition
2012
- * (transition `when`s, activity filters, action `when`s/filters, effect
2013
- * bindings, `spawn` reads, where-op `where`s, editability predicates,
2014
- * author predicates). {@link CONDITION_VARS} is its inventory; each
2015
- * entry's `binding` says when the var actually holds a value. The
2016
- * where-op context is the one closed subset — its bound set is statically
2017
- * fixed and deploy-enforced (see the op-where scope's param-name list in
2018
- * the op applier).
2019
- * 2. **Cascade gates** — transition `when`s, activity filters, and a
2020
- * cascade-fired action's `when`/`filter` must resolve identically no
2021
- * matter whose token drives the cascade, so only the `'always'`-bound
2022
- * subset carries values there ({@link FILTER_SCOPE_VARS}). Caller-bound
2023
- * vars fail closed — `$assigned` binds its caller-free constant `false`,
2024
- * the rest evaluate to `undefined` — and deploy rejects them at these
2025
- * sites; a cascade-fired action's per-token gate is `roles`, never its
2026
- * conditions.
2027
- * 3. **The start contexts** — a definition's `start.filter` and start GROQ
2028
- * requirements evaluate against a CANDIDATE (no instance exists yet):
2029
- * `*[...]` reads the engine-owned `{definition, subject, completedAt}`
2030
- * projection of the tag's instances and none of the rendered
2031
- * condition vars exist. The two split on what a surface can know:
2032
- * `filter` is browse-time-pure (candidate document as root,
2033
- * {@link START_FILTER_VARS} — no `$fields`, which cannot exist before
2034
- * inputs do), a `groq` requirement is the start-time readiness predicate
2035
- * ({@link START_REQUIREMENT_VARS} — `$fields` bound, never a root).
2036
- * 4. **Guard predicates** — NOT conditions. A lake mutation guard's
2037
- * `predicate` is groq-js **delta-mode** GROQ over a document mutation:
2038
- * `before()`/`after()`/`identity()` are dialect natives, and the wire
2039
- * format binds the identifiers in {@link GUARD_PREDICATE_VARS}. None of
2040
- * the condition vars exist there.
2041
- */
2042
2086
  /**
2043
2087
  * When a condition var holds a value:
2044
2088
  *
@@ -2176,11 +2220,7 @@ export declare type ContextEntry =
2176
2220
  value: string;
2177
2221
  };
2178
2222
 
2179
- /**
2180
- * Render the instance's `context` bag as the `$context` map — the
2181
- * start-time seed plus a parent's spawn handoff. `json` entries decode to
2182
- * their object form.
2183
- */
2223
+ /** `$context`: the context bag as a map by name; `json` entries decode to their object form. */
2184
2224
  export declare function contextMap(
2185
2225
  instance: Pick<WorkflowInstance, "context">,
2186
2226
  ): Record<string, unknown>;
@@ -2288,11 +2328,10 @@ export declare function createTelemetryIntake(args: {
2288
2328
  denied?: boolean;
2289
2329
  }): TelemetryIntake;
2290
2330
 
2291
- /**
2292
- * The append-only, machine-readable counterpart of the model log in
2293
- * `DATAMODEL.md`. It records compatibility decisions; the prose log retains
2294
- * the reasoning, absent-value semantics, and old-writer round-trip proof.
2295
- */
2331
+ /** A define-time validated `custom.<camelCaseMeaning>` value. */
2332
+ export declare type CustomSemantic = `custom.${string}`;
2333
+
2334
+ /** Append-only, machine-readable counterpart of the model log in DATAMODEL.md, which keeps the full reasoning. */
2296
2335
  export declare const DATA_MODEL_CHANGES: readonly [
2297
2336
  Readonly<{
2298
2337
  id: "governed-model-stamps";
@@ -2328,7 +2367,7 @@ export declare const DATA_MODEL_CHANGES: readonly [
2328
2367
  documentTypes: readonly ["definition"];
2329
2368
  compatibility: "additive";
2330
2369
  applicability: "detectable";
2331
- summary: "Ordinary actions may carry a closed bag of advisory workflow semantics.";
2370
+ summary: "Ordinary actions may carry advisory workflow semantics.";
2332
2371
  }>,
2333
2372
  Readonly<{
2334
2373
  id: "inclusive-scalar-bounds";
@@ -2384,14 +2423,51 @@ export declare const DATA_MODEL_CHANGES: readonly [
2384
2423
  applicability: "detectable";
2385
2424
  summary: string;
2386
2425
  }>,
2426
+ Readonly<{
2427
+ id: "node-semantics";
2428
+ introducedInModel: 6;
2429
+ minReaderModel: 0;
2430
+ documentTypes: readonly ["definition"];
2431
+ compatibility: "additive";
2432
+ applicability: "detectable";
2433
+ summary: "Workflow, stage, activity, and action nodes may carry signal or custom advisory semantics.";
2434
+ }>,
2435
+ Readonly<{
2436
+ id: "field-patch-ops";
2437
+ introducedInModel: 6;
2438
+ minReaderModel: 0;
2439
+ documentTypes: readonly ["definition", "instance"];
2440
+ compatibility: "additive";
2441
+ applicability: "detectable";
2442
+ summary: "Field ops may increment, decrement, or initialize a missing field value.";
2443
+ }>,
2444
+ Readonly<{
2445
+ id: "attributes-condition-var";
2446
+ introducedInModel: 7;
2447
+ minReaderModel: 0;
2448
+ documentTypes: readonly ["definition"];
2449
+ compatibility: "additive";
2450
+ applicability: "unconditional";
2451
+ summary: string;
2452
+ }>,
2453
+ Readonly<{
2454
+ id: "role-constrained-assignment-fields";
2455
+ introducedInModel: 8;
2456
+ minReaderModel: 8;
2457
+ documentTypes: readonly ["definition", "instance"];
2458
+ compatibility: "reader-floor";
2459
+ applicability: "detectable";
2460
+ summary: "Assignee fields may restrict newly assigned users and collective roles by role.";
2461
+ }>,
2387
2462
  ];
2388
2463
 
2464
+ /** The maximum reader floor this writer can emit for a detectable feature. */
2465
+ export declare const DATA_MODEL_MAX_READER = 8;
2466
+
2389
2467
  /**
2390
- * The maximum reader floor this writer can emit. Individual documents derive
2391
- * their `minReaderModel` from the compatibility-bearing features actually
2392
- * present; a document written at {@link DATA_MODEL_VERSION} may therefore
2393
- * carry a lower floor. Raising this maximum is a declared, DATAMODEL.md-logged
2394
- * decision that requires readers-first fleet sequencing.
2468
+ * The unconditional model-4 reader floor for every engine-owned document.
2469
+ * Detectable features may raise an individual document through
2470
+ * {@link DATA_MODEL_MAX_READER}.
2395
2471
  */
2396
2472
  export declare const DATA_MODEL_MIN_READER = 4;
2397
2473
 
@@ -2404,11 +2480,11 @@ export declare const DATA_MODEL_MIN_READER = 4;
2404
2480
  * honestly record whichever engine last shaped a doc.
2405
2481
  *
2406
2482
  * Bump on every declared shape change (additive included). Bumping does NOT
2407
- * by itself lock out older engines — that is {@link DATA_MODEL_MIN_READER}'s
2408
- * job. Declare every bump in `DATAMODEL.md`; the model-surface snapshot test
2409
- * keeps undeclared drift red.
2483
+ * by itself lock out older engines — that is the document's derived
2484
+ * `minReaderModel` floor. Declare every bump in `DATAMODEL.md`; the model-surface snapshot test
2485
+ * fails on undeclared drift.
2410
2486
  */
2411
- export declare const DATA_MODEL_VERSION = 5;
2487
+ export declare const DATA_MODEL_VERSION = 8;
2412
2488
 
2413
2489
  export declare interface DataModelChange {
2414
2490
  readonly id: string;
@@ -2433,6 +2509,13 @@ export declare function datasetResourceParts(id: string): {
2433
2509
  dataset: string;
2434
2510
  };
2435
2511
 
2512
+ export declare const DECISION_SEMANTICS: readonly [
2513
+ "decision.accept",
2514
+ "decision.decline",
2515
+ ];
2516
+
2517
+ export declare type DecisionSemantic = (typeof DECISION_SEMANTICS)[number];
2518
+
2436
2519
  /** The declarable half of {@link ExecutionContext} — what `createEngine` accepts. */
2437
2520
  export declare type DeclaredExecutionContext = Pick<
2438
2521
  ExecutionContext,
@@ -2564,23 +2647,9 @@ export declare class DefinitionInUseError extends WorkflowError<"definition-in-u
2564
2647
  }
2565
2648
 
2566
2649
  /**
2567
- * Pure GROQ builders for deployed workflow definitions. Composes the doc-type
2568
- * constant and the tag-scope predicate so the engine's internal lookups and the
2569
- * CLI share one definition of "tag-scoped, latest-or-pinned
2570
- * `workflow.definition`" instead of hand-writing the query at each call site.
2571
- *
2572
- * The tag enumerations are the deliberate exception: they span partitions, for a
2573
- * caller holding a resource but no tag yet.
2574
- */
2575
- /**
2576
- * GROQ resolving a single deployed {@link WORKFLOW_DEFINITION_TYPE} visible to
2577
- * the caller's tag. With {@link explicit} the query pins `$version`; otherwise
2578
- * it returns the highest deployed version.
2579
- *
2580
- * Params: `$definition`, `$tag`, plus `$version` when {@link explicit}.
2581
- *
2582
- * @param explicit - whether the caller wants a specific version (`$version`)
2583
- * rather than the latest.
2650
+ * GROQ resolving a single deployed {@link WORKFLOW_DEFINITION_TYPE} for the
2651
+ * caller's tag pinned to `$version` when {@link explicit}, else the highest
2652
+ * deployed version. Params: `$definition`, `$tag`, plus `$version` when explicit.
2584
2653
  */
2585
2654
  export declare function definitionLookupGroq(explicit: boolean): string;
2586
2655
 
@@ -2737,10 +2806,9 @@ export declare interface DeployDefinitionsArgs<
2737
2806
  T extends WorkflowDefinitionInput<T> = WorkflowDefinition,
2738
2807
  > {
2739
2808
  /**
2740
- * Reviewed numeric literal acknowledging the installed writer's maximum reader-floor capability.
2741
- * The deploy gate checks the exact installed value and links the readers-first rollout; do not
2742
- * import {@link DATA_MODEL_MIN_READER}, because that would auto-advance this acknowledgement on
2743
- * upgrade.
2809
+ * Highest reader model verified across runtimes sharing the workflow resource. The deploy gate
2810
+ * compares this reviewed numeric literal with the submitted definitions; do not import
2811
+ * either exported reader constant, because a dependency upgrade must not change it automatically.
2744
2812
  */
2745
2813
  expectedMinReaderModel: number;
2746
2814
  /**
@@ -2786,8 +2854,8 @@ export declare type DeployedDefinition = WorkflowDefinition & {
2786
2854
  /** Engine data-model stamp (see {@link DATA_MODEL_VERSION}) — absent on
2787
2855
  * documents deployed before the stamp existed (model 0). */
2788
2856
  modelVersion?: number;
2789
- /** Reader floor (see {@link DATA_MODEL_MIN_READER}) the oldest engine
2790
- * data model that can safely interpret this document. */
2857
+ /** The oldest engine data model that can safely interpret this document,
2858
+ * derived from its persisted features and the retained model-4 baseline. */
2791
2859
  minReaderModel?: number;
2792
2860
  };
2793
2861
 
@@ -2813,45 +2881,32 @@ export declare function deployedTagsGroq(): string;
2813
2881
  */
2814
2882
  export declare function deployStageGuards(args: StageGuardArgs): Promise<void>;
2815
2883
 
2816
- /** Where a definition deploys: the engine tag it partitions under, the
2817
- * workflow resource it belongs to, and the resource-alias bindings to expand
2818
- * references against. Structurally what `deployDefinitions` receives, minus the
2819
- * definitions themselves — carrying `resourceAliases` here is what keeps a diff
2820
- * fingerprinting the same physical content `deployDefinitions` would. */
2884
+ /** Structurally what `deployDefinitions` receives, minus the definitions; carrying `resourceAliases` here keeps a diff's fingerprint matching what deploy would produce. */
2821
2885
  export declare interface DeployTarget {
2822
- /** Reviewed numeric literal, checked against the exact installed floor before client access. */
2886
+ /** Highest reader model verified across runtimes sharing this workflow resource. */
2823
2887
  expectedMinReaderModel: number;
2824
2888
  tag: string;
2825
2889
  workflowResource: WorkflowResource;
2826
2890
  resourceAliases?: ResourceAliases;
2827
2891
  }
2828
2892
 
2829
- /**
2830
- * Classify an activity from its shape, BPMN-aligned: `target` marks off-system
2831
- * work (`manual`); otherwise any fireAction-fired action means a person (or
2832
- * robot caller) acts on it (`user`); otherwise cascade-fired effects make it a
2833
- * `service` step; otherwise cascade-fired status flips make it a `receive`
2834
- * wait; anything left is an inline `script` step.
2835
- */
2893
+ /** Classifies an activity from its shape: `target` marks off-system work
2894
+ * (`manual`), the one bit action shapes alone can't otherwise show. Then:
2895
+ * any caller-fireable action `user`; effects or spawns → `service`;
2896
+ * cascade-only actions `receive`; no actions at all `script`. */
2836
2897
  export declare function deriveActivityKind(activity: Activity): ActivityKind;
2837
2898
 
2838
2899
  export declare interface DeriveAutonomyOptions {
2839
2900
  /** Child definitions for `spawn` recursion, by definition `name` — the
2840
- * deploy batch or previously deployed set. An unresolvable child reports
2901
+ * deploy batch or the already-deployed set. An unresolvable child reports
2841
2902
  * `conditional` with an unresolved wait. */
2842
2903
  children?: ReadonlyMap<string, WorkflowDefinition>;
2843
2904
  }
2844
2905
 
2845
- /**
2846
- * Who, if anyone, fires the activity's actions derived ahead-of-time from
2847
- * the activity's shape alone: `off-system` when `target` is present; else
2848
- * `autonomous` (every action cascade-fired no caller fires anything),
2849
- * `interactive` (only fireAction-fired actions), or `hybrid` (mixed). An
2850
- * actionless activity classifies `autonomous` vacuously (deploy's
2851
- * terminal-reachability invariant rejects it anyway). Shape-only: whether
2852
- * the activity actually RESOLVES without a caller is the causal question
2853
- * `deriveWorkflowAutonomy` answers.
2854
- */
2906
+ /** Who fires the activity's actions, from shape alone — a separate causal
2907
+ * check decides whether it actually resolves without a caller. A `target`
2908
+ * is `off-system`; all-cascade actions are `autonomous`, none are
2909
+ * `interactive`, a mix is `hybrid`. */
2855
2910
  export declare function deriveExecutorClassification(
2856
2911
  activity: Activity,
2857
2912
  ): ExecutorClassification;
@@ -2967,6 +3022,18 @@ export declare function describeSiteHeading(
2967
3022
  ctx: DescribeContext,
2968
3023
  ): InsightPhrase;
2969
3024
 
3025
+ /**
3026
+ * The activity slice the document-derivable stuck causes read: its runtime
3027
+ * status, and the declared actions whose effects a failure is matched against.
3028
+ * Narrowed to exactly this, so one set of cause functions serves both a full
3029
+ * {@link WorkflowEvaluation} and {@link documentStuckCause}'s snapshot-derived
3030
+ * rows.
3031
+ */
3032
+ declare interface DiagnosedActivity {
3033
+ status: ActivityStatus;
3034
+ activity: Pick<Activity, "name" | "actions">;
3035
+ }
3036
+
2970
3037
  /** The slice of a {@link TransitionEvaluation} the classifier reads — narrowed
2971
3038
  * so a hand-crafted stuck permutation doesn't have to fabricate insights. */
2972
3039
  export declare type DiagnosedTransition = Pick<
@@ -2980,7 +3047,7 @@ export declare type DiagnosedTransition = Pick<
2980
3047
  * without standing up a full evaluation; {@link diagnoseInputFromEvaluation}
2981
3048
  * builds it from a real {@link WorkflowEvaluation}.
2982
3049
  */
2983
- export declare interface DiagnoseInput {
3050
+ export declare interface DiagnoseInput extends DocumentStuckInput {
2984
3051
  instance: Pick<
2985
3052
  WorkflowInstance,
2986
3053
  | "currentStage"
@@ -3021,6 +3088,18 @@ export declare interface DiagnoseResult {
3021
3088
  remediations: SuggestedRemediation[];
3022
3089
  }
3023
3090
 
3091
+ /**
3092
+ * How an in-flight instance reads right now. `waiting` and `blocked` are both
3093
+ * HEALTHY, not stuck: `waiting` means an active activity has an available
3094
+ * action and advances when someone acts — how long a workflow is "allowed" to
3095
+ * wait is workflow- and team-specific, not this classifier's call — while
3096
+ * `blocked` means an active activity's declared requirements aren't all met
3097
+ * yet, and flips to `waiting` once they hold (typically a sibling activity
3098
+ * completing, or content landing). `completed` and `aborted` carry
3099
+ * `liveChildren` when spawned work is still running: a parent finishing while
3100
+ * detached children run is legal — detach means detach — but a consumer
3101
+ * should surface it loudly.
3102
+ */
3024
3103
  export declare type Diagnosis =
3025
3104
  | {
3026
3105
  state: "progressing";
@@ -3068,16 +3147,11 @@ export declare interface DiffEntry {
3068
3147
  }
3069
3148
 
3070
3149
  /**
3071
- * Compare one local definition against the latest deployed version of its
3072
- * name (or its absence), classifying it via the engine's own content-addressed
3073
- * planner ({@link planDefinitionDeploy}). Create-only: a content change is a
3074
- * NEW version, never an in-place update so there is no `update` verdict.
3075
- * Pure the caller owns the fetch. `def` passes the same boundary parse as
3076
- * deploy ({@link parseDefinitionInput}): a fetched document's envelope is
3077
- * stripped and unknown keys fail loud, so diff and deploy accept and reject
3078
- * the same input shape. Deploy's further checks (GROQ + invariants via
3079
- * `validateDefinition`, batch ordering) stay the caller's job, as they always
3080
- * were.
3150
+ * Classifies `def` against the latest deployed version of its name via
3151
+ * {@link planDefinitionDeploy} a content change is always a new version,
3152
+ * never an in-place update. `def` passes the same boundary parse deploy uses
3153
+ * ({@link parseDefinitionInput}), so diff and deploy accept and reject the
3154
+ * same input shape.
3081
3155
  */
3082
3156
  export declare function diffEntry<T extends WorkflowDefinitionInput<T>>({
3083
3157
  def: rawDef,
@@ -3187,20 +3261,11 @@ export declare function displayDescription(
3187
3261
  ): string | undefined;
3188
3262
 
3189
3263
  /**
3190
- * Display metadata for the discriminator literals the engine persists
3191
- * (history entries, field-entry kinds, ops, effects-context entry
3192
- * kinds, document and effect-queue types). Each entry exposes
3193
- *
3194
- * - `title` — short label for chips, badges, headings
3195
- * - `description` — longer prose for tooltips / inspector panes
3196
- *
3197
- * UIs that render an instance audit log should NEVER show
3198
- * `transitionFired` raw — they look it up here and
3199
- * render `"Transition fired"` instead.
3200
- *
3201
- * Each family map is checked (`satisfies`) against the canonical union
3202
- * for that family, so adding or removing a discriminator in the engine
3203
- * fails tsc here until the display entry follows.
3264
+ * Display strings for one persisted discriminator: `title` is a short label
3265
+ * for chips, badges, and headings, `description` longer prose for tooltips and
3266
+ * inspector panes. A UI rendering an instance audit log looks the raw
3267
+ * discriminator up here instead of showing it — `transitionFired` reads as
3268
+ * "Transition fired".
3204
3269
  */
3205
3270
  export declare interface DisplayMetadata {
3206
3271
  readonly title: string;
@@ -3213,6 +3278,7 @@ export declare interface DisplayMetadata {
3213
3278
  */
3214
3279
  export declare function displayTitle(typeKey: string | undefined): string;
3215
3280
 
3281
+ /** Document-value permissions. Grants ({@link Grant} in ./authorization.ts) compose most-permissive-wins. */
3216
3282
  declare const DOCUMENT_VALUE_PERMISSIONS: readonly ["create", "read", "update"];
3217
3283
 
3218
3284
  /**
@@ -3269,6 +3335,36 @@ export declare function documentPrefilter(
3269
3335
  params: Record<string, string | string[]>,
3270
3336
  ): string;
3271
3337
 
3338
+ /**
3339
+ * Classify an instance from its document alone — no evaluation, no reads, no
3340
+ * actor. The transition-level causes need GROQ `when` results, so only
3341
+ * {@link diagnoseInstance} reaches those.
3342
+ *
3343
+ * Sound but incomplete, and a consumer must present it that way: `undefined`
3344
+ * means "no cause this classifier can see", never "healthy". Flag an instance on
3345
+ * a cause; never word an absence as an all-clear.
3346
+ */
3347
+ export declare function documentStuckCause(args: {
3348
+ instance: Pick<
3349
+ WorkflowInstance,
3350
+ "currentStage" | "effectHistory" | "pendingEffects" | "stages"
3351
+ >;
3352
+ /** The instance's parsed snapshot. Absent, the answer narrows — a failed
3353
+ * effect cannot be tied to the activity it stalls — and never widens. */
3354
+ definition: WorkflowDefinition | undefined;
3355
+ }): StuckCause | undefined;
3356
+
3357
+ /**
3358
+ * What the document-derivable stuck causes read. Every field is persisted —
3359
+ * on the instance itself or in the definition snapshot pinned to it — so a
3360
+ * caller holding only a committed instance can classify these without an
3361
+ * evaluation.
3362
+ */
3363
+ declare interface DocumentStuckInput {
3364
+ instance: Pick<WorkflowInstance, "effectHistory" | "pendingEffects">;
3365
+ activities: readonly DiagnosedActivity[];
3366
+ }
3367
+
3272
3368
  export declare type DocumentValuePermission =
3273
3369
  (typeof DOCUMENT_VALUE_PERMISSIONS)[number];
3274
3370
 
@@ -3317,6 +3413,13 @@ export declare const DRIVER_KIND_DISPLAY: {
3317
3413
  };
3318
3414
  };
3319
3415
 
3416
+ /**
3417
+ * What KIND of actor drove an action, recorded on the `actionFired` history
3418
+ * entry for the audit-trail "who did this?" glyph. Distinct from
3419
+ * {@link ActivityKind} (the intended execution lane) — any driver can fire
3420
+ * any kind. New entries stamp `'person'`; `'agent'`/`'service'`/`'engine'`
3421
+ * remain as read vocabulary for stored entries.
3422
+ */
3320
3423
  export declare const DRIVER_KINDS: readonly [
3321
3424
  "person",
3322
3425
  "agent",
@@ -3326,21 +3429,19 @@ export declare const DRIVER_KINDS: readonly [
3326
3429
 
3327
3430
  export declare type DriverKind = (typeof DRIVER_KINDS)[number];
3328
3431
 
3329
- /**
3330
- * Classify the actor that drove an action for the audit-trail glyph. `person`
3331
- * and `agent` pass through from {@link Actor.kind}; `system` maps to
3332
- * `service`. Today every token identity resolves as a person (`/users/me`
3333
- * carries no kind), so new entries stamp `person` and the `agent`/`service`/
3334
- * `engine` values are read vocabulary for stored entries — a service's
3335
- * environment lives on the entry's `executionContext`, and agent delegation
3336
- * is a future designed feature, not an actor kind the engine can mint.
3337
- *
3338
- * Advisory and only as trustworthy as the {@link Actor} it reads — actor
3339
- * identity is itself advisory in this engine (the lake/token is authoritative),
3340
- * so this is a best-effort glyph, never an authorization signal.
3341
- */
3432
+ /** Actor-kind glyph for the audit trail — advisory only, never an
3433
+ * authorization signal. */
3342
3434
  export declare function driverKind(actor: Actor): DriverKind;
3343
3435
 
3436
+ /**
3437
+ * Declared editability of a field — the generic edit seam's gate. Default
3438
+ * (absent) is NOT editable: a field is op-only engine working memory unless the
3439
+ * modeler opens it. The stored form is `true` (editable by anyone within the
3440
+ * field's scope window) or an EDIT CONDITION — rendered-scope GROQ (`$actor`,
3441
+ * `$can`, `$attributes`, `$fields`, `$assigned`), checked like an action filter
3442
+ * to decide who-may-edit. ADVISORY like every engine gate — it disables the
3443
+ * inline field and explains; a {@link Guard} declares the intended write-lock.
3444
+ */
3344
3445
  export declare type Editable = v.InferOutput<typeof StoredEditableSchema>;
3345
3446
 
3346
3447
  /**
@@ -3358,6 +3459,10 @@ export declare interface EditableFieldEvaluation {
3358
3459
  type: FieldKind;
3359
3460
  title?: string;
3360
3461
  validation?: ScalarValidation;
3462
+ /** Eligible assignment roles for `assignee` / `assignees`; absent means unconstrained. */
3463
+ roles?: string[];
3464
+ /** The definition aliases used to interpret {@link EditableFieldEvaluation.roles}. */
3465
+ roleAliases?: RoleAliases;
3361
3466
  /** Current resolved value; `undefined` until the field is first resolved. */
3362
3467
  value: unknown;
3363
3468
  /** Whether THIS actor may edit the field right now (window + predicate + guard). */
@@ -3470,6 +3575,18 @@ export declare interface EditFieldTarget {
3470
3575
 
3471
3576
  export declare type EditMode = "set" | "append" | "unset";
3472
3577
 
3578
+ /**
3579
+ * A registered effect: `name` is its only identity (unique per definition,
3580
+ * read downstream as `$effects.<name>`) — the host app registers a handler
3581
+ * against it 1:1, and the stored definition never references code.
3582
+ * `bindings` are GROQ reads over the rendered scope, resolved to concrete
3583
+ * JSON at queue time; `input` is static config passed through verbatim.
3584
+ * `outputs` (typed {@link FieldShape}s) is a STRICT allowlist: at completion
3585
+ * an undeclared output key, or a value that doesn't fit its shape, fails the
3586
+ * completion and nothing is stored. Omitting `outputs` is an EMPTY allowlist,
3587
+ * so ANY returned output is rejected and fails the completion — the bound is
3588
+ * universal, not opt-in.
3589
+ */
3473
3590
  export declare type Effect = v.InferOutput<typeof EffectSchema>;
3474
3591
 
3475
3592
  /** Total commits one dispatch may make — the runaway-handler bound: without
@@ -3493,8 +3610,10 @@ declare const EFFECT_RUN_STATUSES: readonly ["done", "failed", "cancelled"];
3493
3610
 
3494
3611
  /**
3495
3612
  * A `ctx.commitOps` / `ctx.setProgress` call hit one of the dispatch's
3496
- * bounds. Thrown synchronously at the call site see the module doc for why
3497
- * a rejection would be invisible to exactly the caller the bound exists for.
3613
+ * bounds. Thrown synchronously at the call site, not as a promise rejection:
3614
+ * a tight loop that forgot to `await` dies on its own stack at the bound
3615
+ * instead of spraying unhandled rejections invisible to the caller the bound
3616
+ * exists for.
3498
3617
  */
3499
3618
  export declare class EffectCommitQueueOverflowError extends WorkflowError<"effect-commit-queue-overflow"> {
3500
3619
  readonly effectKey: string;
@@ -3515,11 +3634,29 @@ export declare type EffectCompletionStatus = Exclude<
3515
3634
  "cancelled"
3516
3635
  >;
3517
3636
 
3637
+ /**
3638
+ * External effect handler — invoked at drain time with resolved `params` and
3639
+ * a context. Returning `outputs` records them on the run's `effectHistory`
3640
+ * row, read downstream as `$effects['<name>'].<output>`. Returning `ops`
3641
+ * applies the state half of the effect in the completion commit (`field.*`
3642
+ * only, never `status.set`) — every returned op must explicitly set
3643
+ * `target.scope`, since completion ops have no authoring location to infer
3644
+ * one from. Throwing marks the effect failed, with no `ops`.
3645
+ *
3646
+ * Delivery is at-least-once: a handler MAY run more than once for the same
3647
+ * effect (a dispatch dying after its side effect but before commit, or a
3648
+ * lease expiring mid-dispatch and being taken over). Completion is
3649
+ * first-writer-wins — the losing run's completion is reported as `lost`.
3650
+ * Write handlers to tolerate this: check `effectHistory[]` for a row keyed
3651
+ * by `ctx.effectKey` before irreversible work, and derive external
3652
+ * identifiers from `ctx.effectKey` so the receiving system can dedupe.
3653
+ *
3654
+ * The `bivarianceHack` indirection keeps this readable from the non-generic
3655
+ * `Engine` surface; only the typed drain invokes handlers.
3656
+ */
3518
3657
  export declare type EffectHandler<
3519
3658
  Client extends WorkflowClient = WorkflowClient,
3520
3659
  > = {
3521
- /** Bivariant so a concretely typed handler registry remains readable from
3522
- * the non-generic Engine surface; only the typed drain invokes handlers. */
3523
3660
  bivarianceHack(
3524
3661
  params: Record<string, unknown>,
3525
3662
  ctx: EffectHandlerContext<Client>,
@@ -3529,97 +3666,21 @@ export declare type EffectHandler<
3529
3666
  } | void>;
3530
3667
  }["bivarianceHack"];
3531
3668
 
3532
- /**
3533
- * External effect handler — invoked at drain time with the resolved
3534
- * `params` and a context. Returning `outputs` records them on the run's
3535
- * `effectHistory` row, where downstream bindings and conditions read them
3536
- * as `$effects['<effect name>'].<output>`.
3537
- * Returning `ops` applies the state half of the effect in the completion
3538
- * commit — `field.*` computed from the real result, run through the same op
3539
- * applier as an action's field ops (so a created doc's ref enters `$fields`, or
3540
- * a screened outcome lands in a field the activity/stage gate reads). Effects
3541
- * report results as field state, never by flipping an activity status, so `ops`
3542
- * excludes `status.set`. Unlike definition-authored field ops, completion ops
3543
- * have no authoring location from which to infer a target scope: every returned
3544
- * op must explicitly set `target.scope` to `'workflow'` or `'stage'`. Throwing
3545
- * marks the effect as failed (and returns no `ops`).
3546
- *
3547
- * **Delivery is at-least-once — a handler MAY run more than once for the
3548
- * same effect.** Two overlaps produce a double-run: the dispatching process
3549
- * dies after the handler's side effect but before `completeEffect` commits,
3550
- * and a slow dispatch outliving its claim's lease (the engine's
3551
- * `effectLeaseMs`, default 5 minutes) — an expired claim is taken over by
3552
- * the next drain, or force-released by `sweepStaleClaims`, and redispatched
3553
- * while the original handler may still be running. Completion is
3554
- * first-writer-wins: the losing drainer's dispatch already ran, its
3555
- * completion is reported as `lost`.
3556
- *
3557
- * Write handlers to tolerate that: before irreversible work, check
3558
- * `effectHistory[]` for a row with this run's `ctx.effectKey` (the stable
3559
- * `_key` an entry keeps from queue to history) and skip work a prior run
3560
- * already completed; derive external-system identifiers from `ctx.effectKey`
3561
- * so the receiving system can dedupe the overlap the ledger can't see.
3562
- */
3563
3669
  declare type EffectHandlerContext<Client extends WorkflowClient> = {
3564
- /**
3565
- * A concrete sibling of the client supplied to `createEngine`, bound to the
3566
- * workflow resource with the same namespaces and credentials. Untagged
3567
- * handler requests on its workflow-client surface carry the `workflow.effect`
3568
- * request tag by default. A concrete client's explicit tags compose beneath
3569
- * that prefix. On the structural fallback for minimal clients, pass-through
3570
- * namespaces are not stamped and core builders expose the engine's minimal
3571
- * workflow-client surface.
3572
- */
3670
+ /** A concrete sibling of the `createEngine` client, bound to the workflow resource with the
3671
+ * same credentials; untagged handler requests carry the `workflow.effect` tag by default. */
3573
3672
  client: Client;
3574
- /**
3575
- * Resolve the client bound to a subject doc's own resource. A handler
3576
- * patches the SUBJECT (which may live in a different Sanity resource
3577
- * than the instance — split-dataset GDR deploys); the drainer's
3578
- * `completeEffect` writes the INSTANCE through {@link client}. One
3579
- * client can't address both, so a handler that patches a foreign
3580
- * subject must route its write here.
3581
- *
3582
- * Pass the subject's GDR — the URI a binding like `$fields.subject._id`
3583
- * resolves to (the hydrated doc's `_id`), or a full
3584
- * {@link GlobalDocumentReference}. Returns the `resourceClients` client
3585
- * for that resource when one is mapped, {@link client} for the workflow
3586
- * resource itself, and a sibling derived from {@link client}'s
3587
- * credentials otherwise. Returned clients preserve their concrete APIs and
3588
- * apply the same default effect request tag.
3589
- * Throws if `ref` isn't a GDR — a bare id can't
3590
- * be routed, so failing loud beats silently patching the wrong dataset.
3591
- */
3673
+ /** Resolve the client for a subject doc's own resource: a handler patching a foreign subject
3674
+ * routes its write here {@link client} addresses the instance's. Throws on a bare id. */
3592
3675
  clientFor: (ref: GdrUri | GlobalDocumentReference) => WorkflowClient;
3593
3676
  instanceId: string;
3594
3677
  effectKey: string;
3595
3678
  log: (message: string, extra?: Record<string, unknown>) => void;
3596
- /**
3597
- * Commit mid-dispatch field state as a real engine transaction
3598
- * validated like completion ops (`field.*` only, never `status.set`),
3599
- * gated on THIS dispatch's exact claim (a stale/superseded claim
3600
- * rejects before writing), history + idempotency recorded, guards
3601
- * refreshed, cascade run, and the claim's lease renewed in the same
3602
- * commit. Calls enqueue synchronously into a bounded per-dispatch FIFO
3603
- * and execute strictly in call order, one at a time — forgetting to
3604
- * `await` cannot create same-handler write races, and overflow (or the
3605
- * per-dispatch commit cap) throws synchronously at the call site.
3606
- * Await each call anyway: that is where errors surface promptly and
3607
- * engine commit latency paces the reporter. `idempotencyKey` is
3608
- * required — the engine does not assume a supplied op is idempotent.
3609
- * An accepted-but-unawaited commit that fails still fails the effect
3610
- * at settlement; the final completion always waits for this queue to
3611
- * drain. Never coalesced.
3612
- */
3679
+ /** Mid-dispatch `field.*` commit gated on THIS dispatch's exact claim — a superseded claim
3680
+ * writes nothing. Runs in call order, never coalesced; `idempotencyKey` is required. */
3613
3681
  commitOps: (req: CommitOpsRequest) => Promise<void>;
3614
- /**
3615
- * Report absolute progresssugar over {@link commitOps} that
3616
- * `field.set`s a number (a `progress` field's 0–100 contract is
3617
- * enforced by the engine at commit). A bare string targets a
3618
- * workflow-scope field; pass `{scope: 'stage', field}` for stage
3619
- * scope. Unlike `commitOps`, PENDING sets to the same field coalesce
3620
- * (latest value wins, one commit), so a tight reporting loop is safe
3621
- * by construction; idempotency keys are engine-derived.
3622
- */
3682
+ /** Absolute progress, sugar over {@link commitOps}: `field.set`s a number (0–100, enforced at
3683
+ * commit). Unlike `commitOps`, pending sets to one field coalesce latest value wins. */
3623
3684
  setProgress: (target: ProgressTarget, value: number) => Promise<void>;
3624
3685
  };
3625
3686
 
@@ -3718,12 +3779,7 @@ export declare class EffectOutputsInvalidError extends WorkflowError<"effect-out
3718
3779
  constructor(args: { effect: string; issues: string[] });
3719
3780
  }
3720
3781
 
3721
- /**
3722
- * Render completed effects' outputs as the `$effects` map — each effect's
3723
- * LATEST completed run with outputs wins, by name, across the whole
3724
- * history (outputs are workflow-scope handler results; the per-visit
3725
- * signal is `$effectStatus`).
3726
- */
3782
+ /** `$effects`: each effect name → its LATEST completed run's outputs across the whole history. */
3727
3783
  export declare function effectOutputsMap(
3728
3784
  instance: Pick<WorkflowInstance, "effectHistory">,
3729
3785
  ): Record<string, unknown>;
@@ -3743,7 +3799,6 @@ declare const EffectSchema: v.StrictObjectSchema<
3743
3799
  v.StringSchema<undefined>,
3744
3800
  undefined
3745
3801
  >;
3746
- /** GROQ reads over the rendered scope, resolved to concrete JSON at queue time. */
3747
3802
  readonly bindings: v.OptionalSchema<
3748
3803
  v.RecordSchema<
3749
3804
  v.StringSchema<undefined>,
@@ -3757,28 +3812,10 @@ declare const EffectSchema: v.StrictObjectSchema<
3757
3812
  >,
3758
3813
  undefined
3759
3814
  >;
3760
- /** Static config, passed through to the handler verbatim. */
3761
3815
  readonly input: v.OptionalSchema<
3762
3816
  v.RecordSchema<v.StringSchema<undefined>, v.UnknownSchema, undefined>,
3763
3817
  undefined
3764
3818
  >;
3765
- /**
3766
- * The outputs this effect is allowed to produce, as typed {@link FieldShape}s
3767
- * (each `name` is an output key, read downstream as `$effects['<name>'].<key>`;
3768
- * an `array` output is an array of objects shaped by `of`).
3769
- *
3770
- * A STRICT allowlist: at completion the handler's returned `outputs` are
3771
- * validated against these shapes and an undeclared key — or a value that
3772
- * doesn't fit its shape — fails the completion (nothing is stored). Omitting
3773
- * `outputs` is an EMPTY allowlist: the effect produces nothing, so any returned
3774
- * output is rejected — the bound is universal, not opt-in.
3775
- * Why strict: outputs land on the instance document's `effectHistory`, so
3776
- * the allowlist keeps it bounded — a handler can't accidentally spread a
3777
- * whole API response
3778
- * into the instance — and the declared shapes let tooling (e.g. the simulator's
3779
- * drain UI) suggest an effect's exact output keys. Declaring outputs also
3780
- * powers the advisory deploy-time producer/consumer lint.
3781
- */
3782
3819
  readonly outputs: v.OptionalSchema<
3783
3820
  v.ArraySchema<v.GenericSchema<FieldShape>, undefined>,
3784
3821
  undefined
@@ -3816,6 +3853,10 @@ export declare interface Engine {
3816
3853
  deployDefinitions: <T extends WorkflowDefinitionInput<T>>(
3817
3854
  args: DeployDefinitionsArgs<T>,
3818
3855
  ) => Promise<DeployDefinitionsResult>;
3856
+ /** Starts an instance. `start.filter` is never a gate here — applicability
3857
+ * belongs to `definitionsForDocument`, and an inapplicable definition
3858
+ * starts without complaint. `instanceId` is the idempotency key: reusing
3859
+ * it for the same start resumes; a different start throws. */
3819
3860
  startInstance: (args: StartInstanceArgs) => Promise<OperationResult>;
3820
3861
  fireAction: (args: FireActionArgs) => Promise<OperationResult>;
3821
3862
  /** Edit a declared-editable field directly (the generic edit seam):
@@ -4032,17 +4073,9 @@ export declare function entryDocRefs(
4032
4073
  entries: unknown,
4033
4074
  ): GlobalDocumentReference[];
4034
4075
 
4035
- /**
4036
- * Pure error helpers no client, no I/O. The one home for the engine's
4037
- * "coerce an unknown caught value" + "rethrow with context" idioms, so the
4038
- * message shape and cause-chaining can't drift across call sites.
4039
- */
4040
- /**
4041
- * A human-readable message for an unknown caught value: `.message` for an
4042
- * {@link Error}, otherwise `String(value)`. Strips control characters
4043
- * (keeping newlines and tabs) so server-derived error text can't smuggle
4044
- * terminal escape sequences into consumer output.
4045
- */
4076
+ /** The value's message — `Error.message`, else `String(value)` — with
4077
+ * control characters stripped so server-derived error text can't smuggle
4078
+ * terminal escape sequences into consumer output. */
4046
4079
  export declare function errorMessage(err: unknown): string;
4047
4080
 
4048
4081
  export declare interface EvaluateArgs {
@@ -4093,6 +4126,12 @@ export declare interface EvaluateFromSnapshotArgs {
4093
4126
  * write boundary still enforces).
4094
4127
  */
4095
4128
  grants?: Grant[];
4129
+ /**
4130
+ * Resolved org-level user attributes for the actor. Omit to leave the
4131
+ * rendered `$attributes` undefined (conditions referencing it fail
4132
+ * closed).
4133
+ */
4134
+ attributes?: UserAttributes;
4096
4135
  /**
4097
4136
  * The in-memory snapshot to evaluate against. The caller assembles it
4098
4137
  * from whatever source — a fetch (see {@link evaluateInstance}) or a
@@ -4179,16 +4218,16 @@ export declare function evaluateStartFilter(args: {
4179
4218
 
4180
4219
  /**
4181
4220
  * Well-known {@link ExecutionContext.kind} values. The field is a free
4182
- * string — these are the shipped vocabulary, not a closed set.
4221
+ * string — these are the shipped vocabulary, not a closed set. `interactive`
4222
+ * is the generic human-session fallback when `studio`/`sdkApp` don't apply;
4223
+ * `server` is a proxy acting with a user's token; `drainer` is an
4224
+ * effect-drain runtime.
4183
4225
  */
4184
4226
  export declare const EXECUTION_KINDS: {
4185
- /** A human-facing session (generic — prefer `studio`/`sdkApp` when known). */
4186
4227
  readonly interactive: "interactive";
4187
- /** A server process acting with a user's token (e.g. a publish proxy). */
4188
4228
  readonly server: "server";
4189
4229
  readonly cli: "cli";
4190
4230
  readonly mcp: "mcp";
4191
- /** An effect-drain runtime. */
4192
4231
  readonly drainer: "drainer";
4193
4232
  readonly script: "script";
4194
4233
  readonly test: "test";
@@ -4197,23 +4236,11 @@ export declare const EXECUTION_KINDS: {
4197
4236
  };
4198
4237
 
4199
4238
  /**
4200
- * Execution context advisory "via what" provenance, stamped on every
4201
- * history entry alongside the actor's "who".
4202
- *
4203
- * Identity is always the token behind the client (`/users/me`); the
4204
- * execution context records the ENVIRONMENT that drove the commit: a
4205
- * studio session, the CLI, an MCP host, a server proxy acting with a
4206
- * user's token. It is self-asserted advisory metadata, configured once at
4207
- * `createEngine` — never per call — and never an authorization input.
4208
- *
4209
- * The `runtime` half is always inferred at construction (best-effort,
4210
- * zero dependencies); the declared `{kind, id}` half is optional. An
4211
- * unlabeled `runtime: "node"` is itself a signal (a script or proxy that
4212
- * didn't declare itself), and a declared/inferred mismatch (`kind:
4213
- * "studio"` on `runtime: "node"`) surfaces SSR passes or lying labels
4214
- * for free.
4215
- */
4216
- /** The stored stamp — `runtime` is always present, the declared half optional. */
4239
+ * The stored stamp: self-asserted advisory provenance — "via what", distinct
4240
+ * from the actor's "who". Configured once at `createEngine`, never per call,
4241
+ * and never an authorization input. `runtime` is always present; the declared
4242
+ * half is optional.
4243
+ */
4217
4244
  export declare interface ExecutionContext {
4218
4245
  /** Inferred JavaScript runtime: `browser` | `node` | `worker` | `edge` | `deno` | `bun` | `unknown`. */
4219
4246
  runtime: string;
@@ -4246,6 +4273,13 @@ export declare const EXECUTOR_CLASSIFICATION_DISPLAY: {
4246
4273
  };
4247
4274
  };
4248
4275
 
4276
+ /**
4277
+ * Who, if anyone, fires an activity's actions, derived ahead-of-time from
4278
+ * the activity's shape alone: `'autonomous'` = every action is cascade-fired
4279
+ * (no caller fires anything); `'interactive'` = only fireAction-fired
4280
+ * actions; `'off-system'` = `target` present; `'hybrid'` = mixed. Advisory,
4281
+ * rendered on insight/evaluation nodes — never gating.
4282
+ */
4249
4283
  export declare const EXECUTOR_CLASSIFICATIONS: readonly [
4250
4284
  "autonomous",
4251
4285
  "interactive",
@@ -4319,17 +4353,7 @@ export declare function explainStartRequirement(args: {
4319
4353
  */
4320
4354
  export declare function extractDocumentId(gdrUriString: string): string;
4321
4355
 
4322
- /**
4323
- * Convenience: fetch the grants for a given resource via the supplied
4324
- * client:
4325
- *
4326
- * GET <resourcePath> → Grant[]
4327
- *
4328
- * `resourcePath` is caller-supplied so the same helper works for
4329
- * project ACLs (`/projects/<id>/datasets/<dataset>/acl`) and for a
4330
- * dedicated workflow-collaboration resource. The client must support
4331
- * the `request<T>({url})` method `@sanity/client` exposes.
4332
- */
4356
+ /** `resourcePath` is caller-supplied so this works for both project ACLs and a dedicated workflow-collaboration resource. */
4333
4357
  declare function fetchGrants(args: {
4334
4358
  client: {
4335
4359
  request: <T>(opts: {
@@ -4425,13 +4449,21 @@ export declare const FIELD_KIND_DISPLAY: {
4425
4449
  };
4426
4450
  };
4427
4451
 
4452
+ /**
4453
+ * The three field scopes a field entry can live in. Also the
4454
+ * group-declaration levels: a `groups` array lives at exactly these three
4455
+ * nodes, so `DefinitionGroupSite.level` reuses this vocabulary.
4456
+ */
4428
4457
  declare const FIELD_SCOPES: readonly ["workflow", "stage", "activity"];
4429
4458
 
4430
4459
  /**
4431
4460
  * The kinds a VALUE can take — scalars aligned to Sanity's names, the
4432
4461
  * reference kinds, the actor/assignee identities, and the two compositional
4433
4462
  * kinds (`object` with named `fields`, `array` of objects shaped by `of`).
4434
- * This is also the set a nested {@link FieldShape} sub-field may use.
4463
+ * This is also the set a nested {@link FieldShape} sub-field may use. Kinds
4464
+ * are bare (unique within their union); namespacing lives only on
4465
+ * engine-owned lake document `_type`s ({@link WORKFLOW_DEFINITION_TYPE}, the
4466
+ * instance type).
4435
4467
  *
4436
4468
  * Exported (module-level, not package API) for the model-surface gate's
4437
4469
  * enum-value coverage test.
@@ -4477,6 +4509,7 @@ export declare interface FieldDescription {
4477
4509
  proposals: InsightPhrase[];
4478
4510
  }
4479
4511
 
4512
+ /** One declared field entry as authored and stored: name, value kind, and its scope's sourcing and editability. */
4480
4513
  export declare type FieldEntry = FieldEntryFields<Editable, string[]>;
4481
4514
 
4482
4515
  /** Type-mirror of {@link fieldEntryFields}: a raw field entry of the given
@@ -4489,6 +4522,8 @@ declare type FieldEntryFields<TEditable, TGroup> = FieldBase<
4489
4522
  options?: ChoiceOptions | undefined;
4490
4523
  validation?: ScalarValidation | undefined;
4491
4524
  types?: string[] | undefined;
4525
+ /** Non-empty assignment eligibility constraint. User roles apply aliases; collective roles match literally. */
4526
+ roles?: string[] | undefined;
4492
4527
  fields?: FieldShape[] | undefined;
4493
4528
  of?: FieldShape[] | undefined;
4494
4529
  };
@@ -4515,6 +4550,10 @@ export declare interface FieldInsight {
4515
4550
 
4516
4551
  export declare type FieldKind = keyof FieldValueMap;
4517
4552
 
4553
+ /**
4554
+ * A stored field mutation. `field.inc` and `field.dec` use the same names as
4555
+ * `@sanity/client` patches and default an omitted `value` to a delta of `1`.
4556
+ */
4518
4557
  export declare type FieldOp = v.InferOutput<typeof StoredFieldOpSchema>;
4519
4558
 
4520
4559
  /**
@@ -4538,6 +4577,14 @@ declare type FieldReadExpr = {
4538
4577
 
4539
4578
  export declare type FieldScope = (typeof FIELD_SCOPES)[number];
4540
4579
 
4580
+ /**
4581
+ * A sub-field shape used inside an `object`'s `fields` or an `array`'s `of` —
4582
+ * lighter than {@link FieldEntry}: no `initialValue`/`editable`/`required`,
4583
+ * since a sub-field's value comes from the parent. An `object` kind requires
4584
+ * non-empty `fields` and no `of`; an `array` kind requires non-empty `of` and
4585
+ * no `fields`; every other kind requires neither — enforced at parse, not
4586
+ * visible in this type.
4587
+ */
4541
4588
  export declare interface FieldShape {
4542
4589
  type: FieldValueKind;
4543
4590
  name: string;
@@ -4545,10 +4592,19 @@ export declare interface FieldShape {
4545
4592
  description?: string | undefined;
4546
4593
  options?: ChoiceOptions | undefined;
4547
4594
  validation?: ScalarValidation | undefined;
4595
+ /** Non-empty assignment eligibility constraint. User roles apply aliases; collective roles match literally. */
4596
+ roles?: string[] | undefined;
4548
4597
  fields?: FieldShape[] | undefined;
4549
4598
  of?: FieldShape[] | undefined;
4550
4599
  }
4551
4600
 
4601
+ /**
4602
+ * How a field seeds its `initialValue`, once at materialisation (advisory
4603
+ * after — the field stays freely editable). Absent means working memory: the
4604
+ * field starts empty and an op fills it later, spelled by omission rather
4605
+ * than an arm. Distinct from {@link ValueExpr}, an op's write payload; they
4606
+ * overlap only on the literal and field-read arms.
4607
+ */
4552
4608
  export declare type FieldSource = FieldSourceInternal;
4553
4609
 
4554
4610
  declare type FieldSourceInternal =
@@ -4563,12 +4619,9 @@ declare type FieldSourceInternal =
4563
4619
  | FieldReadExpr;
4564
4620
 
4565
4621
  /**
4566
- * The field tree of a persisted value every leaf replaced by its type name
4567
- * (`null` kept distinct from `object`), object keys sorted by UTF-16 code
4568
- * unit (locale-independent, so the pinned ledgers canonicalise identically
4569
- * on every machine), arrays element-wise so discriminated variants stay
4570
- * visible. The comparison form the model-surface gates pin per model
4571
- * version, and the form ops tooling can diff a live document against.
4622
+ * Every leaf replaced by its type name (`null` distinct from `object`); keys sorted by
4623
+ * UTF-16 code unit, not locale collation, so the shape canonicalises identically on every
4624
+ * machine.
4572
4625
  */
4573
4626
  export declare function fieldTreeShape(value: unknown): unknown;
4574
4627
 
@@ -4629,7 +4682,14 @@ export declare class FieldValueShapeError extends WorkflowError<"field-value-sha
4629
4682
  */
4630
4683
  export declare const FILTER_SCOPE_VARS: readonly string[];
4631
4684
 
4632
- /**
4685
+ /** Returns `undefined`, never throws, for an activity an instance's pinned snapshot names but the definition has since renamed or removed. */
4686
+ export declare function findActivityNode(args: {
4687
+ activityName: string;
4688
+ definition: WorkflowDefinition | undefined;
4689
+ stageName: string;
4690
+ }): Activity | undefined;
4691
+
4692
+ /**
4633
4693
  * The current stage's {@link ActivityEntry} named `activityName`, or
4634
4694
  * `undefined` when the open stage holds no such activity (including when
4635
4695
  * `activityName` is itself `undefined`). Composes {@link findOpenStageEntry}
@@ -4669,6 +4729,12 @@ export declare interface FindPendingEffectsArgs extends InstanceRefArgs {
4669
4729
  names?: string[];
4670
4730
  }
4671
4731
 
4732
+ /** Returns `undefined`, never throws, for a stage an instance's pinned snapshot names but the definition has since renamed or removed. */
4733
+ export declare function findStageNode(args: {
4734
+ definition: WorkflowDefinition | undefined;
4735
+ stageName: string;
4736
+ }): Stage | undefined;
4737
+
4672
4738
  export declare interface FireActionArgs extends DedupableOperationArgs {
4673
4739
  activity: string;
4674
4740
  action: string;
@@ -4824,6 +4890,11 @@ export declare interface GlobalDocumentReference<
4824
4890
  type: TType;
4825
4891
  }
4826
4892
 
4893
+ /**
4894
+ * Filters are GROQ strings evaluated through groq-js with the document as
4895
+ * the dataset and the caller's principal id as `identity()`. Grants compose
4896
+ * most-permissive-wins.
4897
+ */
4827
4898
  export declare interface Grant {
4828
4899
  filter: string;
4829
4900
  permissions: DocumentValuePermission[];
@@ -4845,12 +4916,22 @@ declare function grantsPermissionOn(args: {
4845
4916
  userId?: string;
4846
4917
  }): Promise<boolean>;
4847
4918
 
4919
+ /** A named readiness condition. Activities accept only `'groq'`; workflow
4920
+ * `start.requirements` also accepts `'singleSubject'` — see {@link StartRequirement}. */
4848
4921
  export declare type GroqRequirement = RequirementBase & {
4849
4922
  type: "groq";
4850
4923
  query: string;
4851
4924
  };
4852
4925
 
4853
- /** Type-mirror of {@link GroupSchema} — one declared group. */
4926
+ /**
4927
+ * A declared "what belongs together" tag: the workflow root, a stage, or an
4928
+ * activity declares named groups, and field entries, activities, and actions
4929
+ * opt in via `group`. Purely advisory — the engine stores and validates names
4930
+ * (unique per level, every reference resolves) and never acts on them; a
4931
+ * consumer decides what a group means for its medium. The same name declared
4932
+ * at several levels is intentional nesting, addressed per level; the engine
4933
+ * never merges them.
4934
+ */
4854
4935
  export declare type Group = {
4855
4936
  name: string;
4856
4937
  title?: string | undefined;
@@ -4876,6 +4957,14 @@ export declare const GROUP_KIND_DISPLAY: {
4876
4957
  };
4877
4958
  };
4878
4959
 
4960
+ /**
4961
+ * Advisory classification of a declared {@link Group} by its informational
4962
+ * ROLE, never a rendering treatment: `'core'` marks content central to
4963
+ * understanding the workflow (condensed views include these first);
4964
+ * `'details'` marks depth on demand. Unset = a plain group. Consumers
4965
+ * reading a definition as data MUST treat an unknown kind as unset — growing
4966
+ * this list is an engine version bump, like every stored enum.
4967
+ */
4879
4968
  export declare const GROUP_KINDS: readonly ["core", "details"];
4880
4969
 
4881
4970
  export declare type GroupKind = (typeof GROUP_KINDS)[number];
@@ -4928,6 +5017,27 @@ export declare function groupSitesOf(
4928
5017
  definition: WorkflowDefinition,
4929
5018
  ): DefinitionGroupSite[];
4930
5019
 
5020
+ /**
5021
+ * A lake mutation guard. A FOREIGN CONTRACT mirrored 1:1: `match`,
5022
+ * `predicate`, and `metadata` are the content lake's persisted guard-document
5023
+ * API, not engine-invented surface — the stored form keeps the lake's
5024
+ * vocabulary verbatim. The engine adds exactly two things: `name` (a
5025
+ * lake-id-segment, `^[a-z0-9][a-z0-9-]*$`, unique per definition — the lake
5026
+ * `_id` derives from `(instanceId, name)` at stage entry) and the deploy-time
5027
+ * read VALUES on `match.idRefs` / `metadata` (a typed {@link GuardRead} when
5028
+ * authoring, resolved to bare values at deploy). `match` selects mutations by
5029
+ * `types` (empty matches any), `idRefs` (field reads resolved to bare ids),
5030
+ * `idPatterns` (bare glob ids), and `actions` (at least one). `predicate` is
5031
+ * lake GROQ in a distinct delta-mode eval context (`before()`/`after()`,
5032
+ * `mutation`, `guard`, `identity()`, bare ids/fields only): strictly `true`
5033
+ * ALLOWS the mutation; anything else — false, null, an evaluation error, or
5034
+ * an omitted/empty predicate — DENIES. `metadata` is the only bridge from
5035
+ * that eval context (which cannot see `$fields`) to workflow fields, read as
5036
+ * `guard.metadata.*` and re-synced by the post-field-op guard refresh. The
5037
+ * lake does not enforce the guard document type yet: a deployed guard denies
5038
+ * optimistically engine-side, and the lake ACL is the only hard gate until
5039
+ * guard enforcement ships.
5040
+ */
4931
5041
  export declare type Guard = v.InferOutput<typeof GuardSchema>;
4932
5042
 
4933
5043
  /**
@@ -4985,6 +5095,17 @@ export declare function guardMatches({
4985
5095
  action: MutationGuardAction;
4986
5096
  }): boolean;
4987
5097
 
5098
+ /**
5099
+ * A deploy-time value read on a guard's `match.idRefs` / `metadata`, typed
5100
+ * like {@link ValueExpr} (`self`/`now`/`fieldRead`, plus the guard-only
5101
+ * `effectsRead` for a completed effect's output). Workflow-scope only — a
5102
+ * guard outlives any activity, so `fieldRead` here carries no `scope`.
5103
+ * Desugar prints the STORED string spelling the deploy resolver and guard
5104
+ * refresh parse (`"$self"`, `"$now"`, `"$fields.<name>[.path]"`,
5105
+ * `"$effects['<name>'][.path]"`); those spellings are single-line strings
5106
+ * matched by anchored regexes, so a line break in a path would print an
5107
+ * unparseable read.
5108
+ */
4988
5109
  export declare type GuardRead = v.InferOutput<typeof GuardReadSchema>;
4989
5110
 
4990
5111
  declare const GuardReadSchema: v.VariantSchema<
@@ -5066,14 +5187,8 @@ declare const GuardReadSchema: v.VariantSchema<
5066
5187
  undefined
5067
5188
  >;
5068
5189
 
5069
- /** Stored guards carry the printed string reads (the deploy resolver's input). */
5070
5190
  declare const GuardSchema: v.StrictObjectSchema<
5071
5191
  {
5072
- /**
5073
- * Lake-id-segment grammar (`^[a-z0-9][a-z0-9-]*$`, deploy-enforced): the
5074
- * guard's lake `_id` derives from `(instanceId, name)` at stage entry.
5075
- * Unique per definition.
5076
- */
5077
5192
  name: v.SchemaWithPipe<
5078
5193
  readonly [
5079
5194
  v.StringSchema<undefined>,
@@ -5084,7 +5199,6 @@ declare const GuardSchema: v.StrictObjectSchema<
5084
5199
  description: v.OptionalSchema<v.StringSchema<undefined>, undefined>;
5085
5200
  match: v.StrictObjectSchema<
5086
5201
  {
5087
- /** Subject `_type`(s); empty matches any type. */
5088
5202
  types: v.OptionalSchema<
5089
5203
  v.ArraySchema<
5090
5204
  v.SchemaWithPipe<
@@ -5097,7 +5211,6 @@ declare const GuardSchema: v.StrictObjectSchema<
5097
5211
  >,
5098
5212
  undefined
5099
5213
  >;
5100
- /** Target docs as field reads (or the instance itself), resolved at deploy to bare ids + the resource. */
5101
5214
  idRefs: v.OptionalSchema<
5102
5215
  v.ArraySchema<
5103
5216
  v.SchemaWithPipe<
@@ -5110,7 +5223,6 @@ declare const GuardSchema: v.StrictObjectSchema<
5110
5223
  >,
5111
5224
  undefined
5112
5225
  >;
5113
- /** Glob id patterns (bare, resource-local). */
5114
5226
  idPatterns: v.OptionalSchema<
5115
5227
  v.ArraySchema<
5116
5228
  v.SchemaWithPipe<
@@ -5142,22 +5254,7 @@ declare const GuardSchema: v.StrictObjectSchema<
5142
5254
  },
5143
5255
  undefined
5144
5256
  >;
5145
- /**
5146
- * Lake GROQ predicate — a distinct eval context: delta-mode GROQ
5147
- * reading the `before()`/`after()` natives, `mutation`, `guard`, and
5148
- * `identity()`. Bare ids/fields only. Polarity: a result of strictly
5149
- * `true` ALLOWS the matched mutation; anything else (false, null, an
5150
- * evaluation error) DENIES. Omitted or empty means UNCONDITIONAL DENY.
5151
- */
5152
5257
  predicate: v.OptionalSchema<v.StringSchema<undefined>, undefined>;
5153
- /**
5154
- * Projected workflow fields the predicate reads as `guard.metadata.*` —
5155
- * the only bridge from the lake eval context (which cannot see `$fields`)
5156
- * to workflow fields. Each value is a deploy-time read — a typed
5157
- * {@link GuardRead} when authoring, the printed string spelling once
5158
- * stored — resolved into a bare value at deploy and re-synced by the
5159
- * post-field-op guard refresh.
5160
- */
5161
5258
  metadata: v.OptionalSchema<
5162
5259
  v.RecordSchema<
5163
5260
  v.SchemaWithPipe<
@@ -5307,6 +5404,15 @@ export declare const HISTORY_DISPLAY: {
5307
5404
  };
5308
5405
  };
5309
5406
 
5407
+ /**
5408
+ * One appended audit row. Every `actor` stamp on one is token-resolved
5409
+ * advisory provenance, never authenticated identity — the lake's own document
5410
+ * history is the authenticated ground truth.
5411
+ *
5412
+ * On the three stage-movement arms, `via` discriminates a condition-driven
5413
+ * transition (`'transition'`, the default when absent) from an admin override
5414
+ * (`'setStage'`), and the `reason` beside it is that override's free text.
5415
+ */
5310
5416
  export declare type HistoryEntry = HistoryEvent & {
5311
5417
  /**
5312
5418
  * The execution environment that committed this entry — inferred
@@ -5326,10 +5432,7 @@ declare type HistoryEvent =
5326
5432
  stage: StageName;
5327
5433
  fromStage?: StageName;
5328
5434
  transition?: string;
5329
- /** Discriminates filtered transitions ("transition", default) from
5330
- * admin overrides ("setStage"). */
5331
5435
  via?: "transition" | "setStage";
5332
- /** Admin-supplied free-text on setStage. */
5333
5436
  reason?: string;
5334
5437
  actor?: Actor;
5335
5438
  }
@@ -5362,17 +5465,9 @@ declare type HistoryEvent =
5362
5465
  activity: ActivityName;
5363
5466
  action: ActionName;
5364
5467
  actor?: Actor;
5365
- /**
5366
- * What KIND of driver fired the action, derived from {@link actor} at
5367
- * fire time (see `../activity-kind.ts`) — the audit-trail glyph's
5368
- * person/agent/service/engine axis. Absent when no actor was supplied.
5369
- */
5370
5468
  driverKind?: DriverKind;
5371
- /**
5372
- * The engine fired this action in a cascade (its `when` turned true) —
5373
- * {@link actor} is the cascading token that happened to execute it,
5374
- * not a caller who invoked `fireAction`.
5375
- */
5469
+ /** The engine fired this action in a cascade: `actor` is the cascading token that
5470
+ * executed it, not a caller who invoked `fireAction`. */
5376
5471
  triggered?: true;
5377
5472
  }
5378
5473
  | {
@@ -5395,9 +5490,6 @@ declare type HistoryEvent =
5395
5490
  origin: EffectOrigin;
5396
5491
  }
5397
5492
  | {
5398
- /** A queued effect settled — a reported completion (`done`/`failed`),
5399
- * or an abort cancelling it before dispatch (`cancelled`). One entry
5400
- * per `effectHistory` row, sharing its `effectKey`. */
5401
5493
  _key: string;
5402
5494
  _type: "effectCompleted";
5403
5495
  at: string;
@@ -5414,12 +5506,9 @@ declare type HistoryEvent =
5414
5506
  at: string;
5415
5507
  effectKey: string;
5416
5508
  effect: EffectName;
5417
- /** The expired claim that was released — who abandoned it and when. */
5418
5509
  claim: PendingEffectClaim;
5419
- /** How the stale claim was recovered: a drain taking it over for
5420
- * redispatch, or `sweepStaleClaims` force-releasing it. */
5510
+ /** `drain-takeover` = a drain redispatched it; `sweep` = `sweepStaleClaims` released it. */
5421
5511
  via: "drain-takeover" | "sweep";
5422
- /** The drainer/sweeper that released it. */
5423
5512
  actor?: Actor;
5424
5513
  }
5425
5514
  | {
@@ -5427,12 +5516,6 @@ declare type HistoryEvent =
5427
5516
  _type: "spawned";
5428
5517
  at: string;
5429
5518
  activity: ActivityName;
5430
- /**
5431
- * GDR pointer at the spawned child workflow instance. Stored as
5432
- * the typed `{id, type}` envelope — same shape every other GDR
5433
- * field in the engine uses (`ancestors[]`, the subworkflow registry,
5434
- * any `doc.ref` field entry). The `id` is the full GDR URI.
5435
- */
5436
5519
  instanceRef: GlobalDocumentReference;
5437
5520
  /** Identity of the `forEach` row that produced this child. */
5438
5521
  rowKey?: string;
@@ -5444,8 +5527,6 @@ declare type HistoryEvent =
5444
5527
  at: string;
5445
5528
  stage: StageName;
5446
5529
  activity: ActivityName;
5447
- /** The live child re-bound to the entering stage's cohort instead of
5448
- * being duplicated — its `forEach` row was rediscovered on re-entry. */
5449
5530
  instanceRef: GlobalDocumentReference;
5450
5531
  rowKey: string;
5451
5532
  }
@@ -5454,8 +5535,6 @@ declare type HistoryEvent =
5454
5535
  _type: "subworkflowResolved";
5455
5536
  at: string;
5456
5537
  activity: ActivityName;
5457
- /** The child observed terminal; its registry row now carries the
5458
- * terminal cache. */
5459
5538
  instanceRef: GlobalDocumentReference;
5460
5539
  status: "done" | "aborted";
5461
5540
  }
@@ -5463,9 +5542,8 @@ declare type HistoryEvent =
5463
5542
  _key: string;
5464
5543
  _type: "subworkflowOrphaned";
5465
5544
  at: string;
5466
- /** A child that names this instance in its `ancestors` reached terminal,
5467
- * but no registry row matches it — its completion cannot drive any
5468
- * gate. Loud audit record of a propagation dead-end. */
5545
+ /** A child naming this instance in its `ancestors` reached terminal, but no registry
5546
+ * row matches it — its completion cannot drive any gate. A loud dead-end record. */
5469
5547
  instanceRef: GlobalDocumentReference;
5470
5548
  detail: string;
5471
5549
  }
@@ -5473,9 +5551,7 @@ declare type HistoryEvent =
5473
5551
  _key: string;
5474
5552
  _type: "aborted";
5475
5553
  at: string;
5476
- /** The stage the instance was on when it was hard-stopped. */
5477
5554
  stage: StageName;
5478
- /** Admin-supplied free-text reason for the abort. */
5479
5555
  reason?: string;
5480
5556
  actor?: Actor;
5481
5557
  }
@@ -5484,27 +5560,17 @@ declare type HistoryEvent =
5484
5560
  _type: "opApplied";
5485
5561
  at: string;
5486
5562
  stage: StageName;
5487
- /** The boundary that ran the op. For an action fire (caller- or
5488
- * cascade-fired), `activity` + `action` are set; for a direct edit
5489
- * (the edit seam), `edit` is set and `activity` carries the field's activity when
5490
- * the edited field is activity-scope; for an effect's completion ops,
5491
- * `effect` names the effect. */
5563
+ /** The op's boundary: an action fire sets `activity` + `action`; an edit sets `edit`
5564
+ * (plus `activity` for an activity-scope field); completion ops set `effect`. */
5492
5565
  activity?: ActivityName;
5493
5566
  action?: ActionName;
5494
- /** Set when the op was a direct edit through the edit seam (`editField`),
5495
- * not an action. */
5496
5567
  edit?: true;
5497
- /** Set when the op came from an effect handler's completion (the state
5498
- * half of an effect); names the effect. */
5499
5568
  effect?: EffectName;
5500
- /** The op's `type` (e.g. `field.set`). */
5501
5569
  opType: string;
5502
- /** Field reference the op targeted (omitted for `status.set`). */
5503
5570
  target?: {
5504
5571
  scope: FieldScope;
5505
5572
  field: string;
5506
5573
  };
5507
- /** Concrete resolved params the op acted on. Captured for audit. */
5508
5574
  resolved?: Record<string, unknown>;
5509
5575
  actor?: Actor;
5510
5576
  }
@@ -5512,30 +5578,18 @@ declare type HistoryEvent =
5512
5578
  _key: string;
5513
5579
  _type: "fieldQueryDiscarded";
5514
5580
  at: string;
5515
- /** Scope of the field whose `initialValue: {type:'query'}` result was dropped. */
5516
5581
  scope: FieldScope;
5517
- /** The field entry name. */
5518
5582
  field: string;
5519
- /** Why the lake result was discarded — the shape mismatch against the
5520
- * declared kind. The field falls back to its default (null / []). */
5521
5583
  detail: string;
5522
5584
  };
5523
5585
 
5524
5586
  export { humanize };
5525
5587
 
5526
- /**
5527
- * The in-memory groq-js dataset filters evaluate against. Built once
5528
- * per cascade entry (in the shell), passed through to `evaluateFilter`
5529
- * (in the core) for every filter check.
5530
- */
5588
+ /** The in-memory groq-js dataset the engine's filters evaluate against. */
5531
5589
  export declare interface HydratedSnapshot {
5532
- /** All hydrated docs, keyed by GDR URI as `_id`. */
5590
+ /** Hydrated docs, keyed by GDR URI as `_id`. */
5533
5591
  docs: SanityDocument[];
5534
- /**
5535
- * The set of GDR URIs present in `docs`. Helpful for tests and shells
5536
- * that want to assert "is this doc in scope?" — the core eval pipeline
5537
- * itself doesn't read it.
5538
- */
5592
+ /** Existence-check helper; the core eval pipeline itself doesn't read it. */
5539
5593
  knownIds: Set<string>;
5540
5594
  }
5541
5595
 
@@ -5658,6 +5712,17 @@ export declare type InsightSite =
5658
5712
  activity?: string;
5659
5713
  };
5660
5714
 
5715
+ /**
5716
+ * The tag's instance partition as a listen filter — the one shared change
5717
+ * feed a preview store keeps itself fresh from (an event names the touched
5718
+ * instance; the store refetches that preview alone). Deliberately unfiltered
5719
+ * beyond the tag: one upstream listener serves every view, whatever each is
5720
+ * filtered to.
5721
+ */
5722
+ export declare function instanceChangesQuery(args: {
5723
+ tag: string;
5724
+ }): CompiledQuery;
5725
+
5661
5726
  /**
5662
5727
  * Mint the Sanity document `_id` for a workflow instance — a fresh
5663
5728
  * {@link randomKey} suffix, so every instance (root or spawned child) gets a
@@ -5697,6 +5762,17 @@ export declare class InstanceNotFoundError extends WorkflowError<"instance-not-f
5697
5762
  constructor(args: { instanceId: string; detail?: string });
5698
5763
  }
5699
5764
 
5765
+ /**
5766
+ * The preview projection over the same instances {@link instancesQuery}
5767
+ * matches — a `WorkflowInstancePreview` each, kilobytes lighter than the full
5768
+ * document (no snapshot, no audit trails), for surfaces that render many runs
5769
+ * at once. Parse results through `readInstancePreviewDoc`.
5770
+ */
5771
+ export declare function instancePreviewsQuery(args: {
5772
+ tag: string;
5773
+ filter?: InstancesQueryFilter;
5774
+ }): CompiledQuery;
5775
+
5700
5776
  /** Args for the verbs that address an instance without further input. */
5701
5777
  export declare interface InstanceRefArgs {
5702
5778
  instanceId: string;
@@ -5833,10 +5909,10 @@ export declare interface InstancesQueryFilter {
5833
5909
  document?: GdrUri;
5834
5910
  /**
5835
5911
  * The multi-document form of {@link InstancesQueryFilter.document}: one
5836
- * predicate matching instances that reference ANY of the given docs,
5912
+ * predicate matching instances that reference any of the given docs,
5837
5913
  * for consumers discovering instances across many open documents at once.
5838
5914
  * Merged with `document` when both are set. Callers may defensively recheck
5839
- * with {@link instanceWatchesDocument}. A DEFINED-but-EMPTY
5915
+ * with {@link instanceWatchesDocument}. A defined but empty
5840
5916
  * array matches nothing (the GROQ-natural reading of membership in an
5841
5917
  * empty set) — omit the field for the unconstrained every-in-flight read.
5842
5918
  */
@@ -5846,7 +5922,7 @@ export declare interface InstancesQueryFilter {
5846
5922
  * a consumer tracking freshly-started instances (not yet referencing any
5847
5923
  * registered doc) sees them in the same live read. Bare ids only: an
5848
5924
  * instance's `_id` is never a GDR URI, so a URI here is a caller bug and
5849
- * is rejected. A DEFINED-but-EMPTY array matches nothing, exactly like
5925
+ * is rejected. A defined but empty array matches nothing, exactly like
5850
5926
  * {@link InstancesQueryFilter.documents}.
5851
5927
  */
5852
5928
  ids?: readonly string[];
@@ -5857,13 +5933,25 @@ export declare interface InstancesQueryFilter {
5857
5933
  /** Include completed/aborted instances (default: in-flight only). */
5858
5934
  includeCompleted?: boolean;
5859
5935
  /**
5860
- * Cap the read to the NEWEST `limit` instances — the query flips to
5936
+ * Cap the read to the newest `limit` instances — the query flips to
5861
5937
  * `startedAt desc` and slices, so a bounded consumer (a dashboard over an
5862
5938
  * unbounded dataset) reads the most recent rows instead of the oldest.
5863
5939
  * Unlimited reads keep the ascending order adapters index by. Must be a
5864
5940
  * positive integer.
5865
5941
  */
5866
5942
  limit?: number;
5943
+ /**
5944
+ * Keyset cursor into the newest-first order: only instances strictly older
5945
+ * than this position. Pass the last row of the previous page, and the next
5946
+ * `limit` rows continue where it ended. A cursor rather than an offset, so
5947
+ * rows starting or concluding between pages can't shift what a page holds.
5948
+ * Requires `limit`: pages only exist in the newest-first sliced read.
5949
+ */
5950
+ before?: {
5951
+ /** The `_id` tiebreak for rows sharing `startedAt`. */
5952
+ id: string;
5953
+ startedAt: string;
5954
+ };
5867
5955
  }
5868
5956
 
5869
5957
  /**
@@ -5883,9 +5971,8 @@ export declare function instanceWatchesDocument(
5883
5971
  document: GdrUri,
5884
5972
  ): boolean;
5885
5973
 
5886
- /** The trigger split: a `when` action is cascade-fired; without one it is
5887
- * fireAction-fired. The single spelling of that test — structural over
5888
- * `when` so authoring and stored shapes both qualify. */
5974
+ /** The canonical cascade-fired test: structural on `when`, so both authored
5975
+ * and stored shapes qualify. */
5889
5976
  export declare function isCascadeFired(action: {
5890
5977
  when?: string | undefined;
5891
5978
  }): boolean;
@@ -5957,7 +6044,8 @@ export declare function isInputSourced(
5957
6044
  * apart from other array kinds (e.g. the `todoList` sugar's
5958
6045
  * `{label, status}`). Accepts both vocabularies — a deployed definition
5959
6046
  * entry (`type`) and a resolved instance entry (`_type`) — so start-time
5960
- * and runtime surfaces share one verdict.
6047
+ * and runtime surfaces share one verdict. Resolved-entry overload last, as
6048
+ * on {@link isTodoListEntry}.
5961
6049
  */
5962
6050
  export declare function isNotesEntry(entry: FieldEntry): entry is FieldEntry & {
5963
6051
  type: "array";
@@ -6058,7 +6146,9 @@ export declare function isTerminalStage(stage: Stage): boolean;
6058
6146
  * `status` rows, which tells a todo list apart from other array kinds (e.g.
6059
6147
  * the `notes` sugar's `{body, actor, at}`). Accepts both vocabularies —
6060
6148
  * a deployed definition entry (`type`) and a resolved instance entry
6061
- * (`_type`) — so start-time and runtime surfaces share one verdict.
6149
+ * (`_type`) — so start-time and runtime surfaces share one verdict. The
6150
+ * resolved-entry overload comes last: contextual typing reads an overloaded
6151
+ * argument's FINAL signature, which `.filter(isTodoListEntry)` needs.
6062
6152
  */
6063
6153
  export declare function isTodoListEntry(
6064
6154
  entry: FieldEntry,
@@ -6087,31 +6177,23 @@ export declare function isTodoListItem(row: unknown): row is TodoListItem;
6087
6177
  * did not. The shape is legal and resumable — `startInstance` with the same
6088
6178
  * `instanceId` completes the outstanding commits. Readers should present it
6089
6179
  * as an incomplete start, never as a normal run sitting at its initial
6090
- * stage. Terminal instances are excluded: an aborted never-primed husk
6180
+ * stage. Terminal instances are excluded: an aborted never-primed instance
6091
6181
  * reads as aborted, not as still-resumable.
6092
6182
  */
6093
6183
  export declare function isUnprimed(
6094
6184
  instance: Pick<WorkflowInstance, "stages" | "completedAt" | "abortedAt">,
6095
6185
  ): boolean;
6096
6186
 
6097
- /**
6098
- * Deterministic id so deploy/retract are query-free and idempotent. Derived
6099
- * from the guard's authored `name` — an author-controlled handle that stays
6100
- * stable when guards are reordered or inserted (a positional index would
6101
- * silently shift).
6102
- */
6187
+ /** Deterministic id (from the guard's authored `name`) so deploy/retract are query-free and idempotent; a positional index would silently shift if guards are reordered. */
6103
6188
  export declare function lakeGuardId(args: {
6104
6189
  instanceDocId: string;
6105
6190
  guardName: string;
6106
6191
  }): string;
6107
6192
 
6108
6193
  /**
6109
- * The id a lake-facing check binds for an actor: the resource-local
6110
- * principal id when the namespaces diverge, otherwise the actor's own
6111
- * (account-global) id. Every advisory that must agree with the lake's
6112
- * `identity()` — guard previews and pre-flights, the anchor ACL's `$can`
6113
- * grant filters — resolves through this one rule; binding `actor.id`
6114
- * directly at a lake edge reintroduces the divergent-identity mismatch.
6194
+ * The one rule every lake-facing identity check (guard previews/pre-flights, `$can` grant filters)
6195
+ * must resolve through to agree with the lake's own `identity()`; binding `actor.id` directly at a
6196
+ * lake edge reintroduces the divergent-identity mismatch.
6115
6197
  */
6116
6198
  export declare function lakePrincipalId(args: {
6117
6199
  actor: {
@@ -6171,11 +6253,6 @@ declare type LiteralExpr = {
6171
6253
  value: unknown;
6172
6254
  };
6173
6255
 
6174
- /**
6175
- * One loaded doc plus the resource it came from. The shell builds
6176
- * this list by routing reads to the right client for each doc, then
6177
- * hands it to `buildSnapshot`.
6178
- */
6179
6256
  export declare interface LoadedDoc {
6180
6257
  doc: SanityDocument;
6181
6258
  resource: WorkflowResource;
@@ -6192,18 +6269,17 @@ export declare interface LogicalRef {
6192
6269
  version?: number | "latest";
6193
6270
  }
6194
6271
 
6272
+ /**
6273
+ * Off-system deep-link target — render-only metadata whose presence marks an
6274
+ * activity as off-system (BPMN Manual Task). Either a static URL, or a field
6275
+ * reference whose resolved document the consumer opens; deploy checks the
6276
+ * `field` variant points at a doc-valued entry.
6277
+ */
6195
6278
  export declare type ManualTarget = v.InferOutput<
6196
6279
  typeof StoredManualTargetSchema
6197
6280
  >;
6198
6281
 
6199
- /**
6200
- * Evaluate a grant's GROQ filter against a single document with the
6201
- * supplied identity. Returns true iff the document survives the filter.
6202
- *
6203
- * The implementation parses `*[<filter>]` once per filter string,
6204
- * evaluates against a singleton dataset, and asks the result for its
6205
- * length — `length === 1` means the doc passed.
6206
- */
6282
+ /** Returns true iff `document` survives `filter`'s GROQ predicate under the supplied identity. */
6207
6283
  declare function matchesFilter(args: {
6208
6284
  document: {
6209
6285
  _id?: string;
@@ -6217,10 +6293,9 @@ declare function matchesFilter(args: {
6217
6293
  export { MAX_COUNTERFACTUAL_INDEX };
6218
6294
 
6219
6295
  /**
6220
- * The oldest engine model that can safely read a persisted engine document.
6221
- * The engine always writes the stamp pair, so a `modelVersion`
6222
- * with no `minReaderModel` is malformed foreign data — read conservatively:
6223
- * the stamp itself is the floor. A doc with neither is model 0 (floor 0).
6296
+ * The engine always writes both stamps together, so a bare `modelVersion` with no
6297
+ * `minReaderModel` is malformed foreign data; that case reads the version itself as the
6298
+ * floor (conservative fallback).
6224
6299
  */
6225
6300
  export declare function minReaderModelOf(doc: object): number;
6226
6301
 
@@ -6279,11 +6354,9 @@ export declare function missingRequiredInputs(args: {
6279
6354
  }[];
6280
6355
 
6281
6356
  /**
6282
- * A persisted engine document requires a NEWER reader than this engine: its
6283
- * `minReaderModel` floor is above {@link DATA_MODEL_VERSION}. Reading it
6284
- * could silently misinterpret whatever the newer model reshaped, so every
6285
- * engine read path fails hard instead. The remediation is always the same:
6286
- * upgrade `@sanity/workflow-engine`.
6357
+ * Thrown when a document's reader floor exceeds {@link DATA_MODEL_VERSION} reading it
6358
+ * could silently misinterpret a newer model's reshape, so the read fails hard instead.
6359
+ * Fix: upgrade `@sanity/workflow-engine`.
6287
6360
  */
6288
6361
  export declare class ModelVersionAheadError extends WorkflowError<"model-version-ahead"> {
6289
6362
  readonly documentId: string;
@@ -6297,13 +6370,10 @@ export declare class ModelVersionAheadError extends WorkflowError<"model-version
6297
6370
  });
6298
6371
  }
6299
6372
 
6300
- /** The data model a persisted engine document conforms to. A document with no
6301
- * stamp was last written before governance existed — model 0. Reads the
6302
- * stamp structurally (persisted docs reach the gate as typed docs,
6303
- * projections, and raw snapshot reads alike); a non-number stamp is foreign
6304
- * data the engine never wrote and also reads as model 0. */
6373
+ /** A document with no stamp, or a non-number stamp (foreign data this engine never wrote), reads as model 0. */
6305
6374
  export declare function modelVersionOf(doc: object): number;
6306
6375
 
6376
+ /** The lake operations a guard can gate — see the guard types in ./authorization.ts. */
6307
6377
  declare const MUTATION_GUARD_ACTIONS: readonly [
6308
6378
  "create",
6309
6379
  "update",
@@ -6349,7 +6419,8 @@ export declare type MutationGuardAction =
6349
6419
  * compile inputs, so the field set lives in one place.
6350
6420
  */
6351
6421
  export declare interface MutationGuardBody {
6352
- /** Engine-layer: the single datasource this guard belongs to. */
6422
+ /** The single datasource this guard belongs to — the engine spans
6423
+ * datasources and must record which one, since the lake is per-datasource and infers the resource from storage. */
6353
6424
  resourceType: string;
6354
6425
  resourceId: string;
6355
6426
  /**
@@ -6420,6 +6491,13 @@ export declare class MutationGuardDeniedError extends WorkflowError<"mutation-gu
6420
6491
  export declare interface MutationGuardDoc extends MutationGuardBody {
6421
6492
  _id: string;
6422
6493
  _type: typeof GUARD_DOC_TYPE;
6494
+ /**
6495
+ * Deliberately NO engine data-model stamp (`modelVersion`/`minReaderModel`)
6496
+ * — this doc format is the lake's forthcoming contract, and the engine
6497
+ * must not grow fields on a shape it doesn't own. Assigned by the lake on
6498
+ * write — never sent on create (an empty-string value fails datetime
6499
+ * validation).
6500
+ */
6423
6501
  _rev?: string;
6424
6502
  _createdAt?: string;
6425
6503
  _updatedAt?: string;
@@ -6463,15 +6541,14 @@ export declare interface NoteItem {
6463
6541
  at?: string | null;
6464
6542
  }
6465
6543
 
6466
- /**
6467
- * `notes` an append-only audit/comment log. Sugar over `array of object
6468
- * { body, actor, at }` (the `actor`/`at` sub-fields match the `audit` op's
6469
- * stamp names, so it pairs with it). Never a stored kind.
6470
- */
6544
+ /** An append-only audit/comment log: sugar over `array of object {body, actor, at}` — the `actor`/`at`
6545
+ * names match the `audit` op's stamp fields, so it pairs with it. Never a stored kind. */
6471
6546
  declare type NotesField = FieldBase<AuthoringEditable, GroupMembership> & {
6472
6547
  type: "notes";
6473
6548
  };
6474
6549
 
6550
+ /** A `field.updateWhere` / `field.removeWhere` op's `where` selects rows to
6551
+ * mutate with rendered-scope GROQ (`$row`, `$params` bound) — row selection, not a gate; an unevaluable row never matches. */
6475
6552
  export declare type Op = v.InferOutput<typeof StoredOpSchema>;
6476
6553
 
6477
6554
  /**
@@ -6482,6 +6559,10 @@ export declare const OP_DISPLAY: {
6482
6559
  title: string;
6483
6560
  description: string;
6484
6561
  };
6562
+ "field.setIfMissing": {
6563
+ title: string;
6564
+ description: string;
6565
+ };
6485
6566
  "field.unset": {
6486
6567
  title: string;
6487
6568
  description: string;
@@ -6490,6 +6571,14 @@ export declare const OP_DISPLAY: {
6490
6571
  title: string;
6491
6572
  description: string;
6492
6573
  };
6574
+ "field.inc": {
6575
+ title: string;
6576
+ description: string;
6577
+ };
6578
+ "field.dec": {
6579
+ title: string;
6580
+ description: string;
6581
+ };
6493
6582
  "field.updateWhere": {
6494
6583
  title: string;
6495
6584
  description: string;
@@ -6604,22 +6693,26 @@ export declare interface ParsedGdr {
6604
6693
  export declare function parseGdr(uri: string): ParsedGdr;
6605
6694
 
6606
6695
  /**
6607
- * Parse a fetched guard document, failing hard with a
6608
- * {@link PersistedDocShapeError} naming the document and every offending
6609
- * field. No model-version gate: the guard doc carries no stamp by design —
6610
- * its `_type` cutover is its versioning event.
6696
+ * Throws {@link PersistedDocShapeError} on shape mismatch. Unlike other
6697
+ * persisted docs, this doc carries no model-version stamp to gate on.
6611
6698
  */
6612
6699
  export declare function parseGuardDocument(doc: unknown): MutationGuardDoc;
6613
6700
 
6614
6701
  /**
6615
6702
  * Parse a fetched `sanity.workflow.instance` document, failing hard with a
6616
6703
  * {@link PersistedDocShapeError} naming the document and every offending
6617
- * field. The caller's model-version gate (`assertReadableModel`) comes
6618
- * FIRST a doc from beyond the reader floor is a governed
6704
+ * field. The caller's model-version gate (`assertReadableModel`) must run
6705
+ * first: a doc from beyond the reader floor is a governed
6619
6706
  * `ModelVersionAheadError`, not a shape error.
6620
6707
  */
6621
6708
  export declare function parseInstanceDocument(doc: unknown): WorkflowInstance;
6622
6709
 
6710
+ /** {@link parseInstanceDocument}'s row-projection counterpart, with the same
6711
+ * gate-first contract. */
6712
+ export declare function parseInstancePreviewDocument(
6713
+ doc: unknown,
6714
+ ): WorkflowInstancePreview;
6715
+
6623
6716
  /**
6624
6717
  * Parse a resource-shaped GDR (`<type>:<id>`, no document part) into the
6625
6718
  * {@link WorkflowResource} it names. The one grammar for resource addresses —
@@ -6865,25 +6958,39 @@ export { quoted };
6865
6958
  export declare const READER_MODEL_ROLLOUT_URL =
6866
6959
  "https://www.sanity.io/docs/editorial-workflows/prerelease";
6867
6960
 
6868
- /** A producer has not explicitly acknowledged this engine's writer capability. */
6961
+ /** A producer has not acknowledged the floor required by its submitted definitions. */
6869
6962
  export declare class ReaderModelAcknowledgementError extends WorkflowError<"reader-model-acknowledgement"> {
6870
6963
  readonly code = "WORKFLOW_READER_MODEL_ACKNOWLEDGEMENT_MISMATCH";
6871
6964
  readonly expectedMinReaderModel: unknown;
6965
+ readonly requiredMinReaderModel: number;
6872
6966
  readonly engineMinReaderModel = 4;
6873
- readonly engineModelVersion = 5;
6967
+ readonly engineMaxReaderModel = 8;
6968
+ readonly engineModelVersion = 8;
6874
6969
  readonly documentationUrl =
6875
6970
  "https://www.sanity.io/docs/editorial-workflows/prerelease";
6876
- constructor(expectedMinReaderModel: unknown, context?: string);
6971
+ constructor(
6972
+ expectedMinReaderModel: unknown,
6973
+ options?: {
6974
+ requiredMinReaderModel?: number;
6975
+ context?: string;
6976
+ },
6977
+ );
6877
6978
  }
6878
6979
 
6879
6980
  /**
6880
- * The one spelling of the instance read discipline model gate
6881
- * ({@link assertReadableModel}) first, shape parse
6882
- * ({@link parseInstanceDocument}) second shared by the point-read funnel
6981
+ * The single definition of the instance read discipline (model gate
6982
+ * {@link assertReadableModel} first, shape parse
6983
+ * {@link parseInstanceDocument} second), shared by the point-read funnel
6883
6984
  * above and the list-read sites that fetch instance rows in bulk.
6884
6985
  */
6885
6986
  export declare function readInstanceDoc(doc: SanityDocument): WorkflowInstance;
6886
6987
 
6988
+ /** {@link readInstanceDoc}'s preview-projection counterpart: the same
6989
+ * gate-then-parse order over an `instancePreviewsQuery` result. */
6990
+ export declare function readInstancePreviewDoc(
6991
+ doc: unknown,
6992
+ ): WorkflowInstancePreview;
6993
+
6887
6994
  /**
6888
6995
  * Whether a watched ref reads RAW — never perspective-scoped. The
6889
6996
  * instance, its ancestors, and its spawned children (all instance docs), and
@@ -6895,16 +7002,10 @@ export declare function readInstanceDoc(doc: SanityDocument): WorkflowInstance;
6895
7002
  */
6896
7003
  export declare function readsRaw(ref: { type: string }): boolean;
6897
7004
 
6898
- /**
6899
- * Whether a GROQ expression reads its ROOT document the candidate document
6900
- * a `start.filter` binds as root. A bare attribute access (`_type == 'task'`)
6901
- * or `@` in the OUTER scope reads the root; the same inside a construct that
6902
- * rebinds the implicit `this` per element (`*[...]` filters, projections,
6903
- * `map`/pipe traversals) addresses THOSE items, so it doesn't. `^` (Parent)
6904
- * climbs scopes — one that escapes past the outermost scope lands back on the
6905
- * root and counts, wherever it is nested. A malformed expression reads
6906
- * nothing here ({@link conditionSyntaxIssues} owns the parse error).
6907
- */
7005
+ /** Whether a GROQ expression reads its ROOT document — the candidate a
7006
+ * `start.filter` binds, not an item inside a rebound scope (filters, `map`). A `^`
7007
+ * that escapes past the outermost scope lands back on the root and counts. A
7008
+ * malformed expression reads nothing here, so it returns `false`. */
6908
7009
  export declare function readsRootDocument(groq: string): boolean;
6909
7010
 
6910
7011
  /** Make a GDR pointer to a Canvas-resource doc. */
@@ -6972,15 +7073,10 @@ export declare class RefResourceUndeclaredError extends WorkflowError<"ref-resou
6972
7073
  export declare function refsOf(def: WorkflowDefinition): LogicalRef[];
6973
7074
 
6974
7075
  /**
6975
- * The GDR `type`s in a reference-kind ({@link refKindAcceptsTypes}) value
6976
- * that the entry's declared accepted `types` reject — empty when the value
6977
- * conforms, the entry declares no `types`, or the kind isn't a ref. A GDR's
6978
- * `type` names the target document's schema type, so this is the
6979
- * declared-target-type contract. Skips anything that isn't GDR-shaped — the
6980
- * shape schemas scream about those. Boundaries that need their own error
6981
- * framing (the spawn `with` projection gates its remediation hint on the
6982
- * generic `"document"` type being among the rejects) read this; everything
6983
- * else goes through {@link refTypeIssues} / {@link checkFieldValue}.
7076
+ * GDR `type`s in a reference-kind ({@link refKindAcceptsTypes}) value that the
7077
+ * entry's declared `types` reject — empty when it conforms, no `types` are
7078
+ * declared, or the kind isn't a ref. Skips non-GDR-shaped values; the shape
7079
+ * schemas already reject those.
6984
7080
  */
6985
7081
  export declare function rejectedRefTypes(args: {
6986
7082
  entryType: string;
@@ -7046,6 +7142,11 @@ export declare type RemediationVerb =
7046
7142
  | "set-stage"
7047
7143
  | "abort";
7048
7144
 
7145
+ /** The reader model a deployment must acknowledge for its submitted definitions. */
7146
+ export declare function requiredDefinitionReaderModel(
7147
+ definitions: readonly unknown[],
7148
+ ): number;
7149
+
7049
7150
  /**
7050
7151
  * Thrown when a workflow is started (or a child spawned) without a value for
7051
7152
  * a field entry marked `required`. Mirrors {@link ActionParamsInvalidError}:
@@ -7101,14 +7202,6 @@ export declare interface RequirementDescriptor {
7101
7202
  */
7102
7203
  export declare const RESERVED_CONDITION_VARS: readonly string[];
7103
7204
 
7104
- /**
7105
- * What to reset a stuck activity INTO — the two non-`failed` outcomes that
7106
- * unstick a stage gated on it. `active` re-runs it (back in progress, so a
7107
- * caller drives it to completion again); `skipped` bypasses it (terminal but
7108
- * resolved, so `$allActivitiesDone` can satisfy and a gated exit transition
7109
- * fire). `done` is deliberately absent: a reset is recovery, not a silent
7110
- * declaration that the work succeeded.
7111
- */
7112
7205
  declare const RESET_ACTIVITY_TARGETS: readonly ["active", "skipped"];
7113
7206
 
7114
7207
  export declare interface ResetActivityArgs extends DedupableOperationArgs {
@@ -7136,14 +7229,24 @@ export declare type ResetActivityResult =
7136
7229
  to: ResetActivityTarget;
7137
7230
  };
7138
7231
 
7232
+ /**
7233
+ * What to reset a stuck activity INTO — the two non-`failed` outcomes that
7234
+ * unstick a stage gated on it. `active` re-runs it (back in progress, so a
7235
+ * caller drives it to completion again); `skipped` bypasses it (terminal but
7236
+ * resolved, so `$allActivitiesDone` can satisfy and a gated exit transition
7237
+ * fire). `done` is deliberately absent: a reset is recovery, not a silent
7238
+ * declaration that the work succeeded.
7239
+ */
7139
7240
  export declare type ResetActivityTarget =
7140
7241
  (typeof RESET_ACTIVITY_TARGETS)[number];
7141
7242
 
7142
7243
  /**
7143
- * Resolve the engine's `WorkflowAccess` for a client — both halves
7144
- * fetched from its token in parallel and cached. Throws if the client
7145
- * can't yield an actor — the engine refuses to operate without an
7146
- * identity.
7244
+ * Resolve the engine's `WorkflowAccess` for a client — actor and grants
7245
+ * (when a path is supplied) fetched from its token in parallel and cached.
7246
+ * Throws if the client can't yield an actor — the engine refuses to operate
7247
+ * without an identity. A grants-fetch failure degrades open instead: the
7248
+ * rendered `$can` stays undefined and the real Sanity write boundary still
7249
+ * enforces. Does not fetch User Attributes; see {@link resolveUserAttributes}.
7147
7250
  */
7148
7251
  export declare function resolveAccess(
7149
7252
  taggedClient: WorkflowClient,
@@ -7185,8 +7288,9 @@ export declare interface ResolveClientActorArgs {
7185
7288
  * `resolvedAt` — the lake-read time — so `resolvedAt` is provenance-driven,
7186
7289
  * not kind-specific. `object` / `array` entries carry their declared
7187
7290
  * sub-field shape (`fields` / `of`) — and the reference kinds
7188
- * ({@link refKindAcceptsTypes}) their declared accepted `types` — so the
7189
- * instance is self-describing for op-time validation and rendering.
7291
+ * ({@link refKindAcceptsTypes}) their declared accepted `types`, and
7292
+ * assignment kinds their eligible `roles` so the instance is
7293
+ * self-describing for op-time validation and rendering.
7190
7294
  */
7191
7295
  export declare type ResolvedFieldEntry = {
7192
7296
  [K in FieldKind]: {
@@ -7210,6 +7314,11 @@ export declare type ResolvedFieldEntry = {
7210
7314
  of: FieldShape[];
7211
7315
  }
7212
7316
  : Record<never, never>) &
7317
+ (K extends "assignee" | "assignees"
7318
+ ? {
7319
+ roles?: string[];
7320
+ }
7321
+ : Record<never, never>) &
7213
7322
  (K extends "doc.ref" | "doc.refs" | "subject"
7214
7323
  ? {
7215
7324
  types?: string[];
@@ -7217,14 +7326,8 @@ export declare type ResolvedFieldEntry = {
7217
7326
  : Record<never, never>);
7218
7327
  }[FieldKind];
7219
7328
 
7220
- /**
7221
- * The resolved entry a field site names, read from the instance's runtime
7222
- * `fields[]` at the site's scope — the instance copy that carries what an
7223
- * evaluation doesn't (the declared `of`/`fields` shape). Stage- and
7224
- * activity-scope sites resolve against the OPEN stage. `undefined` when the
7225
- * field hasn't been resolved yet (e.g. an activity-scope field before its
7226
- * activity activated).
7227
- */
7329
+ /** Resolves against the OPEN stage for stage/activity scopes; `undefined`
7330
+ * when the field hasn't resolved yet (e.g. an activity field before activation). */
7228
7331
  export declare function resolveFieldEntry(
7229
7332
  instance: WorkflowInstance,
7230
7333
  site: {
@@ -7234,6 +7337,17 @@ export declare function resolveFieldEntry(
7234
7337
  },
7235
7338
  ): ResolvedFieldEntry | undefined;
7236
7339
 
7340
+ /**
7341
+ * Resolve advisory `$attributes` for the caller-bound projection — project →
7342
+ * org → global-host attributes page. Cached per (client, orgId). Expected
7343
+ * absences (401–404) leave the bag unbound; unexpected failures throw.
7344
+ * Call only from soft-gate paths (evaluate / fireAction filter re-check /
7345
+ * editField), never from ticks or drainers.
7346
+ */
7347
+ export declare function resolveUserAttributes(
7348
+ taggedClient: WorkflowClient,
7349
+ ): Promise<UserAttributes | undefined>;
7350
+
7237
7351
  /**
7238
7352
  * A map binding each resource-alias name to the physical {@link WorkflowResource}
7239
7353
  * it resolves to at deploy. Parallels the role-alias map: where role aliases map
@@ -7247,26 +7361,20 @@ export declare type ResourceAliases = Record<string, WorkflowResource>;
7247
7361
  * Collapse a deployment's `resourceAliases` bindings into the
7248
7362
  * {@link ResourceAliases} map (handle name → physical resource) that
7249
7363
  * `deployDefinitions` expands `@<handle>:` references against. Deploy-time
7250
- * only — the map never reaches any other verb.
7364
+ * only — the map never reaches any other verb. A duplicate binding name
7365
+ * silently overwrites here (last wins), which is why `DeploymentSchema`
7366
+ * rejects one at parse time, before this ever runs.
7251
7367
  */
7252
7368
  export declare function resourceAliasesToMap(
7253
7369
  resourceAliases: WorkflowDeployment["resourceAliases"],
7254
7370
  ): ResourceAliases;
7255
7371
 
7256
7372
  /**
7257
- * Routing override for cross-resource reads (subject + ancestor docs that
7258
- * live in a different Sanity resource than the workflow). Called with a
7259
- * parsed GDR; return a client for that resource, or `undefined` to let the
7260
- * engine route it its own client for the workflow resource, a derived
7261
- * sibling ({@link WorkflowClient.withConfig}) for anything else.
7262
- *
7263
- * Serving a resource also DECLARES it on the written-ref surface: the write
7264
- * boundaries probe this resolver per ref, so narrowing a resolver rejects
7265
- * refs to the resources it stops serving.
7266
- *
7267
- * Engine-owned verb scopes rebind resolved clients onto
7268
- * `ENGINE_API_VERSION`. Effect handlers derive request-tagged siblings from
7269
- * resolver clients so their concrete APIs remain available and attributed.
7373
+ * Cross-resource read routing override return a client for the parsed
7374
+ * GDR's resource, or `undefined` to let the engine route it. Serving a
7375
+ * resource also declares it on the written-ref surface, so narrowing this
7376
+ * resolver rejects refs to resources it stops serving; engine verb scopes
7377
+ * also rebind any returned client onto their own API version.
7270
7378
  */
7271
7379
  export declare type ResourceClientResolver = (
7272
7380
  parsed: ParsedGdr,
@@ -7315,38 +7423,22 @@ export declare interface ResourceSurface {
7315
7423
  * the stage and must keep its lock) or gone (leave the lock as the orphan
7316
7424
  * seam rather than silently unlocking a vanished instance — the same
7317
7425
  * over-lock direction as deploy).
7426
+ *
7427
+ * Guard revisions are observed before the live-stage gate, then only those
7428
+ * revisions are deleted: a deploy landing in between changes the revision,
7429
+ * so the delete's revision fence fails instead of deleting the active guard.
7318
7430
  */
7319
7431
  export declare function retractStageGuards(args: StageGuardArgs): Promise<void>;
7320
7432
 
7321
- export declare type RoleAliases = v.InferOutput<typeof RoleAliasesSchema>;
7322
-
7323
7433
  /**
7324
- * Role aliasing the "can be fulfilled by" map, an authoring convenience.
7325
- * A `roles` gate (or an `assignees` entry) names the role the author writes;
7326
- * but the SAME capability is often carried by different role names depending
7327
- * on how a given project deploys its Content Lake roles, and several roles may
7328
- * legitimately do the job. Rather than enumerate every equivalent role inline
7329
- * in each gate — or fork the definition per deployment — declare once here
7330
- * which other roles also fulfill it.
7331
- *
7332
- * Each key is a role a gate/assignee names; its value lists the roles that
7333
- * also satisfy it. The reserved key `"*"` lists roles that fulfill ANY gate
7334
- * (e.g. `"*": ["administrator"]` — whatever this deployment's broad role is).
7335
- * `"*"` is the spelling authors write; it is rewritten to a lake-safe stored
7336
- * key before the definition is persisted, since the Content Lake rejects `"*"`
7337
- * as a document attribute name (see {@link normalizeRoleAliases}).
7338
- *
7339
- * Applied as an in-place expansion of the REQUIRED side, never the actor's
7340
- * roles: the `roles` gate bakes the expanded membership into its desugared
7341
- * GROQ at define time; `$assigned` expands the assignee's role at match time
7342
- * (see {@link expandRequiredRoles}). Carried into the stored definition for
7343
- * that runtime half.
7344
- *
7345
- * Advisory, like every engine gate — an alias only predicts what the
7346
- * deployment's Content Lake ACLs already allow, it never grants access. An
7347
- * alias the lake won't honor makes the gate predict "allowed" for a write the
7348
- * lake then rejects, so keep it true to what's actually deployed.
7434
+ * Roles that may fulfil each authored role. Aliases widen action gates,
7435
+ * `$assigned`, and assignment-field user eligibility by expanding the required
7436
+ * side; they never alter an actor's roles. Collective role assignees remain
7437
+ * literal ownership values and are not widened by this map. The authored `"*"`
7438
+ * key lists universal fulfillers and is normalized before persistence.
7349
7439
  */
7440
+ export declare type RoleAliases = v.InferOutput<typeof RoleAliasesSchema>;
7441
+
7350
7442
  declare const RoleAliasesSchema: v.RecordSchema<
7351
7443
  v.SchemaWithPipe<
7352
7444
  readonly [
@@ -7421,6 +7513,8 @@ export declare interface ScopedInitialFieldDeclarations {
7421
7513
  }[];
7422
7514
  }
7423
7515
 
7516
+ export declare type Semantic = SignalSemantic | CustomSemantic;
7517
+
7424
7518
  export { sentenceCase };
7425
7519
 
7426
7520
  export declare interface SessionArgs {
@@ -7442,6 +7536,14 @@ export declare interface SetStageArgs extends DedupableOperationArgs {
7442
7536
  initialFields?: InitialFieldValue[];
7443
7537
  }
7444
7538
 
7539
+ export declare const SIGNAL_SEMANTICS: readonly [
7540
+ "signal.positive",
7541
+ "signal.caution",
7542
+ "signal.critical",
7543
+ ];
7544
+
7545
+ export declare type SignalSemantic = (typeof SIGNAL_SEMANTICS)[number];
7546
+
7445
7547
  /**
7446
7548
  * No-op logger. Default for library callers that don't want any
7447
7549
  * output unless explicitly opted in.
@@ -7504,6 +7606,18 @@ export declare class SpawnContractsInvalidError extends WorkflowError<"spawn-con
7504
7606
  constructor(args: { issues: SpawnContractIssue[]; message: string });
7505
7607
  }
7506
7608
 
7609
+ /**
7610
+ * A pure container — name, fields, guards, activities, transitions, no
7611
+ * behaviour of its own. Activities own enter, transitions own exit and
7612
+ * arrival; a stage with no transitions IS terminal (structural, nothing to
7613
+ * declare or mis-declare). `guards` are lake mutation guards active while
7614
+ * the stage holds, each compiling to a persisted guard document deployed on
7615
+ * stage entry and retracted on exit. `editable` is a tighten-only override
7616
+ * for the time the stage holds, keyed by an in-scope field name: the field's
7617
+ * own `editable` is the ceiling, ANDed with the stage value at runtime, so an
7618
+ * override can only NARROW — never open a field the baseline left closed. An
7619
+ * unlisted field inherits its baseline.
7620
+ */
7507
7621
  export declare type Stage = StageFields<
7508
7622
  FieldEntry,
7509
7623
  Activity,
@@ -7540,6 +7654,8 @@ export declare interface StageEntry {
7540
7654
 
7541
7655
  export declare interface StageEvaluation {
7542
7656
  stage: Stage;
7657
+ /** The stage's advisory workflow meaning, unchanged from its definition. */
7658
+ semantics?: Semantic[] | undefined;
7543
7659
  activities: ActivityEvaluation[];
7544
7660
  transitions: TransitionEvaluation[];
7545
7661
  /** The stage's causal-autonomy rollup — will it progress without a caller,
@@ -7550,6 +7666,7 @@ export declare interface StageEvaluation {
7550
7666
  /** Type-mirror of {@link stageFields}, parameterised over field/activity/transition/guard/editable. */
7551
7667
  declare type StageFields<TField, TActivity, TTransition, TGuard, TEditable> = {
7552
7668
  name: string;
7669
+ semantics?: Semantic[] | undefined;
7553
7670
  title?: string | undefined;
7554
7671
  description?: string | undefined;
7555
7672
  groups?: Group[] | undefined;
@@ -7608,10 +7725,12 @@ export declare class StaleEffectClaimError extends WorkflowError<"stale-effect-c
7608
7725
  * not the rendered condition scope (no {@link ConditionVarBinding}: these
7609
7726
  * bind only while the filter is evaluated on the READ side — the
7610
7727
  * `definitionsForDocument` derivation and the Studio start control).
7611
- * `startInstance` never evaluates the filter. BROWSE-TIME-PURE: `$fields` is
7612
- * deliberately absent a `$fields` read is deploy-rejected with a pointer
7613
- * to start GROQ requirements.
7614
- * Bound in one place: `startContextParams` in the applicability evaluator.
7728
+ * `startInstance` never evaluates the filter. BROWSE-TIME-PURE: `$fields` and
7729
+ * every caller-bound var (`$actor` / `$assigned` / `$can` / `$attributes` /
7730
+ * `$params`) are deliberately absent — a read is deploy-rejected (`$fields`
7731
+ * with a pointer to start GROQ requirements; caller vars as silent
7732
+ * never-match). Bound in one place: `startContextParams` in the applicability
7733
+ * evaluator.
7615
7734
  */
7616
7735
  export declare const START_FILTER_VARS: readonly {
7617
7736
  name: string;
@@ -7636,6 +7755,19 @@ export declare const START_REQUIREMENT_VARS: readonly {
7636
7755
  description: string;
7637
7756
  }[];
7638
7757
 
7758
+ /**
7759
+ * How standalone runs of this workflow begin. `filter` is a READ-SIDE
7760
+ * visibility predicate — "should a start surface offer this workflow for
7761
+ * this document?" — evaluated by `definitionsForDocument`/applicability in
7762
+ * the browse-time-pure start-filter context (`$tag`/`$definition`/`$now`
7763
+ * bound; `$fields` cannot exist before inputs do, so a `$fields` read here
7764
+ * is deploy-rejected). It is NOT a `startInstance` gate; the verb never
7765
+ * reads it. `requirements` are named readiness checks evaluated in author
7766
+ * order in the start-time context (GROQ nodes add `$fields`; `singleSubject`
7767
+ * is the one-in-flight-run-per-subject rule) — every node must pass before
7768
+ * `startInstance` commits. Both are advisory like every engine-side check;
7769
+ * the Content Lake remains the only enforcement point.
7770
+ */
7639
7771
  export declare type StartBlock = StartFields & {
7640
7772
  kind: StartKind;
7641
7773
  };
@@ -7697,9 +7829,6 @@ export declare interface StartEvaluation {
7697
7829
  invalidInitialFields: InitialFieldIssue[];
7698
7830
  }
7699
7831
 
7700
- /** Type-mirror of {@link startFields}: how standalone runs of this workflow
7701
- * begin. Stored requires `kind` (desugar fills the `'interactive'` default);
7702
- * authoring may omit it — so each variant declares it. */
7703
7832
  declare type StartFields = {
7704
7833
  filter?: string | undefined;
7705
7834
  requirements?: StartRequirement[] | undefined;
@@ -7865,16 +7994,12 @@ export declare class StartNotSettledError extends WorkflowError<"start-not-settl
7865
7994
  });
7866
7995
  }
7867
7996
 
7868
- /**
7869
- * Why a definition can't be started standalone, or `undefined` when it can.
7870
- * Advisory — the engine itself does not refuse ({@link isStartableDefinition})
7871
- * — but a start surface has no way to supply the parent context a spawn-only
7872
- * child expects, so it fails fast with this message instead.
7873
- */
7997
+ /** Advisory only, per {@link isStartableDefinition} — a start surface has no parent context to give a spawn-only child, so it rejects fast with this message instead. */
7874
7998
  export declare function startRefusal(definition: {
7875
7999
  lifecycle?: WorkflowLifecycle | undefined;
7876
8000
  }): string | undefined;
7877
8001
 
8002
+ /** Every named readiness requirement accepted by workflow `start.requirements`. */
7878
8003
  export declare type StartRequirement =
7879
8004
  | GroqRequirement
7880
8005
  | SingleSubjectRequirement;
@@ -7926,15 +8051,6 @@ export declare interface StartSliceRow {
7926
8051
  completedAt: string | null;
7927
8052
  }
7928
8053
 
7929
- /**
7930
- * Declared editability of a field — the generic edit seam's gate. Default
7931
- * (absent) is NOT editable: a field is op-only engine working memory unless the
7932
- * modeler opens it. The stored form is `true` (editable by anyone within the
7933
- * field's scope window) or an EDIT CONDITION — rendered-scope GROQ (`$actor`,
7934
- * `$can`, `$fields`, `$assigned`), checked like an action filter to decide
7935
- * who-may-edit. ADVISORY like every engine gate — it disables the inline field
7936
- * and explains; a {@link Guard} declares the intended write-lock.
7937
- */
7938
8054
  declare const StoredEditableSchema: v.UnionSchema<
7939
8055
  [
7940
8056
  v.LiteralSchema<true, undefined>,
@@ -7982,6 +8098,28 @@ declare const StoredFieldOpSchema: v.VariantSchema<
7982
8098
  },
7983
8099
  undefined
7984
8100
  >,
8101
+ v.StrictObjectSchema<
8102
+ {
8103
+ readonly type: v.LiteralSchema<"field.setIfMissing", undefined>;
8104
+ readonly target: v.StrictObjectSchema<
8105
+ {
8106
+ readonly scope: v.PicklistSchema<
8107
+ readonly ["workflow", "stage", "activity"],
8108
+ string
8109
+ >;
8110
+ readonly field: v.SchemaWithPipe<
8111
+ readonly [
8112
+ v.StringSchema<undefined>,
8113
+ v.MinLengthAction<string, 1, "must be a non-empty string">,
8114
+ ]
8115
+ >;
8116
+ },
8117
+ undefined
8118
+ >;
8119
+ readonly value: v.GenericSchema<ValueExprInternal>;
8120
+ },
8121
+ undefined
8122
+ >,
7985
8123
  v.StrictObjectSchema<
7986
8124
  {
7987
8125
  readonly type: v.LiteralSchema<"field.unset", undefined>;
@@ -8025,6 +8163,56 @@ declare const StoredFieldOpSchema: v.VariantSchema<
8025
8163
  },
8026
8164
  undefined
8027
8165
  >,
8166
+ v.StrictObjectSchema<
8167
+ {
8168
+ readonly type: v.LiteralSchema<"field.inc", undefined>;
8169
+ readonly target: v.StrictObjectSchema<
8170
+ {
8171
+ readonly scope: v.PicklistSchema<
8172
+ readonly ["workflow", "stage", "activity"],
8173
+ string
8174
+ >;
8175
+ readonly field: v.SchemaWithPipe<
8176
+ readonly [
8177
+ v.StringSchema<undefined>,
8178
+ v.MinLengthAction<string, 1, "must be a non-empty string">,
8179
+ ]
8180
+ >;
8181
+ },
8182
+ undefined
8183
+ >;
8184
+ readonly value: v.OptionalSchema<
8185
+ v.GenericSchema<ValueExprInternal>,
8186
+ undefined
8187
+ >;
8188
+ },
8189
+ undefined
8190
+ >,
8191
+ v.StrictObjectSchema<
8192
+ {
8193
+ readonly type: v.LiteralSchema<"field.dec", undefined>;
8194
+ readonly target: v.StrictObjectSchema<
8195
+ {
8196
+ readonly scope: v.PicklistSchema<
8197
+ readonly ["workflow", "stage", "activity"],
8198
+ string
8199
+ >;
8200
+ readonly field: v.SchemaWithPipe<
8201
+ readonly [
8202
+ v.StringSchema<undefined>,
8203
+ v.MinLengthAction<string, 1, "must be a non-empty string">,
8204
+ ]
8205
+ >;
8206
+ },
8207
+ undefined
8208
+ >;
8209
+ readonly value: v.OptionalSchema<
8210
+ v.GenericSchema<ValueExprInternal>,
8211
+ undefined
8212
+ >;
8213
+ },
8214
+ undefined
8215
+ >,
8028
8216
  v.StrictObjectSchema<
8029
8217
  {
8030
8218
  readonly type: v.LiteralSchema<"field.updateWhere", undefined>;
@@ -8084,6 +8272,7 @@ declare const StoredFieldOpSchema: v.VariantSchema<
8084
8272
  undefined
8085
8273
  >;
8086
8274
 
8275
+ /** A field reference with `scope` already resolved — the form every op target carries. */
8087
8276
  export declare type StoredFieldRef = v.InferOutput<typeof StoredFieldRefSchema>;
8088
8277
 
8089
8278
  declare const StoredFieldRefSchema: v.StrictObjectSchema<
@@ -8168,6 +8357,28 @@ declare const StoredOpSchema: v.VariantSchema<
8168
8357
  },
8169
8358
  undefined
8170
8359
  >,
8360
+ v.StrictObjectSchema<
8361
+ {
8362
+ readonly type: v.LiteralSchema<"field.setIfMissing", undefined>;
8363
+ readonly target: v.StrictObjectSchema<
8364
+ {
8365
+ readonly scope: v.PicklistSchema<
8366
+ readonly ["workflow", "stage", "activity"],
8367
+ string
8368
+ >;
8369
+ readonly field: v.SchemaWithPipe<
8370
+ readonly [
8371
+ v.StringSchema<undefined>,
8372
+ v.MinLengthAction<string, 1, "must be a non-empty string">,
8373
+ ]
8374
+ >;
8375
+ },
8376
+ undefined
8377
+ >;
8378
+ readonly value: v.GenericSchema<ValueExprInternal>;
8379
+ },
8380
+ undefined
8381
+ >,
8171
8382
  v.StrictObjectSchema<
8172
8383
  {
8173
8384
  readonly type: v.LiteralSchema<"field.unset", undefined>;
@@ -8211,6 +8422,56 @@ declare const StoredOpSchema: v.VariantSchema<
8211
8422
  },
8212
8423
  undefined
8213
8424
  >,
8425
+ v.StrictObjectSchema<
8426
+ {
8427
+ readonly type: v.LiteralSchema<"field.inc", undefined>;
8428
+ readonly target: v.StrictObjectSchema<
8429
+ {
8430
+ readonly scope: v.PicklistSchema<
8431
+ readonly ["workflow", "stage", "activity"],
8432
+ string
8433
+ >;
8434
+ readonly field: v.SchemaWithPipe<
8435
+ readonly [
8436
+ v.StringSchema<undefined>,
8437
+ v.MinLengthAction<string, 1, "must be a non-empty string">,
8438
+ ]
8439
+ >;
8440
+ },
8441
+ undefined
8442
+ >;
8443
+ readonly value: v.OptionalSchema<
8444
+ v.GenericSchema<ValueExprInternal>,
8445
+ undefined
8446
+ >;
8447
+ },
8448
+ undefined
8449
+ >,
8450
+ v.StrictObjectSchema<
8451
+ {
8452
+ readonly type: v.LiteralSchema<"field.dec", undefined>;
8453
+ readonly target: v.StrictObjectSchema<
8454
+ {
8455
+ readonly scope: v.PicklistSchema<
8456
+ readonly ["workflow", "stage", "activity"],
8457
+ string
8458
+ >;
8459
+ readonly field: v.SchemaWithPipe<
8460
+ readonly [
8461
+ v.StringSchema<undefined>,
8462
+ v.MinLengthAction<string, 1, "must be a non-empty string">,
8463
+ ]
8464
+ >;
8465
+ },
8466
+ undefined
8467
+ >;
8468
+ readonly value: v.OptionalSchema<
8469
+ v.GenericSchema<ValueExprInternal>,
8470
+ undefined
8471
+ >;
8472
+ },
8473
+ undefined
8474
+ >,
8214
8475
  v.StrictObjectSchema<
8215
8476
  {
8216
8477
  readonly type: v.LiteralSchema<"field.updateWhere", undefined>;
@@ -8297,6 +8558,12 @@ export declare function stripSystemFields(
8297
8558
  * its activity looking merely "active", so it wins over the activity- and
8298
8559
  * transition-level symptoms it produces. Note an active activity awaiting a human
8299
8560
  * action is NOT here — that's the healthy {@link Diagnosis} `waiting` state.
8561
+ *
8562
+ * `transition-unevaluable` is the recoverable arm: every activity resolved,
8563
+ * but an exit transition's `when` came back GROQ `null` (a referenced operand
8564
+ * is missing or unreadable), so selection halts and the cascade re-fires once
8565
+ * the operand resolves — where `no-transition-fires` means every `when` is a
8566
+ * definite `false`. It carries the undecidable transitions.
8300
8567
  */
8301
8568
  export declare type StuckCause =
8302
8569
  | {
@@ -8314,13 +8581,6 @@ export declare type StuckCause =
8314
8581
  | {
8315
8582
  kind: "no-transition-fires";
8316
8583
  }
8317
- /**
8318
- * Every activity resolved, but an exit transition's `when` is *unevaluable*
8319
- * (GROQ `null` — a referenced operand is missing/unreadable), so selection
8320
- * halts. Unlike {@link StuckCause} `no-transition-fires` this is recoverable:
8321
- * the cascade re-fires once the operand resolves (e.g. the subject is
8322
- * published or the field is filled). Carries the undecidable transitions.
8323
- */
8324
8584
  | {
8325
8585
  kind: "transition-unevaluable";
8326
8586
  transitions: string[];
@@ -8350,14 +8610,9 @@ export declare interface SubjectPermissionDenial {
8350
8610
  permission: DocumentValuePermission;
8351
8611
  }
8352
8612
 
8353
- /** One foreign resource's forecast inputs: the actor's grants there, and the
8354
- * actor's principal id in THAT resource's own identity namespace. */
8355
8613
  declare interface SubjectResourceAccess {
8356
8614
  grants: Grant[];
8357
- /** What that resource's lake `identity()` returns for the acting token
8358
- * resolved through the resource's own routed client, so a dataset
8359
- * resource contributes the actor's per-project user id and an org-level
8360
- * resource the account-global id. */
8615
+ /** The actor's principal id in this resource's own namespace: per-project user id for a dataset resource, account-global id for an org-level one. */
8361
8616
  actorId: string;
8362
8617
  }
8363
8618
 
@@ -8464,18 +8719,23 @@ export declare interface SubworkflowEntry {
8464
8719
  };
8465
8720
  }
8466
8721
 
8722
+ /**
8723
+ * Fan-out declared as an action's `spawn`, read back as `$subworkflows`.
8724
+ * `forEach` is GROQ producing one row per subworkflow (bound as `$row`); each
8725
+ * row needs an identity the engine can adopt on re-entry (`_key` ?? `_id` ??
8726
+ * GDR `id`, or the value itself for a scalar row) or the spawn fails.
8727
+ * `definition` resolves by stable `name`, ordered `version desc` unless
8728
+ * pinned. `with` seeds each child's initial fields; `context` delivers extra
8729
+ * parent-scope values into the child's `$context`. `onExit` governs only
8730
+ * still-live children when the cohort's scope stops applying: `'detach'`
8731
+ * (default) lets them run to completion, `'abort'` kills them recursively —
8732
+ * always an authored choice, never automatic. Whether the PARENT may move at
8733
+ * all is a separate gate over `$subworkflows`.
8734
+ */
8467
8735
  export declare type Subworkflows = v.InferOutput<typeof SubworkflowsSchema>;
8468
8736
 
8469
8737
  declare const SubworkflowsSchema: v.StrictObjectSchema<
8470
8738
  {
8471
- /**
8472
- * GROQ producing one row per subworkflow; each row binds as `$row`. Every
8473
- * row must carry an identity the engine can adopt against on re-entry:
8474
- * `_key` ?? `_id` ?? GDR `id` for object rows (a GDR value — `{id, type}`
8475
- * with a GDR-URI `id`, the rows a `doc.refs` field stores — keys on its
8476
- * `id`; mint a `_key` in the projection for synthetic rows), the value
8477
- * itself for scalar rows. A row without an identity fails the spawn.
8478
- */
8479
8739
  readonly forEach: v.SchemaWithPipe<
8480
8740
  readonly [
8481
8741
  v.StringSchema<undefined>,
@@ -8509,7 +8769,6 @@ declare const SubworkflowsSchema: v.StrictObjectSchema<
8509
8769
  },
8510
8770
  undefined
8511
8771
  >;
8512
- /** Initial fields for each subworkflow — entry name → GROQ over `$row` + the parent scope. */
8513
8772
  readonly with: v.OptionalSchema<
8514
8773
  v.RecordSchema<
8515
8774
  v.SchemaWithPipe<
@@ -8528,11 +8787,6 @@ declare const SubworkflowsSchema: v.StrictObjectSchema<
8528
8787
  >,
8529
8788
  undefined
8530
8789
  >;
8531
- /**
8532
- * Extra values evaluated in the parent's rendered scope at spawn time and
8533
- * delivered into each subworkflow's `$context` bag — the parent→child
8534
- * handoff.
8535
- */
8536
8790
  readonly context: v.OptionalSchema<
8537
8791
  v.RecordSchema<
8538
8792
  v.SchemaWithPipe<
@@ -8551,16 +8805,6 @@ declare const SubworkflowsSchema: v.StrictObjectSchema<
8551
8805
  >,
8552
8806
  undefined
8553
8807
  >;
8554
- /**
8555
- * What happens to still-live children when their cohort's scope stops
8556
- * applying — the spawning stage exits, or a re-fire's `forEach` no longer
8557
- * discovers their row. `'detach'` (the default) lets them run to
8558
- * completion outside the gate; `'abort'` kills them (recursively). The
8559
- * engine never destroys in-flight work implicitly — `'abort'` is always
8560
- * an authored choice. Note this governs only the CHILDREN's fate; whether
8561
- * the parent may move at all is what gates (conditions over
8562
- * `$subworkflows`) decide.
8563
- */
8564
8808
  readonly onExit: v.OptionalSchema<
8565
8809
  v.PicklistSchema<readonly ["detach", "abort"], string>,
8566
8810
  undefined
@@ -8590,6 +8834,10 @@ export declare interface SuggestedRemediation {
8590
8834
  * recovered entries is the next `drainEffects` call's job. To kill a stuck
8591
8835
  * entry WITHOUT redispatching, report it via
8592
8836
  * `completeEffect({status: 'failed'})` instead.
8837
+ *
8838
+ * A standalone export, NOT an `Engine` verb: like the guard-lifecycle
8839
+ * helpers, this is housekeeping for admin/ops tooling, not part of the
8840
+ * editor/runtime verb surface — a drain already self-recovers via takeover.
8593
8841
  */
8594
8842
  export declare function sweepStaleClaims(args: {
8595
8843
  client: WorkflowClient;
@@ -8610,12 +8858,7 @@ export declare interface SweepStaleClaimsResult {
8610
8858
  /** Lake `identity()` sentinel for system-initiated actions. */
8611
8859
  export declare const SYSTEM_IDENTITY = "<system>";
8612
8860
 
8613
- /**
8614
- * The engine's read-partition invariant as a GROQ predicate: a document is
8615
- * visible when its `tag` equals the caller's `$tag` param. The single
8616
- * definition of "tag-scoped" shared by the engine's internal lookups, the
8617
- * `workflow.query` guard, and the CLI/MCP read helpers.
8618
- */
8861
+ /** Single source of the tag-scope GROQ predicate; the engine's lookups, `workflow.query`, and CLI/MCP reads all call this instead of hand-rolling the filter. */
8619
8862
  export declare function tagScopeFilter(): string;
8620
8863
 
8621
8864
  /**
@@ -8629,22 +8872,6 @@ declare type Telemetered<T> = T & {
8629
8872
  telemetry?: WorkflowTelemetryLogger;
8630
8873
  };
8631
8874
 
8632
- /**
8633
- * The standard Sanity-intake recipe every workflow app shell shares —
8634
- * consent from `GET /intake/telemetry-status`, transport via
8635
- * `POST /intake/batch` `{projectId, batch}`, and the request tags that
8636
- * keep shell telemetry traffic identifiable in request logs. The shells
8637
- * (App SDK provider, MCP server, CLI) each own their store and
8638
- * environment gates; this module is the one home for the recipe those
8639
- * stores run on, so a change to an endpoint, body shape, or tag lands
8640
- * everywhere at once.
8641
- *
8642
- * Like the event vocabulary (`engine.telemetry.ts`), this module keeps
8643
- * the engine free of a runtime `@sanity/telemetry` dependency: the
8644
- * result is a structural mirror of that package's batched-store options,
8645
- * so a shell passes it straight to `createBatchedStore`. Drift against
8646
- * the real package is pinned by a type-level test (dev dependency).
8647
- */
8648
8875
  /** Mirror of `@sanity/telemetry`'s `ConsentStatus`. */
8649
8876
  export declare type TelemetryConsentStatus =
8650
8877
  | "undetermined"
@@ -8679,6 +8906,14 @@ export declare interface TelemetryIntakeClient {
8679
8906
  }) => Promise<T>;
8680
8907
  }
8681
8908
 
8909
+ /**
8910
+ * The statuses an activity can be resolved INTO — what `status.set` accepts.
8911
+ * A health axis, not a decision axis: a routine decision (decline, send back,
8912
+ * hold) resolves `done` and routes via a field write; `failed` means the work
8913
+ * genuinely could not complete. Only `done`/`skipped` satisfy
8914
+ * `$allActivitiesDone` — a `failed` activity blocks it permanently, surfacing
8915
+ * via `$anyActivityFailed`.
8916
+ */
8682
8917
  declare const TERMINAL_ACTIVITY_STATUSES: readonly [
8683
8918
  "done",
8684
8919
  "skipped",
@@ -8692,8 +8927,8 @@ export declare type TerminalActivityStatus =
8692
8927
  export declare type TerminalState = "aborted" | "completed" | "in-flight";
8693
8928
 
8694
8929
  /**
8695
- * Classify an instance by its terminal stamps. The ONE home for the
8696
- * precedence rule: aborted instances carry `completedAt` too (stamped at the
8930
+ * Classify an instance by its terminal stamps. The single definition of the
8931
+ * precedence rule: aborted instances have `completedAt` too (stamped at the
8697
8932
  * abort, so in-flight queries treat both terminals uniformly), so `abortedAt`
8698
8933
  * must be checked first — `'completed'` means completed *without* an abort.
8699
8934
  */
@@ -8709,15 +8944,8 @@ export declare function terminalState(
8709
8944
  */
8710
8945
  export declare function toBareId(id: string): string;
8711
8946
 
8712
- /**
8713
- * `todoList` ad-hoc, status-tracked work items. Sugar over `array of object
8714
- * { label, status, assignee?, dueDate? }`; a plain checklist is this used with
8715
- * `{label, status}` only (open ↔ done). Never a stored kind.
8716
- *
8717
- * The `dueDate` column is a `date` NAMED `dueDate`, not the {@link
8718
- * FieldValueMap.dueDate} kind — that kind reserves one deadline slot per level,
8719
- * and a repeating row has nothing to reserve.
8720
- */
8947
+ /** Ad-hoc, status-tracked work items: sugar over `array of object {label, status, assignee?, dueDate?}`; a plain checklist is that with `{label, status}` alone.
8948
+ * Its `dueDate` is a `date` column named `dueDate`, not the elevated `dueDate` kind, which reserves one deadline slot per level. Never a stored kind. */
8721
8949
  declare type TodoListField = FieldBase<AuthoringEditable, GroupMembership> & {
8722
8950
  type: "todoList";
8723
8951
  };
@@ -8739,6 +8967,16 @@ export declare interface TodoListItem {
8739
8967
  dueDate?: string | null;
8740
8968
  }
8741
8969
 
8970
+ /**
8971
+ * A pure edge — `{name, when, to}` plus presentation, no ops or effects
8972
+ * (structure never does; only actions do). Every transition is evaluated on
8973
+ * every commit and cascade; the first truthy `when` in declaration order
8974
+ * fires. No action coupling: a routing difference is written into fields by
8975
+ * an action and read by the trigger — arrival work is a `when: 'true'`
8976
+ * action in the destination stage, and exit work is an action in the source
8977
+ * stage whose `when` repeats this transition's condition (the hop rule
8978
+ * guarantees it commits before the move).
8979
+ */
8742
8980
  export declare type Transition = TransitionFields & {
8743
8981
  when: string;
8744
8982
  };
@@ -8819,6 +9057,9 @@ export declare function unsatisfiedTransitionSummaries(
8819
9057
  summary: string;
8820
9058
  }[];
8821
9059
 
9060
+ /** Flat key → active-value record bound as advisory `$attributes` when present. */
9061
+ export declare type UserAttributes = Record<string, unknown>;
9062
+
8822
9063
  /** The identity provider under whichever spelling the answering endpoint used
8823
9064
  * — the ONE place that disagreement is resolved. */
8824
9065
  export declare function userLoginProvider(
@@ -8859,6 +9100,12 @@ declare interface ValidationIssue {
8859
9100
  message: string;
8860
9101
  }
8861
9102
 
9103
+ /**
9104
+ * An op's write payload, resolved to concrete JSON when the op applies. Each
9105
+ * context-bound arm has a rendered `$`-twin in conditions (`actor` ↔
9106
+ * `$actor`, `now` ↔ `$now`, `self` ↔ `$self`), so learning one side teaches
9107
+ * the other. Distinct from {@link FieldSource}, a field's seed recipe.
9108
+ */
8862
9109
  export declare type ValueExpr = ValueExprInternal;
8863
9110
 
8864
9111
  declare type ValueExprInternal =
@@ -8959,110 +9206,80 @@ export { WhatIfOutcome };
8959
9206
 
8960
9207
  export { withAssignment };
8961
9208
 
8962
- /**
8963
- * The workflow verbs, bound as one object — write path, admin
8964
- * overrides, pure reads, and permission helpers. The module doc above
8965
- * describes the model.
8966
- */
8967
9209
  export declare const workflow: {
8968
9210
  /**
8969
- * Deploy a set of workflow definitions as one call. Definitions are
8970
- * immutable and content-addressed: the author writes no version, and each
8971
- * deploy compares a definition's content fingerprint to the latest version
8972
- * already deployed under its name. Identical content is a no-op
8973
- * (`unchanged`); any change mints the next version (`created`) deploy
8974
- * never patches a deployed version, so a definition can't change out from
8975
- * under the instances pinned to it. `startInstance` picks the highest
8976
- * version by default. The engine figures out the dependency order itself
8977
- * (children before parents that spawn them via `action.spawn.definition`)
8978
- * and reports a per-definition outcome (`created` / `unchanged`).
8979
- *
8980
- * Refs may point inside the batch OR at already-deployed definitions
8981
- * in the lake — both are valid. A ref pointing at neither errors with
8982
- * a clear message naming the missing target.
8983
- *
8984
- * Cycles in the dependency graph error before any write happens.
8985
- *
8986
- * Input is authored content or a fetched definition document — the document
8987
- * envelope (`_*` system fields, `tag`, `version`, `contentHash`) is stripped
8988
- * at the boundary, never fingerprinted, so a fetched document redeploys as
8989
- * `unchanged`. Any other unknown key fails loud.
9211
+ * Deploy a set of definitions as one call. Definitions are immutable and
9212
+ * content-addressed: the author writes no version, identical content no-ops
9213
+ * (`unchanged`), and any change mints the next version (`created`) — deploy
9214
+ * never patches a deployed version out from under the instances pinned to it.
9215
+ * The engine orders the batch itself (children before the parents that spawn
9216
+ * them). Refs may point inside the batch or at already-deployed definitions;
9217
+ * a ref resolving to neither, or a cycle, errors before any write. Input is
9218
+ * authored content or a fetched definition document the document envelope
9219
+ * (`_*` system fields, `tag`, `version`, `contentHash`) is stripped at the
9220
+ * boundary and never fingerprinted, so a fetched document redeploys as
9221
+ * `unchanged`; any other unknown key fails loud.
8990
9222
  */
8991
9223
  deployDefinitions: <T extends WorkflowDefinitionInput<T>>(
8992
9224
  rawArgs: Telemetered<DeployDefinitionsArgs<T> & EngineScopeArgs>,
8993
9225
  ) => Promise<DeployDefinitionsResult>;
8994
9226
  /**
8995
- * Remove a deployed workflow definition (all versions, or one via
8996
- * `version`). Refuses while non-terminal instances exist unless
8997
- * `cascade` aborts them first — instances are never deleted, only
8998
- * aborted in place; see {@link deleteDefinitionInternal} for the
8999
- * full contract (spawn-referrer check, guard-doc housekeeping).
9227
+ * Remove a deployed definition (all versions, or one via `version`). Refuses
9228
+ * while non-terminal instances exist unless `cascade` aborts them first —
9229
+ * instances are never deleted, only aborted in place; see
9230
+ * {@link deleteDefinitionInternal} for the full contract (spawn-referrer
9231
+ * check, guard-doc housekeeping).
9000
9232
  */
9001
9233
  deleteDefinition: (
9002
9234
  rawArgs: Clocked<Telemetered<DeleteDefinitionArgs & EngineScopeArgs>>,
9003
9235
  ) => Promise<DeleteDefinitionResult>;
9004
9236
  /**
9005
- * Spawn a new workflow instance from a deployed definition.
9006
- *
9007
- * The gates run before anything is written, in order: supplied rows must be
9008
- * structurally consumable, required inputs must be present
9009
- * ({@link RequiredFieldNotProvidedError}), then every declared start
9010
- * requirement is evaluated in author order. All unmet `groq` and
9011
- * `singleSubject` nodes are reported by one {@link StartNotAllowedError}
9012
- * (there is no override argpre-flight with `evaluateStart`).
9013
- * Per-value SHAPE validation fires during field resolution, after the
9014
- * verdict but still before any write. It does NOT evaluate `start.filter`:
9015
- * that is a read-side visibility rule (see `definitionsForDocument`).
9016
- *
9017
- * Pins the snapshot at start-time, seeds the `context` bag, and enters
9018
- * the initial stage — fields resolve and every in-scope activity is
9019
- * born active. Then cascades until stable, so the initial stage's
9020
- * `when: 'true'` triggers have fired by the time this returns.
9237
+ * Spawn a new instance from a deployed definition: pins the snapshot, seeds
9238
+ * the `context` bag, enters the initial stage with every in-scope activity
9239
+ * born active, then cascades until stable. The gates run before anything is
9240
+ * written — supplied rows must be structurally consumable, required inputs
9241
+ * must be present, then every declared start requirement is evaluated in
9242
+ * author order and all unmet nodes are reported by one
9243
+ * {@link StartNotAllowedError} (no override arg; pre-flight with
9244
+ * `evaluateStart`). `start.filter` is NOT evaluated herethat is a
9245
+ * read-side visibility rule, see `definitionsForDocument`.
9021
9246
  *
9022
9247
  * Start is three commits — create, prime, first cascade — and a supplied
9023
- * `instanceId` is its idempotency key across them. When that id already
9024
- * exists under this tag for the same start, the call RESUMES: input gates
9025
- * and field resolution are skipped (those values were pinned at create)
9026
- * and the outstanding commits run — the retry path for a start that
9027
- * failed after its create landed (see `isUnprimed`). Reusing an id for a
9028
- * DIFFERENT start (definition or explicit version mismatch) or for an
9029
- * unfinished start that was aborted (a discarded start) — throws
9030
- * {@link ContractViolationError}. The mid-sequence failures are typed and
9031
- * carry the retry id: a prime failure after the create committed throws
9032
- * `StartNotPrimedError` (failed but resumable), and a cascade failure
9033
- * after a successful prime throws `StartNotSettledError` — the run exists
9034
- * by then and must not be reported as a failed start. `changed` is `true`
9035
- * on a fresh start and rev-derived on a resume; `cascaded` reports how far
9036
- * the instance auto-advanced.
9248
+ * `instanceId` is the idempotency key across them: reusing it for the SAME
9249
+ * start RESUMES (input gates and field resolution are skipped, those values
9250
+ * were pinned at create), while reusing it for a DIFFERENT start, or for an
9251
+ * unfinished start that was aborted, throws
9252
+ * {@link ContractViolationError}. `changed` is `true` on a fresh start and
9253
+ * rev-derived on a resume; `cascaded` reports how far the instance
9254
+ * auto-advanced.
9037
9255
  */
9038
9256
  startInstance: (
9039
9257
  rawArgs: Clocked<Telemetered<StartInstanceArgs & EngineScopeArgs>>,
9040
9258
  ) => Promise<OperationResult>;
9041
9259
  /**
9042
- * Fire an action against an active activity. Cascades and propagates to
9043
- * ancestors after the action commits. A cascade-fired (`when`) action is
9044
- * rejected the cascade is its only firing path.
9045
- *
9046
- * This is the universal "something happened" call. Editors fire it.
9047
- * Runtimes fire it in response to webhooks, effect completions, and
9048
- * timer firings. External signals never bypass this.
9260
+ * Fire an action against an active activity, then cascade and propagate to
9261
+ * ancestors once it commits. The universal "something happened" call —
9262
+ * editors fire it, and runtimes fire it in response to webhooks, effect
9263
+ * completions, and timer firings; external signals never bypass it. A
9264
+ * cascade-fired (`when`) action is rejected: the cascade is its only firing
9265
+ * path.
9049
9266
  */
9050
9267
  fireAction: (
9051
9268
  rawArgs: Clocked<Telemetered<FireActionArgs & EngineScopeArgs>>,
9052
9269
  ) => Promise<OperationResult>;
9053
9270
  /**
9054
9271
  * Edit a declared-editable field directly — reassign, reschedule,
9055
- * claim-by-hand, append to a running log — through the generic edit seam,
9272
+ * claim-by-hand, append to a running log — through the generic edit seam
9056
9273
  * instead of a bespoke action per field. Soft-gates on the field's declared
9057
9274
  * editability (the same projection a UI renders), applies the edit as a
9058
- * `field.*` op (so provenance + history are stamped by the op path),
9275
+ * `field.*` op so provenance and history are stamped by the op path,
9059
9276
  * refreshes the stage's guards, then cascades — an edit to a value a
9060
9277
  * transition reads can and should move the instance. Advisory like every
9061
9278
  * engine gate.
9062
9279
  *
9063
9280
  * Each call is a discrete COMMIT (a history entry, a guard refresh, a
9064
9281
  * cascade, an `ifRevisionId` write), not a draft patch — so an inline-field
9065
- * UI must bind it to a deliberate boundary (blur / Enter / Save / debounce),
9282
+ * UI must bind it to a deliberate boundary (blur, Enter, Save, debounce),
9066
9283
  * never an `onChange` per keystroke.
9067
9284
  */
9068
9285
  editField: (
@@ -9070,94 +9287,87 @@ export declare const workflow: {
9070
9287
  ) => Promise<OperationResult>;
9071
9288
  /**
9072
9289
  * Report a queued effect's outcome. Drains it from `pendingEffects` and
9073
- * appends an `effectHistory` entry whose `outputs` (when supplied on a
9074
- * successful run) are what downstream effect bindings and conditions
9075
- * read as `$effects['<name>'].<output>` the start-only `context` bag
9076
- * is never touched. Any `ops` the handler returned (`field.*`) are
9077
- * validated and applied to the instance in the same commit, through the
9078
- * same op applier an action's field ops use. Cascades after. A completion
9079
- * that applies always changes state (the effect drains + history is
9080
- * appended), so `changed` is `true` — a bad `effectKey`/status throws
9081
- * instead, and a keyed retry of an already-applied completion replays as
9082
- * `changed: false`.
9290
+ * appends an `effectHistory` entry whose `outputs` are what downstream
9291
+ * bindings and conditions read as `$effects['<name>'].<output>` the
9292
+ * start-only `context` bag is never touched. Any `ops` the handler returned
9293
+ * (`field.*`) are validated and applied in the same commit, through the op
9294
+ * applier an action's field ops use. Cascades after. A completion that
9295
+ * applies always changes state, so `changed` is `true`; a bad
9296
+ * `effectKey`/status throws instead, and a keyed retry of an
9297
+ * already-applied completion replays as `changed: false`.
9083
9298
  *
9084
9299
  * Completion is first-writer-wins — see {@link CompleteEffectArgs}. A
9085
- * completer reporting over a retrying transport (webhook redelivery,
9086
- * queue, cron) should pass `idempotencyKey`.
9300
+ * completer reporting over a retrying transport (webhook redelivery, queue,
9301
+ * cron) should pass `idempotencyKey`.
9087
9302
  */
9088
9303
  completeEffect: (
9089
9304
  rawArgs: Clocked<Telemetered<CompleteEffectArgs & EngineScopeArgs>>,
9090
9305
  ) => Promise<OperationResult>;
9091
9306
  /**
9092
- * Commit mid-dispatch field state from a running effect handler — the
9093
- * engine verb behind `ctx.commitOps`. Gates on the dispatch's exact claim
9094
- * (token match + unexpired lease; a stale report throws
9095
- * `StaleEffectClaimError` and writes nothing), validates and applies the
9096
- * `field.*` ops through the shared op applier, records history and the
9097
- * mandatory idempotency key, renews the claim's lease in the same
9098
- * compare-and-swap commit, refreshes the stage's guards, then cascades —
9099
- * a report that satisfies a transition moves the instance, by design.
9307
+ * Commit mid-dispatch field state from a running effect handler — the engine
9308
+ * verb behind `ctx.commitOps`. Gates on the dispatch's exact claim (token
9309
+ * match plus unexpired lease; a stale report throws `StaleEffectClaimError`
9310
+ * and writes nothing), validates and applies the `field.*` ops through the
9311
+ * shared op applier, records history and the mandatory idempotency key,
9312
+ * renews the claim's lease in the same compare-and-swap commit, refreshes
9313
+ * the stage's guards, then cascades — a report that satisfies a transition
9314
+ * moves the instance, by design.
9100
9315
  *
9101
- * Completion (`completeEffect`) remains the authoritative final result
9102
- * and stays claim-blind; this verb only protects the mid-dispatch write
9103
- * channel from superseded handlers.
9316
+ * `completeEffect` remains the authoritative final result and stays
9317
+ * claim-blind; this verb only protects the mid-dispatch write channel from
9318
+ * superseded handlers.
9104
9319
  */
9105
9320
  commitEffectOps: (
9106
9321
  rawArgs: Clocked<Telemetered<CommitEffectOpsArgs & EngineScopeArgs>>,
9107
9322
  ) => Promise<OperationResult>;
9108
9323
  /**
9109
9324
  * Run the cascade until stable — triggered actions fire, transitions move.
9110
- *
9111
- * Used by the runtime after any event that might affect the workflow
9112
- * but isn't itself an action fire: a subject doc was patched, a sibling
9113
- * workflow completed, the clock crossed a deadline a `when` reads, etc.
9114
- * The runtime doesn't need to know what changed — it just nudges
9115
- * affected instances and the engine re-evaluates. `changed` reports
9116
- * whether the nudge wrote anything: a fired transition, but also a
9117
- * hop that fired triggered actions without unlocking a transition yet —
9118
- * so it's derived from the instance's `_rev`, not from `cascaded` alone.
9325
+ * For a runtime reacting to any event that might affect the workflow but
9326
+ * isn't itself an action fire: a subject doc was patched, a sibling workflow
9327
+ * completed, the clock crossed a deadline a `when` reads. The caller doesn't
9328
+ * need to know what changed it nudges the affected instance and the engine
9329
+ * re-evaluates. `changed` reports whether the nudge wrote anything, derived
9330
+ * from the instance's `_rev` rather than `cascaded` alone, since a hop can
9331
+ * fire triggered actions without unlocking a transition.
9119
9332
  */
9120
9333
  tick: (
9121
9334
  rawArgs: Clocked<Telemetered<OperationArgs & EngineScopeArgs>>,
9122
9335
  ) => Promise<OperationResult>;
9123
9336
  /**
9124
- * Admin override — force the instance into `targetStage` regardless
9125
- * of filters or declared transitions. ACL gating should be enforced
9126
- * upstream; this verb performs the mechanical move. `changed: false`
9127
- * means the move was a no-op (already at the target / terminal).
9337
+ * Admin override — force the instance into `targetStage` regardless of
9338
+ * filters or declared transitions. ACL gating is enforced upstream by the
9339
+ * caller; this verb performs no permission pre-flight, only the mechanical
9340
+ * move. `changed: false` means the move was a no-op (already at the target,
9341
+ * or terminal).
9128
9342
  */
9129
9343
  setStage: (
9130
9344
  rawArgs: Clocked<Telemetered<SetStageArgs & EngineScopeArgs>>,
9131
9345
  ) => Promise<OperationResult>;
9132
9346
  /**
9133
- * Admin override — hard-stop an in-flight instance where it stands.
9134
- * No stage move, no transition effects, pending effects cancelled;
9135
- * see {@link abortAndPropagate} for the abort + ancestor-propagation
9136
- * contract (propagated, not cascaded — the instance is terminal, so
9137
- * `cascaded` is always `0`; ancestor movement is reported on the
9138
- * ancestors, not here). `changed: false` means the instance was
9139
- * already terminal.
9347
+ * Admin override — hard-stop an in-flight instance where it stands. No stage
9348
+ * move, no transition effects, pending effects cancelled; see
9349
+ * {@link abortAndPropagate} for the abort + ancestor-propagation contract.
9350
+ * Propagated, not cascaded — the instance is terminal, so `cascaded` is
9351
+ * always `0` and ancestor movement is reported on the ancestors, not here.
9352
+ * `changed: false` means the instance was already terminal.
9140
9353
  */
9141
9354
  abortInstance: (
9142
9355
  rawArgs: Clocked<Telemetered<AbortInstanceArgs & EngineScopeArgs>>,
9143
9356
  ) => Promise<OperationResult>;
9144
9357
  /**
9145
9358
  * Admin override — reset a failed (or otherwise terminal) activity in the
9146
- * instance's current stage: `to: 'active'` re-runs it, `to: 'skipped'`
9147
- * (the bypass) resolves it so a `$allActivitiesDone`-gated exit can fire.
9148
- * Defaults to `active`. Cascades after the reset, so an unblocked
9149
- * transition fires in the same call. ACL gating should be enforced
9150
- * upstream. `changed: false` means the reset was a no-op (instance
9151
- * terminal, or the activity already at the target status).
9359
+ * instance's current stage. `to: 'active'` (the default) re-runs it;
9360
+ * `to: 'skipped'` is the bypass that resolves it so a `$allActivitiesDone`-gated
9361
+ * exit can fire. Cascades after the reset, so an unblocked transition fires
9362
+ * in the same call. ACL gating is enforced upstream by the caller; this verb
9363
+ * performs no permission pre-flight. `changed: false` means the reset was a
9364
+ * no-op (instance terminal, or the activity already at the target status).
9152
9365
  */
9153
9366
  resetActivity: (
9154
9367
  rawArgs: Clocked<Telemetered<ResetActivityArgs & EngineScopeArgs>>,
9155
9368
  ) => Promise<OperationResult>;
9156
- /**
9157
- * Fetch a workflow instance by id, scoped to the engine's tag.
9158
- * Throws when the instance doesn't exist or isn't visible to this
9159
- * engine.
9160
- */
9369
+ /** Fetch a workflow instance by id, scoped to the engine's tag. Throws when
9370
+ * the instance doesn't exist or isn't visible to this engine. */
9161
9371
  getInstance: (
9162
9372
  rawArgs: InstanceRefArgs & EngineScopeArgs,
9163
9373
  ) => Promise<WorkflowInstance>;
@@ -9168,65 +9378,52 @@ export declare const workflow: {
9168
9378
  rawArgs: GuardsForDefinitionArgs & EngineScopeArgs,
9169
9379
  ) => Promise<MutationGuardDoc[]>;
9170
9380
  /**
9171
- * Run a caller-supplied GROQ query with the engine's tag bound as
9172
- * `$tag`. This does NOT rewrite the query — arbitrary GROQ
9173
- * can't be safely tag-scoped after the fact — so the CALLER MUST
9174
- * filter on `$tag` (e.g. `tag == $tag`). To guard against accidental
9175
- * cross-partition reads, a query that never references `$tag` is
9176
- * rejected before it reaches the lake. Caller is responsible for type
9177
- * narrowing the result.
9381
+ * Run a caller-supplied GROQ query with the engine's tag bound as `$tag`.
9382
+ * This does NOT rewrite the query — arbitrary GROQ can't be safely
9383
+ * tag-scoped after the fact — so the CALLER MUST filter on `$tag` (e.g.
9384
+ * `tag == $tag`). To guard against accidental cross-partition reads, a query
9385
+ * that never references `$tag` is rejected before it reaches the lake. The
9386
+ * caller is responsible for type-narrowing the result.
9178
9387
  */
9179
9388
  query: <T = unknown>(rawArgs: QueryArgs & EngineScopeArgs) => Promise<T>;
9180
9389
  /**
9181
- * Snapshot-aware GROQ — runs against the same in-memory view that
9182
- * filters see for a given instance.
9183
- *
9184
- * Hydrates the instance's snapshot (instance + ancestors + every doc
9185
- * declared by a `doc.ref` / `subject` / `doc.refs` entry in scope), then
9186
- * evaluates the supplied GROQ in groq-js against that dataset. The
9187
- * caller-free rendered scope cascade gates evaluate in is auto-bound
9188
- * the instance-derived vars ({@link FILTER_SCOPE_VARS}) with the open
9189
- * stage's overlay merged into `$fields`, `$assigned` at its caller-free
9190
- * `false`, plus the author's pre-evaluated `$<predicate>` booleans —
9191
- * ids in GDR URI form to match the snapshot's keying.
9192
- *
9193
- * Use when an external consumer (a UI, a debug pane, a test) wants
9194
- * to ask "what does the engine see for this workflow right now?"
9195
- * without re-implementing hydration. Pure read — never writes.
9390
+ * Snapshot-aware GROQ — runs against the same in-memory view that filters
9391
+ * see for a given instance. Hydrates the instance's snapshot (instance +
9392
+ * ancestors + every doc declared by a `doc.ref` / `subject` / `doc.refs`
9393
+ * entry in scope), then evaluates the supplied GROQ in groq-js against that
9394
+ * dataset. The caller-free rendered scope cascade gates evaluate in is
9395
+ * auto-bound the instance-derived vars with the open stage's overlay
9396
+ * merged into `$fields`, `$assigned` at its caller-free `false`, plus the
9397
+ * author's pre-evaluated `$<predicate>` booleans with ids in GDR URI form
9398
+ * to match the snapshot's keying. Pure read; never writes.
9196
9399
  */
9197
9400
  queryInScope: <T = unknown>(
9198
9401
  rawArgs: Clocked<QueryInScopeArgs & EngineScopeArgs>,
9199
9402
  ) => Promise<T>;
9200
- /**
9201
- * List every pending effect on the instance. Returns the same entries
9202
- * the runtime would see — claimed and unclaimed alike.
9203
- */
9403
+ /** Every pending effect on the instance — the same entries the runtime would
9404
+ * see, claimed and unclaimed alike. */
9204
9405
  listPendingEffects: (
9205
9406
  rawArgs: InstanceRefArgs & EngineScopeArgs,
9206
9407
  ) => Promise<PendingEffect[]>;
9207
- /**
9208
- * Filter pending effects on the instance by criteria. `claimed`
9209
- * filters on claim presence; `names` restricts to specific effect
9210
- * names. Both filters compose (AND).
9211
- */
9408
+ /** Filter the instance's pending effects: `claimed` on claim presence,
9409
+ * `names` on specific effect names. Both filters compose (AND). */
9212
9410
  findPendingEffects: (
9213
9411
  rawArgs: FindPendingEffectsArgs & EngineScopeArgs,
9214
9412
  ) => Promise<PendingEffect[]>;
9215
9413
  /**
9216
- * Project the instance from a given actor's perspective. Returns a
9217
- * `WorkflowEvaluation` with per-action verdicts (`allowed` + a
9218
- * structured `disabledReason`). Pure read; never writes.
9219
- *
9220
- * Used by UIs to render disabled-with-reason buttons and by
9221
- * `fireAction` to gate writes via the same logic.
9414
+ * Project the instance from a given actor's perspective a
9415
+ * {@link WorkflowEvaluation} with per-action verdicts (`allowed` plus a
9416
+ * structured `disabledReason`). Used by UIs to render
9417
+ * disabled-with-reason buttons and by `fireAction` to gate writes through
9418
+ * the same logic. Pure read; never writes.
9222
9419
  */
9223
9420
  evaluate: (
9224
9421
  rawArgs: Clocked<EvaluateArgs & EngineScopeArgs>,
9225
9422
  ) => Promise<WorkflowEvaluation>;
9226
9423
  /**
9227
- * Diagnose why an instance is or isn't progressing. Projects the
9228
- * instance (the same read as `evaluate`) and classifies it — terminal,
9229
- * `progressing`, `waiting` (an action is available healthy), or `stuck`
9424
+ * Diagnose why an instance is or isn't progressing. Projects the instance
9425
+ * (the same read as `evaluate`) and classifies it — terminal,
9426
+ * `progressing`, `waiting` (an action is available, so healthy), or `stuck`
9230
9427
  * with a structured cause — returning that verdict as a
9231
9428
  * {@link DiagnoseResult} alongside the evaluation it came from, so a
9232
9429
  * consumer can render the supporting evidence without a second projection.
@@ -9235,59 +9432,39 @@ export declare const workflow: {
9235
9432
  diagnose: (
9236
9433
  rawArgs: Clocked<EvaluateArgs & EngineScopeArgs>,
9237
9434
  ) => Promise<DiagnoseResult>;
9238
- /**
9239
- * List the actions an actor could fire on an instance's current stage,
9240
- * each flagged `allowed` (with a structured `disabledReason` when not).
9241
- * Projects the instance from the actor's perspective and flattens its
9242
- * activities' actions. Returns the evaluation alongside the actions so a
9243
- * consumer can read the instance/stage context. Pure read.
9244
- */
9435
+ /** The actions an actor could fire on the instance's current stage, each
9436
+ * flagged `allowed` with a structured `disabledReason` when not, returned
9437
+ * with the evaluation they were projected from. Pure read. */
9245
9438
  availableActions: (
9246
9439
  rawArgs: Clocked<EvaluateArgs & EngineScopeArgs>,
9247
9440
  ) => Promise<AvailableActionsResult>;
9248
9441
  /**
9249
- * Materialised spawned children of a parent instance.
9250
- *
9251
- * Walks `history` for `spawned` eventsthe durable
9252
- * record predating the workflow-scope subworkflow registry, and still the
9253
- * one place adoption/orphan events sit alongside spawns. Strips
9254
- * the GDR URI on each `instanceRef` to a bare `_id`, fetches the
9255
- * instances, drops any that aren't visible to this engine's tag, and
9256
- * returns them sorted by `startedAt` ascending.
9257
- *
9258
- * Pass `activity` to restrict to a single spawning activity on the parent.
9442
+ * Materialised spawned children of a parent instance. Walks `history` for
9443
+ * `spawned` events — the durable record, and still the one place adoption
9444
+ * and orphan events sit alongside spawns strips each `instanceRef`'s GDR
9445
+ * URI to a bare `_id`, fetches the instances, drops any not visible to this
9446
+ * engine's tag, and returns them sorted by `startedAt` ascending. Pass
9447
+ * `activity` to restrict to a single spawning activity on the parent.
9259
9448
  */
9260
9449
  children: (
9261
9450
  rawArgs: ChildrenArgs & EngineScopeArgs,
9262
9451
  ) => Promise<WorkflowInstance[]>;
9263
9452
  /**
9264
9453
  * Every in-flight instance whose reactive watch-set includes `document` —
9265
- * the reverse of {@link subscriptionDocumentsForInstance}.
9266
- *
9267
- * For a non-reactive, content-change-driven runtime (a Sanity Function, an
9268
- * Inngest/durable worker, any server) that holds no instances in memory: a
9269
- * document changed; which instances should it `tick`? The watch-set covers
9270
- * the instance itself, its ancestors, live spawned children, and the docs named by
9271
- * `doc.ref` / `subject` / `doc.refs` / `release.ref` field entries on the
9272
- * workflow scope
9273
- * **and the current stage** — so a hand-rolled GROQ over `fields[]` gets it
9274
- * subtly wrong (misses stage-scope refs, `release.ref`, ancestors, and children).
9275
- *
9276
- * The GROQ filter narrows candidates server-side (in-flight, tag-scoped,
9277
- * matching workflow/open-stage refs); {@link instanceWatchesDocument},
9278
- * derived from `collectWatchRefs`, rechecks the result so the reverse stays
9454
+ * the reverse of an instance's subscription document set. For a
9455
+ * content-change-driven runtime holding no instances in memory: a document
9456
+ * changed, which instances should it `tick`? The watch-set covers the
9457
+ * instance itself, its ancestors, live spawned children, and the docs named
9458
+ * by `doc.ref` / `subject` / `doc.refs` / `release.ref` entries on the
9459
+ * workflow scope AND the current stage, so a hand-rolled GROQ over `fields[]`
9460
+ * gets it subtly wrong. The GROQ filter narrows candidates server-side and
9461
+ * {@link instanceWatchesDocument} rechecks each result, keeping the reverse
9279
9462
  * in lockstep with the forward set.
9280
9463
  *
9281
- * Single-resource: instances always live in the engine's own resource, so
9282
- * this reads one client (unlike {@link guardsForInstance}, whose guard docs
9283
- * are scattered across the watched resources). "Routed by resource" applies
9284
- * to the **subject**: a cross-dataset doc is matched by its full,
9285
- * resource-qualified GDR URI, never its bare id, so an instance watching
9286
- * `dataset:A:ds:doc` is not matched by a change to `dataset:B:ds:doc`.
9287
- *
9288
- * `document` must be a resource-qualified GDR URI; a bare id is rejected
9289
- * (it can't be resource-routed and would silently mismatch). Sorted by
9290
- * `startedAt` ascending.
9464
+ * `document` must be a resource-qualified GDR URI; a bare id is rejected,
9465
+ * since it can't be resource-routed and would silently mismatch — an
9466
+ * instance watching `dataset:A:ds:doc` is never matched by a change to
9467
+ * `dataset:B:ds:doc`. Sorted by `startedAt` ascending.
9291
9468
  */
9292
9469
  instancesForDocument: (
9293
9470
  rawArgs: InstancesForDocumentArgs & EngineScopeArgs,
@@ -9296,51 +9473,46 @@ export declare const workflow: {
9296
9473
  * The startable half of {@link workflow.instancesForDocument}: every
9297
9474
  * deployed definition that APPLIES to `document` — what a start picker for
9298
9475
  * it should offer. Loads the latest deployed version of each definition
9299
- * visible to the engine's tag and filters it through the derivation
9300
- * ({@link applicableDefinitions}): startable ∧ the `subject`-kind entry
9301
- * accepts the doc's `_type` ∧ `start.filter` passes evaluated in the
9302
- * browse-time-pure start-filter context with `$tag`/`$definition`/`$now`
9303
- * bound and the tag's projected start slice (completed included) backing dataset
9304
- * reads. Start requirements never participate — readiness is a start-time
9305
- * question; pre-flight it with {@link workflow.evaluateStart}.
9476
+ * visible to the engine's tag and filters it through
9477
+ * {@link applicableDefinitions}: startable ∧ the `subject`-kind entry
9478
+ * accepts the doc's `_type` ∧ `start.filter` passes, evaluated in the
9479
+ * browse-time-pure start-filter context. Start requirements never
9480
+ * participate readiness is a start-time question; pre-flight it with
9481
+ * {@link workflow.evaluateStart}.
9306
9482
  *
9307
9483
  * Takes the LOADED candidate document, not a ref — applicability evaluates
9308
9484
  * its content under whatever perspective the caller read it with. Surfaces
9309
- * ALL matches (name ascending), no engine
9310
- * ranking — presenting a picker or auto-picking is consumer policy.
9311
- * Advisory like every engine-side check.
9485
+ * ALL matches (name ascending) with no engine ranking: presenting a picker
9486
+ * or auto-picking is consumer policy. Advisory like every engine-side check.
9312
9487
  */
9313
9488
  definitionsForDocument: (
9314
9489
  rawArgs: Clocked<DefinitionsForDocumentArgs & EngineScopeArgs>,
9315
9490
  ) => Promise<DeployedDefinition[]>;
9316
9491
  /**
9317
- * Pre-flight the start gates for a definition + candidate `initialFields` —
9318
- * the read `startInstance` enforces, as a {@link StartEvaluation} a surface
9319
- * can render: `missingRequired` mirrors the input contract
9320
- * ({@link RequiredFieldNotProvidedError}'s rows), while `requirements`
9321
- * preserves every declared node's authored descriptor, outcome, and GROQ
9322
- * insight when applicable. `allowed` / `outcome` aggregate those ordered
9323
- * results. BINDABILITY-AWARE for partial mid-form inputs: when a predicate
9324
- * reads an entry `initialFields` doesn't supply including a
9325
- * `singleSubject` node's implicit subject read `outcome` is
9326
- * `'unevaluable'` and `unboundReads` names the entries ("fill these to
9327
- * decide") instead of the collapsed answer GROQ equality would give —
9328
- * this is the ONE deliberate divergence from the gate, where absence is
9329
- * final, not provisional (a rule like `!defined($fields.rush)` genuinely
9330
- * passes there when `rush` is absent). A definition declaring no start
9331
- * requirements is vacuously allowed, exactly like
9332
- * the verb. Pure read; advisory under races — the enforcement moment is
9492
+ * Pre-flight the start gates for a definition plus candidate
9493
+ * `initialFields` — the read `startInstance` enforces, as a
9494
+ * {@link StartEvaluation} a surface can render: `missingRequired` mirrors
9495
+ * the input contract, while `requirements` preserves every declared node's
9496
+ * authored descriptor, outcome, and GROQ insight where applicable;
9497
+ * `allowed` / `outcome` aggregate those ordered results.
9498
+ *
9499
+ * BINDABILITY-AWARE for partial mid-form inputs: when a predicate reads an
9500
+ * entry `initialFields` doesn't supply including a `singleSubject` node's
9501
+ * implicit subject read — `outcome` is `'unevaluable'` and `unboundReads`
9502
+ * names the entries ("fill these to decide") instead of the collapsed answer
9503
+ * GROQ equality would give. That is the ONE deliberate divergence from the
9504
+ * gate, where absence is final rather than provisional. A definition
9505
+ * declaring no start requirements is vacuously allowed, exactly like the
9506
+ * verb. Pure read; advisory under races — the enforcement moment is
9333
9507
  * `startInstance` itself.
9334
9508
  */
9335
9509
  evaluateStart: (
9336
9510
  rawArgs: Clocked<EvaluateStartArgs & EngineScopeArgs>,
9337
9511
  ) => Promise<StartEvaluation>;
9338
- /**
9339
- * Permission helpers Sanity ACL grants evaluated against documents
9340
- * via GROQ. Used by `workflow.evaluate` to soft-gate actions when the
9341
- * caller supplies grants. Deliberately namespace-only (not mirrored on
9342
- * `Engine`): pure helpers that need none of the engine's pinned scope.
9343
- */
9512
+ /** Permission helpers — Sanity ACL grants evaluated against documents via
9513
+ * GROQ, used by `workflow.evaluate` to soft-gate actions when the caller
9514
+ * supplies grants. Deliberately namespace-only, not mirrored on `Engine`:
9515
+ * pure helpers that need none of the engine's pinned scope. */
9344
9516
  permissions: {
9345
9517
  matchesFilter: typeof matchesFilter;
9346
9518
  grantsPermissionOn: typeof grantsPermissionOn;
@@ -9359,7 +9531,7 @@ export declare const WORKFLOW_DEFINITION_TYPE = "sanity.workflow.definition";
9359
9531
  * The lake document type for a workflow instance. Single source of truth — the
9360
9532
  * {@link WorkflowInstance} `_type`, every tag-scoped query, and the create
9361
9533
  * write all derive from here, mirroring {@link WORKFLOW_DEFINITION_TYPE}.
9362
- * Engine-owned standalone documents carry the platform namespace.
9534
+ * Engine-owned standalone documents use the platform namespace.
9363
9535
  */
9364
9536
  export declare const WORKFLOW_INSTANCE_TYPE = "sanity.workflow.instance";
9365
9537
 
@@ -9373,7 +9545,8 @@ declare const WORKFLOW_LIFECYCLES: readonly ["standalone", "child"];
9373
9545
  * can read; there is no engine-side permission verdict. When grants are
9374
9546
  * absent the rendered `$can` is undefined — conditions referencing it
9375
9547
  * fail closed, everything else is ungated engine-side — and the real
9376
- * Sanity write boundary takes over.
9548
+ * Sanity write boundary takes over. See {@link WorkflowAccess.attributes}
9549
+ * for the parallel `$attributes` bag.
9377
9550
  */
9378
9551
  export declare interface WorkflowAccess {
9379
9552
  actor: Actor;
@@ -9388,6 +9561,12 @@ export declare interface WorkflowAccess {
9388
9561
  */
9389
9562
  localPrincipalId?: string;
9390
9563
  grants?: Grant[];
9564
+ /**
9565
+ * Optional bag for callers that compose a {@link WorkflowAccess} by hand
9566
+ * (the test bench). {@link resolveAccess} never populates this — soft-gate
9567
+ * paths load attributes via {@link resolveUserAttributes}.
9568
+ */
9569
+ attributes?: UserAttributes;
9391
9570
  }
9392
9571
 
9393
9572
  export declare const WorkflowActionFired: WorkflowTelemetryEvent<WorkflowActionFiredData>;
@@ -9522,10 +9701,10 @@ export declare interface WorkflowClient {
9522
9701
  */
9523
9702
  withConfig?: (config: WorkflowClientConfig) => this;
9524
9703
  /**
9525
- * Optional — present on the real `@sanity/client`, absent on the
9526
- * in-memory test client. The engine probes for it when auto-resolving
9527
- * ACL grants from an endpoint; absence is the package's signal for
9528
- * "dry-run mode, don't try to fetch real grants."
9704
+ * Optional — present on the real `@sanity/client`. Without it, ACL grant
9705
+ * discovery uses its dry-run fallback, while a definition containing
9706
+ * role-constrained assignment fields fails loudly because the engine cannot
9707
+ * read the project membership directory required to validate assignees.
9529
9708
  */
9530
9709
  request?: <T>(opts: {
9531
9710
  /** Raw URL (host + path). One of `url` / `uri` required. */
@@ -9588,6 +9767,16 @@ export declare interface WorkflowCommitOptions {
9588
9767
  tag?: string;
9589
9768
  }
9590
9769
 
9770
+ /**
9771
+ * `deployments` names must be unique (the selector deployment-targeted
9772
+ * commands resolve by), and each `(workflowResource, tag)` pair must be
9773
+ * unique — that pair is the storage partition, so two deployments sharing
9774
+ * both would fight over definition versions. `telemetry`, when set, replaces
9775
+ * the CLI's built-in Sanity-intake shell entirely: every event flows to this
9776
+ * logger unconditionally (CI and `DO_NOT_TRACK` included), and consent,
9777
+ * environment suppression, and transport become this implementation's
9778
+ * business.
9779
+ */
9591
9780
  export declare type WorkflowConfig = v.InferOutput<typeof WorkflowConfigSchema>;
9592
9781
 
9593
9782
  /**
@@ -9865,6 +10054,7 @@ declare const WorkflowConfigSchema: v.ObjectSchema<
9865
10054
  v.CustomSchema<
9866
10055
  {
9867
10056
  name: string;
10057
+ semantics?: Semantic[] | undefined;
9868
10058
  title: string;
9869
10059
  description?: string | undefined;
9870
10060
  groups?: Group[] | undefined;
@@ -9883,6 +10073,7 @@ declare const WorkflowConfigSchema: v.ObjectSchema<
9883
10073
  v.MinLengthAction<
9884
10074
  {
9885
10075
  name: string;
10076
+ semantics?: Semantic[] | undefined;
9886
10077
  title: string;
9887
10078
  description?: string | undefined;
9888
10079
  groups?: Group[] | undefined;
@@ -9950,6 +10141,7 @@ declare const WorkflowConfigSchema: v.ObjectSchema<
9950
10141
  | undefined;
9951
10142
  definitions: {
9952
10143
  name: string;
10144
+ semantics?: Semantic[] | undefined;
9953
10145
  title: string;
9954
10146
  description?: string | undefined;
9955
10147
  groups?: Group[] | undefined;
@@ -10011,6 +10203,7 @@ declare const WorkflowConfigSchema: v.ObjectSchema<
10011
10203
  | undefined;
10012
10204
  definitions: {
10013
10205
  name: string;
10206
+ semantics?: Semantic[] | undefined;
10014
10207
  title: string;
10015
10208
  description?: string | undefined;
10016
10209
  groups?: Group[] | undefined;
@@ -10070,6 +10263,7 @@ declare const WorkflowConfigSchema: v.ObjectSchema<
10070
10263
  | undefined;
10071
10264
  definitions: {
10072
10265
  name: string;
10266
+ semantics?: Semantic[] | undefined;
10073
10267
  title: string;
10074
10268
  description?: string | undefined;
10075
10269
  groups?: Group[] | undefined;
@@ -10131,6 +10325,7 @@ declare const WorkflowConfigSchema: v.ObjectSchema<
10131
10325
  | undefined;
10132
10326
  definitions: {
10133
10327
  name: string;
10328
+ semantics?: Semantic[] | undefined;
10134
10329
  title: string;
10135
10330
  description?: string | undefined;
10136
10331
  groups?: Group[] | undefined;
@@ -10190,6 +10385,7 @@ declare const WorkflowConfigSchema: v.ObjectSchema<
10190
10385
  | undefined;
10191
10386
  definitions: {
10192
10387
  name: string;
10388
+ semantics?: Semantic[] | undefined;
10193
10389
  title: string;
10194
10390
  description?: string | undefined;
10195
10391
  groups?: Group[] | undefined;
@@ -10207,14 +10403,6 @@ declare const WorkflowConfigSchema: v.ObjectSchema<
10207
10403
  >,
10208
10404
  ]
10209
10405
  >;
10210
- /**
10211
- * Custom telemetry destination for the CLI. When set, the CLI's built-in
10212
- * Sanity-intake shell is not constructed and none of its policy applies:
10213
- * every event — the command trace and the engine vocabulary — flows to
10214
- * this logger unconditionally (CI and `DO_NOT_TRACK` environments
10215
- * included). Consent, environment suppression, transport, and destination
10216
- * are wholly this implementation's business.
10217
- */
10218
10406
  readonly telemetry: v.OptionalSchema<
10219
10407
  v.CustomSchema<
10220
10408
  WorkflowTelemetryLogger,
@@ -10226,6 +10414,21 @@ declare const WorkflowConfigSchema: v.ObjectSchema<
10226
10414
  undefined
10227
10415
  >;
10228
10416
 
10417
+ /**
10418
+ * `name` is a lake-id-segment (`^[a-z0-9][a-z0-9-]*$`) that interpolates into
10419
+ * every deployed document id (`<tag>.<name>.v<version>`) — stable identity
10420
+ * that instances pin to and subworkflows resolve by. `lifecycle: 'child'`
10421
+ * marks a spawn-only definition, instantiated by a parent via an action's
10422
+ * `spawn`, never started cold from a picker (omitted ⇒ `'standalone'`,
10423
+ * startable); advisory only — consumers filter start pickers on it (see
10424
+ * {@link isStartableDefinition}), the engine does not itself refuse a
10425
+ * `startInstance` on a `'child'` definition. `start` is meaningless
10426
+ * (deploy-rejected) on a spawn-only definition; omitted, it means
10427
+ * interactive semantics with no predicates. `predicates` are nullary named
10428
+ * conditions — each `name: groq` entry is pre-evaluated and bound as the
10429
+ * boolean `$name` var; redefining a built-in var is a deploy error, never a
10430
+ * silent shadow.
10431
+ */
10229
10432
  export declare type WorkflowDefinition = v.InferOutput<
10230
10433
  typeof WorkflowDefinitionSchema
10231
10434
  >;
@@ -10298,37 +10501,37 @@ export declare type WorkflowDefinitionInput<T> = string extends keyof T
10298
10501
  * every reference scope resolved. Cross-field invariants (unique names,
10299
10502
  * transition targets, effect-name uniqueness, predicate shadowing) are
10300
10503
  * checked by `checkWorkflowInvariants` after desugar — see `defineWorkflow`.
10504
+ * Carries NO `version`: a definition's version and content fingerprint are
10505
+ * stamped onto the deployed document at deploy time, derived from the
10506
+ * content itself, so redeploying identical content is a no-op and any
10507
+ * change mints the next version.
10301
10508
  *
10302
- * Carries NO `version` the author never writes one. A definition's version
10303
- * (and its content fingerprint) are stamped onto the deployed *document* at
10304
- * deploy time, derived from the content itself; see `DeployedDefinition` and
10305
- * `planDefinitionDeploy` in `api/deploy.ts`. The author's content is the sole
10306
- * source of identity: redeploying identical content is a no-op, any change
10307
- * mints the next version.
10509
+ * Exported (module-level, not package API) for the model-surface gate's
10510
+ * coverage test and for `parseStoredDefinition` the boundary parse for a
10511
+ * definition that did not come out of `defineWorkflow` in-process; trusted
10512
+ * in-process desugar output is never re-parsed.
10308
10513
  */
10309
10514
  declare const WorkflowDefinitionSchema: v.GenericSchema<
10310
10515
  WorkflowFields<FieldEntry, Stage, StartBlock>
10311
10516
  >;
10312
10517
 
10313
10518
  /** One deployment as loaded from a config: the floor is optional/unverified so
10314
- * a command that never selects a deployment can hold a stale or missing
10315
- * acknowledgement. Deployment-scoped paths assert before they act; authors
10316
- * write {@link WorkflowDeploymentInput}. */
10519
+ * commands that do not submit definitions can hold a missing acknowledgement.
10520
+ * Definition-submission paths compare it with their selected definitions; authors write
10521
+ * {@link WorkflowDeploymentInput}. */
10317
10522
  export declare type WorkflowDeployment = WorkflowConfig["deployments"][number];
10318
10523
 
10319
10524
  /**
10320
- * What an author writes for one deployment: the current reader floor as the
10321
- * reviewed literal. Compile-time only omitting it or setting a wrong value
10322
- * is a type error in the editor. Runtime parse still tolerates a stale or
10323
- * missing floor on {@link WorkflowDeployment} so commands that never select a
10324
- * deployment still run; deployment-scoped paths assert the selected
10325
- * deployment (instance-id commands do not).
10525
+ * What an author writes for one deployment: the highest reader model verified
10526
+ * across runtimes sharing its workflow resource. Runtime validation compares
10527
+ * it with the submitted definitions, so a dependency upgrade alone does not
10528
+ * require changing the literal.
10326
10529
  */
10327
10530
  export declare type WorkflowDeploymentInput = Omit<
10328
10531
  WorkflowDeployment,
10329
10532
  "expectedMinReaderModel"
10330
10533
  > & {
10331
- expectedMinReaderModel: typeof DATA_MODEL_MIN_READER;
10534
+ expectedMinReaderModel: number;
10332
10535
  };
10333
10536
 
10334
10537
  export declare const WorkflowEffectCompleted: WorkflowTelemetryEvent<WorkflowEffectCompletedData>;
@@ -10423,6 +10626,8 @@ export declare type WorkflowErrorKind =
10423
10626
  export declare interface WorkflowEvaluation {
10424
10627
  instance: WorkflowInstance;
10425
10628
  definition: WorkflowDefinition;
10629
+ /** The workflow's advisory meaning, unchanged from its definition. */
10630
+ semantics?: Semantic[] | undefined;
10426
10631
  actor: Actor;
10427
10632
  currentStage: StageEvaluation;
10428
10633
  /** Active activities whose assignees-kind field entry matches the actor. */
@@ -10480,13 +10685,8 @@ export declare interface WorkflowFieldEditedData extends InstanceScopedEventData
10480
10685
 
10481
10686
  /** Type-mirror of {@link workflowFields}, parameterised over field/stage/start. */
10482
10687
  declare type WorkflowFields<TField, TStage, TStart> = {
10483
- /**
10484
- * Lake-id-segment grammar (`^[a-z0-9][a-z0-9-]*$`, deploy-enforced): the
10485
- * name interpolates into every deployed document id
10486
- * (`<tag>.<name>.v<version>`). Stable identity — instances pin to it,
10487
- * subworkflows resolve by it.
10488
- */
10489
10688
  name: string;
10689
+ semantics?: Semantic[] | undefined;
10490
10690
  title: string;
10491
10691
  description?: string | undefined;
10492
10692
  groups?: Group[] | undefined;
@@ -10511,8 +10711,8 @@ export declare interface WorkflowInstance extends SanityDocument {
10511
10711
  modelVersion?: number;
10512
10712
  /**
10513
10713
  * Reader floor — the oldest engine data model that can safely interpret
10514
- * this document. No lower than the writer's unconditional
10515
- * {@link DATA_MODEL_MIN_READER}, and written alongside
10714
+ * this document. Derived from its persisted features and the retained
10715
+ * model-4 baseline, and written alongside
10516
10716
  * {@link WorkflowInstance.modelVersion}. Full persists never lower it.
10517
10717
  */
10518
10718
  minReaderModel?: number;
@@ -10538,7 +10738,7 @@ export declare interface WorkflowInstance extends SanityDocument {
10538
10738
  * can detect a deployed definition that drifted from what this instance
10539
10739
  * started on. Advisory — the engine enforces nothing; this enables detection,
10540
10740
  * not prevention. Absent when the instance was started against a definition
10541
- * deployed before content-addressing (it carried no hash to pin).
10741
+ * deployed before content-addressing (it had no hash to pin).
10542
10742
  */
10543
10743
  pinnedContentHash?: string;
10544
10744
  /** Frozen JSON snapshot of the definition at the moment the instance started. */
@@ -10587,10 +10787,10 @@ export declare interface WorkflowInstance extends SanityDocument {
10587
10787
  */
10588
10788
  stages: StageEntry[];
10589
10789
  /**
10590
- * Workflow-scope registry of every child this instance ever spawned
10790
+ * Workflow-scope registry of every child this instance ever spawned;
10591
10791
  * see {@link SubworkflowEntry}. Rows are never deleted; a row without
10592
- * `resolved` is a LIVE child (watched, hydrated, propagating), one with
10593
- * it is terminal, and a live row with `abortPending` is CONDEMNED — the
10792
+ * `resolved` is a live child (watched, hydrated, propagating), one with
10793
+ * it is terminal, and a live row with `abortPending` is condemned — the
10594
10794
  * cascade owes it an abort. Rendered as the `$subworkflows` condition
10595
10795
  * var. Absent only on instances persisted before the registry existed.
10596
10796
  */
@@ -10620,6 +10820,63 @@ export declare interface WorkflowInstance extends SanityDocument {
10620
10820
 
10621
10821
  export declare const WorkflowInstanceAborted: WorkflowTelemetryEvent<WorkflowAdminOverrideData>;
10622
10822
 
10823
+ /**
10824
+ * The instance list projection — a reduced {@link WorkflowInstance} for
10825
+ * surfaces that render many runs at once, fetched by `instancePreviewsQuery`.
10826
+ *
10827
+ * The reduction keeps the full instance's field names and member shapes so
10828
+ * instance helpers (`terminalState`, `findOpenStageEntry`, `parentRef`, the
10829
+ * identity normalizer) read a preview unchanged; what shrinks is the content:
10830
+ * `stages` holds the open entry alone, every `fields` list keeps only the
10831
+ * identity, date, document-reference, and release-reference kinds, and the unbounded audit
10832
+ * trails are gone — `claimedEffects` and `failedEffects` hold the two facts
10833
+ * a stuck classifier reads in their place. There is deliberately no
10834
+ * `definitionSnapshot`: a consumer titles what it shows from the deployed
10835
+ * catalog, falling back to raw names.
10836
+ */
10837
+ export declare interface WorkflowInstancePreview {
10838
+ _id: string;
10839
+ _type: typeof WORKFLOW_INSTANCE_TYPE;
10840
+ /** See {@link WorkflowInstance.modelVersion}. */
10841
+ modelVersion?: number;
10842
+ /** See {@link WorkflowInstance.minReaderModel}. */
10843
+ minReaderModel?: number;
10844
+ workflowResource: WorkflowResource;
10845
+ definition: string;
10846
+ pinnedVersion: number;
10847
+ /** Identity, date, document-reference, and release-reference entries only
10848
+ * — the kinds list surfaces read. Composite (`object`/`array`) entries are
10849
+ * dropped, so identities nested inside them are invisible to a preview. */
10850
+ fields: ResolvedFieldEntry[];
10851
+ ancestors: GlobalDocumentReference[];
10852
+ perspective?: WorkflowPerspective;
10853
+ currentStage: StageName;
10854
+ /** The open stage entry alone, its activities' fields reduced like
10855
+ * {@link fields}. A completed run keeps its terminal entry open, so this
10856
+ * is empty only for an aborted run (whose entries closed in place) or
10857
+ * before the run primes. */
10858
+ stages: StageEntry[];
10859
+ /** Pending effects a drainer has claimed — the hung-automation fact. */
10860
+ claimedEffects: WorkflowInstancePreviewEffect[];
10861
+ /** Effect-history rows that reported failure — the failed-automation fact. */
10862
+ failedEffects: WorkflowInstancePreviewEffect[];
10863
+ startedAt: string;
10864
+ completedAt?: string;
10865
+ abortedAt?: string;
10866
+ }
10867
+
10868
+ /** A stalled automation as a preview reports it — the effect's machine name
10869
+ * and its display title. */
10870
+ export declare interface WorkflowInstancePreviewEffect {
10871
+ name: string;
10872
+ title?: string;
10873
+ }
10874
+
10875
+ /** The instance list projection (`instancePreviewsQuery` results). The reduced
10876
+ * members reuse the persisted document's own schemas, so a preview can
10877
+ * never admit a shape the full parse would refuse. */
10878
+ export declare const WorkflowInstancePreviewSchema: v.GenericSchema<WorkflowInstancePreview>;
10879
+
10623
10880
  /**
10624
10881
  * The persisted instance document, root to leaf. Reused verbatim by every
10625
10882
  * engine read boundary through {@link parseInstanceDocument}; the