@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/define.d.cts CHANGED
@@ -1,14 +1,24 @@
1
1
  import * as v from "valibot";
2
2
 
3
+ /**
4
+ * A stored action. `semantics` is engine-owned advisory meaning, independent
5
+ * of execution and presentation — an array so the vocabulary can grow without
6
+ * reshaping this field. `when`'s presence makes the action CASCADE-FIRED: the
7
+ * engine fires it the moment the condition turns true, at most once per stage
8
+ * visit, and it is never invocable via `fireAction`; absent, the action must
9
+ * be invoked via `fireAction` by any caller holding a token (fire-on-entry is
10
+ * `when: 'true'`). `filter` is existence with GROQ semantics — a non-matching
11
+ * action might as well not exist (invisible to UI and LLMs, never merely
12
+ * disabled); on a `when` action it composes: `filter` scopes whether the
13
+ * automation exists, `when` is its firing trigger. `roles` is kept VERBATIM
14
+ * only when cascade-fired (the pin on which identities may execute the
15
+ * trigger); a fireAction-fired action's `roles` folds into `filter` at
16
+ * desugar instead.
17
+ */
3
18
  declare type Action = ActionFields<Op, string[]> & {
4
19
  roles?: string[] | undefined;
5
20
  };
6
21
 
7
- declare const ACTION_SEMANTICS: readonly [
8
- "decision.accept",
9
- "decision.decline",
10
- ];
11
-
12
22
  /** Type-mirror of {@link actionFields}, parameterised over the op and
13
23
  * group-membership grammars. */
14
24
  declare type ActionFields<TOp, TGroup> = {
@@ -25,14 +35,14 @@ declare type ActionFields<TOp, TGroup> = {
25
35
  spawn?: Subworkflows | undefined;
26
36
  };
27
37
 
28
- declare type ActionParam = v.InferOutput<typeof ActionParamSchema>;
29
-
30
38
  /**
31
- * Caller-supplied params declared on an action. The engine validates
32
- * incoming `params` against this list before running ops or queuing
33
- * effects: missing required params ActionParamsInvalidError, action
34
- * does not commit. Resolved values feed `ValueExpr.param` lookups.
39
+ * Caller-supplied params declared on an action, validated before running ops
40
+ * or queuing effects: a missing required param throws
41
+ * `ActionParamsInvalidError` and the action does not commit. Resolved values
42
+ * feed `ValueExpr.param` lookups.
35
43
  */
44
+ declare type ActionParam = v.InferOutput<typeof ActionParamSchema>;
45
+
36
46
  declare const ActionParamSchema: v.SchemaWithPipe<
37
47
  readonly [
38
48
  v.StrictObjectSchema<
@@ -160,8 +170,22 @@ declare const ActionParamSchema: v.SchemaWithPipe<
160
170
  ]
161
171
  >;
162
172
 
163
- declare type ActionSemantic = (typeof ACTION_SEMANTICS)[number];
173
+ declare type ActionSemantic = DecisionSemantic | Semantic;
164
174
 
175
+ /**
176
+ * A unit of work carrying no payload of its own — every op, effect, and
177
+ * spawn lives on an action; an activity contributes scoped `fields`
178
+ * (resolved at stage entry), existence (`filter`), advisory readiness
179
+ * (`requirements`), and the off-system marker (`target`, a BPMN Manual Task
180
+ * deep-link, render-only and never gating). All in-scope activities are
181
+ * ACTIVE from stage entry until an action's terminal `status` resolves them —
182
+ * there is no activation moment. `filter` is existence with GROQ semantics,
183
+ * evaluated once against the stage's entry state: a definite `false`
184
+ * excludes the activity from UI, LLMs, and `$allActivitiesDone`.
185
+ * `requirements` are readiness gates orthogonal to `filter` — an unmet one
186
+ * keeps the activity visible but disables its actions with a
187
+ * `requirements-unmet` verdict; distinct from ACL and guards.
188
+ */
165
189
  declare type Activity = ActivityFields<
166
190
  FieldEntry,
167
191
  Action,
@@ -172,6 +196,7 @@ declare type Activity = ActivityFields<
172
196
  /** Type-mirror of {@link activityFields}, parameterised over field/action/target/group. */
173
197
  declare type ActivityFields<TField, TAction, TTarget, TGroup> = {
174
198
  name: string;
199
+ semantics?: Semantic[] | undefined;
175
200
  title?: string | undefined;
176
201
  description?: string | undefined;
177
202
  groups?: Group[] | undefined;
@@ -183,6 +208,18 @@ declare type ActivityFields<TField, TAction, TTarget, TGroup> = {
183
208
  fields?: TField[] | undefined;
184
209
  };
185
210
 
211
+ /**
212
+ * The stored action fields plus two authoring sugars, or the
213
+ * {@link ClaimAction} pair-half. `roles`: on a fireAction-fired action (no
214
+ * `when`) it desugars into a `count($actor.roles[@ in [...]]) > 0` condition
215
+ * ANDed with `filter`; on a CASCADE-FIRED action it stores VERBATIM instead —
216
+ * the pin on which identities may execute the trigger, since folding it into
217
+ * `filter` would make the action's existence depend on whose token cascades.
218
+ * `roleAliases` widens the membership either way. `status` compiles to a
219
+ * `status.set` op on the firing activity, appended AFTER the authored ops —
220
+ * deliberately never implied, so a forgotten `status` is a visible stall
221
+ * rather than a silently completed action.
222
+ */
186
223
  declare type AuthoringAction = AuthoringRawAction | ClaimAction;
187
224
 
188
225
  declare type AuthoringActivity = ActivityFields<
@@ -192,14 +229,14 @@ declare type AuthoringActivity = ActivityFields<
192
229
  GroupMembership
193
230
  >;
194
231
 
195
- declare type AuthoringEditable = v.InferOutput<typeof AuthoringEditableSchema>;
196
-
197
232
  /**
198
233
  * Authoring editability adds the `role[]` convenience: a non-empty role list
199
234
  * desugars to the same `count($actor.roles[@ in [...]]) > 0` membership
200
235
  * predicate `action.roles` produces. `true` opens the field to anyone in its
201
236
  * window; a bare string is a raw predicate.
202
237
  */
238
+ declare type AuthoringEditable = v.InferOutput<typeof AuthoringEditableSchema>;
239
+
203
240
  declare const AuthoringEditableSchema: v.UnionSchema<
204
241
  [
205
242
  v.LiteralSchema<true, undefined>,
@@ -228,6 +265,8 @@ declare type AuthoringFieldEntry =
228
265
  | TodoListField
229
266
  | NotesField;
230
267
 
268
+ /** A field reference with `scope` optional; desugar resolves it lexically
269
+ * (activity → stage → workflow) into {@link StoredFieldRef}. */
231
270
  declare type AuthoringFieldRef = v.InferOutput<typeof AuthoringFieldRefSchema>;
232
271
 
233
272
  declare const AuthoringFieldRefSchema: v.StrictObjectSchema<
@@ -246,15 +285,12 @@ declare const AuthoringFieldRefSchema: v.StrictObjectSchema<
246
285
  undefined
247
286
  >;
248
287
 
288
+ /** {@link Guard}'s contract as authored: `match.idRefs` and `metadata` carry
289
+ * typed {@link GuardRead} values that deploy resolves to bare ones. */
249
290
  declare type AuthoringGuard = v.InferOutput<typeof AuthoringGuardSchema>;
250
291
 
251
292
  declare const AuthoringGuardSchema: v.StrictObjectSchema<
252
293
  {
253
- /**
254
- * Lake-id-segment grammar (`^[a-z0-9][a-z0-9-]*$`, deploy-enforced): the
255
- * guard's lake `_id` derives from `(instanceId, name)` at stage entry.
256
- * Unique per definition.
257
- */
258
294
  name: v.SchemaWithPipe<
259
295
  readonly [
260
296
  v.StringSchema<undefined>,
@@ -265,7 +301,6 @@ declare const AuthoringGuardSchema: v.StrictObjectSchema<
265
301
  description: v.OptionalSchema<v.StringSchema<undefined>, undefined>;
266
302
  match: v.StrictObjectSchema<
267
303
  {
268
- /** Subject `_type`(s); empty matches any type. */
269
304
  types: v.OptionalSchema<
270
305
  v.ArraySchema<
271
306
  v.SchemaWithPipe<
@@ -278,7 +313,6 @@ declare const AuthoringGuardSchema: v.StrictObjectSchema<
278
313
  >,
279
314
  undefined
280
315
  >;
281
- /** Target docs as field reads (or the instance itself), resolved at deploy to bare ids + the resource. */
282
316
  idRefs: v.OptionalSchema<
283
317
  v.ArraySchema<
284
318
  v.VariantSchema<
@@ -381,7 +415,6 @@ declare const AuthoringGuardSchema: v.StrictObjectSchema<
381
415
  >,
382
416
  undefined
383
417
  >;
384
- /** Glob id patterns (bare, resource-local). */
385
418
  idPatterns: v.OptionalSchema<
386
419
  v.ArraySchema<
387
420
  v.SchemaWithPipe<
@@ -413,22 +446,7 @@ declare const AuthoringGuardSchema: v.StrictObjectSchema<
413
446
  },
414
447
  undefined
415
448
  >;
416
- /**
417
- * Lake GROQ predicate — a distinct eval context: delta-mode GROQ
418
- * reading the `before()`/`after()` natives, `mutation`, `guard`, and
419
- * `identity()`. Bare ids/fields only. Polarity: a result of strictly
420
- * `true` ALLOWS the matched mutation; anything else (false, null, an
421
- * evaluation error) DENIES. Omitted or empty means UNCONDITIONAL DENY.
422
- */
423
449
  predicate: v.OptionalSchema<v.StringSchema<undefined>, undefined>;
424
- /**
425
- * Projected workflow fields the predicate reads as `guard.metadata.*` —
426
- * the only bridge from the lake eval context (which cannot see `$fields`)
427
- * to workflow fields. Each value is a deploy-time read — a typed
428
- * {@link GuardRead} when authoring, the printed string spelling once
429
- * stored — resolved into a bare value at deploy and re-synced by the
430
- * post-field-op guard refresh.
431
- */
432
450
  metadata: v.OptionalSchema<
433
451
  v.RecordSchema<
434
452
  v.SchemaWithPipe<
@@ -538,6 +556,8 @@ declare const AuthoringGuardSchema: v.StrictObjectSchema<
538
556
  undefined
539
557
  >;
540
558
 
559
+ /** Like {@link ManualTarget}, but the `field` variant also accepts a bare
560
+ * field name; desugar normalises it into {@link AuthoringFieldRef}. */
541
561
  declare type AuthoringManualTarget = v.InferOutput<
542
562
  typeof AuthoringManualTargetSchema
543
563
  >;
@@ -597,6 +617,9 @@ declare const AuthoringManualTargetSchema: v.VariantSchema<
597
617
  undefined
598
618
  >;
599
619
 
620
+ /** Like {@link Op}, plus: `status.set`'s `activity` is optional (desugar fills
621
+ * the firing activity), and the `audit` sugar — a stamped append merging
622
+ * `actor`/`at` {@link ValueExpr} fields into its own value. */
600
623
  declare type AuthoringOp = v.InferOutput<typeof AuthoringOpSchema>;
601
624
 
602
625
  declare const AuthoringOpSchema: v.VariantSchema<
@@ -627,6 +650,31 @@ declare const AuthoringOpSchema: v.VariantSchema<
627
650
  },
628
651
  undefined
629
652
  >,
653
+ v.StrictObjectSchema<
654
+ {
655
+ readonly type: v.LiteralSchema<"field.setIfMissing", undefined>;
656
+ readonly target: v.StrictObjectSchema<
657
+ {
658
+ readonly scope: v.OptionalSchema<
659
+ v.PicklistSchema<
660
+ readonly ["workflow", "stage", "activity"],
661
+ string
662
+ >,
663
+ undefined
664
+ >;
665
+ readonly field: v.SchemaWithPipe<
666
+ readonly [
667
+ v.StringSchema<undefined>,
668
+ v.MinLengthAction<string, 1, "must be a non-empty string">,
669
+ ]
670
+ >;
671
+ },
672
+ undefined
673
+ >;
674
+ readonly value: v.GenericSchema<ValueExprInternal>;
675
+ },
676
+ undefined
677
+ >,
630
678
  v.StrictObjectSchema<
631
679
  {
632
680
  readonly type: v.LiteralSchema<"field.unset", undefined>;
@@ -676,6 +724,62 @@ declare const AuthoringOpSchema: v.VariantSchema<
676
724
  },
677
725
  undefined
678
726
  >,
727
+ v.StrictObjectSchema<
728
+ {
729
+ readonly type: v.LiteralSchema<"field.inc", undefined>;
730
+ readonly target: v.StrictObjectSchema<
731
+ {
732
+ readonly scope: v.OptionalSchema<
733
+ v.PicklistSchema<
734
+ readonly ["workflow", "stage", "activity"],
735
+ string
736
+ >,
737
+ undefined
738
+ >;
739
+ readonly field: v.SchemaWithPipe<
740
+ readonly [
741
+ v.StringSchema<undefined>,
742
+ v.MinLengthAction<string, 1, "must be a non-empty string">,
743
+ ]
744
+ >;
745
+ },
746
+ undefined
747
+ >;
748
+ readonly value: v.OptionalSchema<
749
+ v.GenericSchema<ValueExprInternal>,
750
+ undefined
751
+ >;
752
+ },
753
+ undefined
754
+ >,
755
+ v.StrictObjectSchema<
756
+ {
757
+ readonly type: v.LiteralSchema<"field.dec", undefined>;
758
+ readonly target: v.StrictObjectSchema<
759
+ {
760
+ readonly scope: v.OptionalSchema<
761
+ v.PicklistSchema<
762
+ readonly ["workflow", "stage", "activity"],
763
+ string
764
+ >,
765
+ undefined
766
+ >;
767
+ readonly field: v.SchemaWithPipe<
768
+ readonly [
769
+ v.StringSchema<undefined>,
770
+ v.MinLengthAction<string, 1, "must be a non-empty string">,
771
+ ]
772
+ >;
773
+ },
774
+ undefined
775
+ >;
776
+ readonly value: v.OptionalSchema<
777
+ v.GenericSchema<ValueExprInternal>,
778
+ undefined
779
+ >;
780
+ },
781
+ undefined
782
+ >,
679
783
  v.StrictObjectSchema<
680
784
  {
681
785
  readonly type: v.LiteralSchema<"field.updateWhere", undefined>;
@@ -811,27 +915,6 @@ declare const AuthoringOpSchema: v.VariantSchema<
811
915
  undefined
812
916
  >;
813
917
 
814
- /**
815
- * Authoring action — the stored fields plus two field sugars with one
816
- * defined expansion each:
817
- *
818
- * - `roles` — on a fireAction-fired action (no `when`) it desugars to a
819
- * `count($actor.roles[@ in [...]]) > 0` membership condition ANDed with
820
- * the authored `filter` (for a caller, "not yours to fire" and "doesn't
821
- * exist for you" are the same advisory answer). On a CASCADE-FIRED
822
- * action it stores VERBATIM — the pin on which identities may execute
823
- * the trigger; folding it into `filter` would make the action's
824
- * existence depend on whose token happens to cascade. The definition's
825
- * `roleAliases` ({@link RoleAliasesSchema}) widen the membership either
826
- * way.
827
- * - `status` → a `status.set` op on the firing activity, appended **after**
828
- * the authored ops (deliberately never implied: a forgotten explicit
829
- * `status` is a visible stall, an implied default silently completes
830
- * claim-like actions). Status is the health axis: a decision action
831
- * (decline, send back) resolves `done` and writes the decision into a
832
- * field the transition trigger reads — `failed` is for work that
833
- * genuinely could not complete.
834
- */
835
918
  declare type AuthoringRawAction = ActionFields<AuthoringOp, GroupMembership> & {
836
919
  roles?: string[] | undefined;
837
920
  status?: TerminalActivityStatus | undefined;
@@ -881,14 +964,8 @@ declare interface ChoiceOptions {
881
964
 
882
965
  declare type ChoiceValue = string | number;
883
966
 
884
- /**
885
- * The action half of the mirrored claim pair. `field` references an
886
- * author-declared actor-valued entry (the pair's other half), resolved
887
- * lexically. Expansion, strictly within this action: a no-steal
888
- * `!defined($fields.<field>)` filter ANDed with `roles`/`filter`, plus a
889
- * `field.set` ← actor op. `ops` and `status` are reserved (the expansion
890
- * owns them) — strictObject rejects them as unknown keys.
891
- */
967
+ /** The action half of the mirrored claim pair: `field` names the actor-valued entry this action claims, resolved lexically, and the expansion
968
+ * 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). */
892
969
  declare type ClaimAction = {
893
970
  type: "claim";
894
971
  name: string;
@@ -902,12 +979,8 @@ declare type ClaimAction = {
902
979
  effects?: Effect[] | undefined;
903
980
  };
904
981
 
905
- /**
906
- * Authoring fields accept the raw entries plus the `claim` sugar type the
907
- * field half of the mirrored claim pair. Expansion: an `actor` working-
908
- * memory field (no `initialValue`; the claim action's op fills it), strictly
909
- * within this entry.
910
- */
982
+ /** The field half of the mirrored claim pair, expanding strictly within this entry: an `actor`
983
+ * working-memory field with no `initialValue` the paired {@link ClaimAction}'s op fills it. */
911
984
  declare type ClaimField = {
912
985
  type: "claim";
913
986
  name: string;
@@ -917,10 +990,23 @@ declare type ClaimField = {
917
990
  };
918
991
 
919
992
  /**
920
- * Every variable the engine binds for conditions, in one place. The
921
- * deploy-time shadow check ({@link RESERVED_CONDITION_VARS}) and the docs on
922
- * {@link Condition} derive from this list — extend it here when the engine
923
- * grows a binding, never in a comment elsewhere.
993
+ * Every variable the engine binds for the RENDERED condition scope (every
994
+ * condition site: transition `when`s, activity filters, action
995
+ * `when`s/filters, effect bindings, `spawn` reads, where-op `where`s,
996
+ * editability predicates, author predicates) the deploy-time shadow check
997
+ * ({@link RESERVED_CONDITION_VARS}) and the docs on {@link Condition} derive
998
+ * from this list; extend it here when the engine grows a binding, never in
999
+ * a comment elsewhere.
1000
+ *
1001
+ * Three other GROQ contexts read a definition and do NOT share this
1002
+ * inventory: cascade gates (transition/activity/cascade-action gates, which
1003
+ * must resolve identically regardless of caller — only the `'always'`-bound
1004
+ * subset carries values, {@link FILTER_SCOPE_VARS}); the start contexts
1005
+ * (`start.filter` is browse-time-pure over a candidate document,
1006
+ * {@link START_FILTER_VARS}; a start `groq` requirement binds `$fields`
1007
+ * instead, {@link START_REQUIREMENT_VARS}); and lake guard predicates, which
1008
+ * are not conditions at all — delta-mode GROQ over a mutation, binding
1009
+ * {@link GUARD_PREDICATE_VARS} instead.
924
1010
  */
925
1011
  export declare const CONDITION_VARS: readonly ConditionVar[];
926
1012
 
@@ -934,43 +1020,6 @@ export declare interface ConditionVar {
934
1020
  label: string;
935
1021
  }
936
1022
 
937
- /**
938
- * The condition-variable inventory — the single source of truth for every
939
- * `$var` the engine binds when it evaluates a {@link Condition}.
940
- *
941
- * Four evaluation contexts read a definition's GROQ:
942
- *
943
- * 1. **Rendered condition scope** — every condition site in a definition
944
- * (transition `when`s, activity filters, action `when`s/filters, effect
945
- * bindings, `spawn` reads, where-op `where`s, editability predicates,
946
- * author predicates). {@link CONDITION_VARS} is its inventory; each
947
- * entry's `binding` says when the var actually holds a value. The
948
- * where-op context is the one closed subset — its bound set is statically
949
- * fixed and deploy-enforced (see the op-where scope's param-name list in
950
- * the op applier).
951
- * 2. **Cascade gates** — transition `when`s, activity filters, and a
952
- * cascade-fired action's `when`/`filter` must resolve identically no
953
- * matter whose token drives the cascade, so only the `'always'`-bound
954
- * subset carries values there ({@link FILTER_SCOPE_VARS}). Caller-bound
955
- * vars fail closed — `$assigned` binds its caller-free constant `false`,
956
- * the rest evaluate to `undefined` — and deploy rejects them at these
957
- * sites; a cascade-fired action's per-token gate is `roles`, never its
958
- * conditions.
959
- * 3. **The start contexts** — a definition's `start.filter` and start GROQ
960
- * requirements evaluate against a CANDIDATE (no instance exists yet):
961
- * `*[...]` reads the engine-owned `{definition, subject, completedAt}`
962
- * projection of the tag's instances and none of the rendered
963
- * condition vars exist. The two split on what a surface can know:
964
- * `filter` is browse-time-pure (candidate document as root,
965
- * {@link START_FILTER_VARS} — no `$fields`, which cannot exist before
966
- * inputs do), a `groq` requirement is the start-time readiness predicate
967
- * ({@link START_REQUIREMENT_VARS} — `$fields` bound, never a root).
968
- * 4. **Guard predicates** — NOT conditions. A lake mutation guard's
969
- * `predicate` is groq-js **delta-mode** GROQ over a document mutation:
970
- * `before()`/`after()`/`identity()` are dialect natives, and the wire
971
- * format binds the identifiers in {@link GUARD_PREDICATE_VARS}. None of
972
- * the condition vars exist there.
973
- */
974
1023
  /**
975
1024
  * When a condition var holds a value:
976
1025
  *
@@ -983,14 +1032,15 @@ export declare interface ConditionVar {
983
1032
  */
984
1033
  export declare type ConditionVarBinding = "always" | "caller" | "spawn";
985
1034
 
986
- /**
987
- * The maximum reader floor this writer can emit. Individual documents derive
988
- * their `minReaderModel` from the compatibility-bearing features actually
989
- * present; a document written at {@link DATA_MODEL_VERSION} may therefore
990
- * carry a lower floor. Raising this maximum is a declared, DATAMODEL.md-logged
991
- * decision that requires readers-first fleet sequencing.
992
- */
993
- declare const DATA_MODEL_MIN_READER = 4;
1035
+ /** A define-time validated `custom.<camelCaseMeaning>` value. */
1036
+ declare type CustomSemantic = `custom.${string}`;
1037
+
1038
+ declare const DECISION_SEMANTICS: readonly [
1039
+ "decision.accept",
1040
+ "decision.decline",
1041
+ ];
1042
+
1043
+ declare type DecisionSemantic = (typeof DECISION_SEMANTICS)[number];
994
1044
 
995
1045
  export declare function defineAction(action: AuthoringAction): AuthoringAction;
996
1046
 
@@ -1053,21 +1103,42 @@ export declare function defineWorkflow(
1053
1103
  * deployment's bindings via {@link resourceAliasesToMap} into the
1054
1104
  * `resourceAliases` map `deployDefinitions` expands against.
1055
1105
  *
1056
- * Validates shape only — NOT the reader-floor acknowledgement. That is a
1057
- * selected-deployment gate (`deployDefinitions`, the CLI's
1058
- * `deploymentToTarget` / `buildBatches` / `resolveContext`, and blueprint
1059
- * provision each assert the deployment they target), so a command that never
1060
- * selects a deployment loads a config with a stale or missing floor on an
1061
- * untargeted entry without failing. Authors must still acknowledge the floor
1062
- * at compile time each {@link WorkflowDeploymentInput} requires it; the
1063
- * returned {@link WorkflowConfig} is the looser parsed shape.
1106
+ * Validates shape only; reader-floor acknowledgement belongs to paths that
1107
+ * submit definitions (`deployDefinitions`, the CLI deploy and definition-diff
1108
+ * commands, and blueprint provision). Other commands may load a selected
1109
+ * deployment with a missing floor.
1110
+ *
1111
+ * Each `WorkflowDeploymentInput` carries an acknowledgement; definition-submission
1112
+ * paths compare it with the submitted definitions. The returned {@link WorkflowConfig}
1113
+ * is the looser parsed shape.
1064
1114
  */
1065
1115
  export declare function defineWorkflowConfig(
1066
1116
  config: WorkflowConfigInput,
1067
1117
  ): WorkflowConfig;
1068
1118
 
1119
+ /**
1120
+ * Declared editability of a field — the generic edit seam's gate. Default
1121
+ * (absent) is NOT editable: a field is op-only engine working memory unless the
1122
+ * modeler opens it. The stored form is `true` (editable by anyone within the
1123
+ * field's scope window) or an EDIT CONDITION — rendered-scope GROQ (`$actor`,
1124
+ * `$can`, `$attributes`, `$fields`, `$assigned`), checked like an action filter
1125
+ * to decide who-may-edit. ADVISORY like every engine gate — it disables the
1126
+ * inline field and explains; a {@link Guard} declares the intended write-lock.
1127
+ */
1069
1128
  declare type Editable = v.InferOutput<typeof StoredEditableSchema>;
1070
1129
 
1130
+ /**
1131
+ * A registered effect: `name` is its only identity (unique per definition,
1132
+ * read downstream as `$effects.<name>`) — the host app registers a handler
1133
+ * against it 1:1, and the stored definition never references code.
1134
+ * `bindings` are GROQ reads over the rendered scope, resolved to concrete
1135
+ * JSON at queue time; `input` is static config passed through verbatim.
1136
+ * `outputs` (typed {@link FieldShape}s) is a STRICT allowlist: at completion
1137
+ * an undeclared output key, or a value that doesn't fit its shape, fails the
1138
+ * completion and nothing is stored. Omitting `outputs` is an EMPTY allowlist,
1139
+ * so ANY returned output is rejected and fails the completion — the bound is
1140
+ * universal, not opt-in.
1141
+ */
1071
1142
  declare type Effect = v.InferOutput<typeof EffectSchema>;
1072
1143
 
1073
1144
  /**
@@ -1102,7 +1173,6 @@ declare const EffectSchema: v.StrictObjectSchema<
1102
1173
  v.StringSchema<undefined>,
1103
1174
  undefined
1104
1175
  >;
1105
- /** GROQ reads over the rendered scope, resolved to concrete JSON at queue time. */
1106
1176
  readonly bindings: v.OptionalSchema<
1107
1177
  v.RecordSchema<
1108
1178
  v.StringSchema<undefined>,
@@ -1116,28 +1186,10 @@ declare const EffectSchema: v.StrictObjectSchema<
1116
1186
  >,
1117
1187
  undefined
1118
1188
  >;
1119
- /** Static config, passed through to the handler verbatim. */
1120
1189
  readonly input: v.OptionalSchema<
1121
1190
  v.RecordSchema<v.StringSchema<undefined>, v.UnknownSchema, undefined>,
1122
1191
  undefined
1123
1192
  >;
1124
- /**
1125
- * The outputs this effect is allowed to produce, as typed {@link FieldShape}s
1126
- * (each `name` is an output key, read downstream as `$effects['<name>'].<key>`;
1127
- * an `array` output is an array of objects shaped by `of`).
1128
- *
1129
- * A STRICT allowlist: at completion the handler's returned `outputs` are
1130
- * validated against these shapes and an undeclared key — or a value that
1131
- * doesn't fit its shape — fails the completion (nothing is stored). Omitting
1132
- * `outputs` is an EMPTY allowlist: the effect produces nothing, so any returned
1133
- * output is rejected — the bound is universal, not opt-in.
1134
- * Why strict: outputs land on the instance document's `effectHistory`, so
1135
- * the allowlist keeps it bounded — a handler can't accidentally spread a
1136
- * whole API response
1137
- * into the instance — and the declared shapes let tooling (e.g. the simulator's
1138
- * drain UI) suggest an effect's exact output keys. Declaring outputs also
1139
- * powers the advisory deploy-time producer/consumer lint.
1140
- */
1141
1193
  readonly outputs: v.OptionalSchema<
1142
1194
  v.ArraySchema<v.GenericSchema<FieldShape>, undefined>,
1143
1195
  undefined
@@ -1150,7 +1202,10 @@ declare const EffectSchema: v.StrictObjectSchema<
1150
1202
  * The kinds a VALUE can take — scalars aligned to Sanity's names, the
1151
1203
  * reference kinds, the actor/assignee identities, and the two compositional
1152
1204
  * kinds (`object` with named `fields`, `array` of objects shaped by `of`).
1153
- * This is also the set a nested {@link FieldShape} sub-field may use.
1205
+ * This is also the set a nested {@link FieldShape} sub-field may use. Kinds
1206
+ * are bare (unique within their union); namespacing lives only on
1207
+ * engine-owned lake document `_type`s ({@link WORKFLOW_DEFINITION_TYPE}, the
1208
+ * instance type).
1154
1209
  *
1155
1210
  * Exported (module-level, not package API) for the model-surface gate's
1156
1211
  * enum-value coverage test.
@@ -1189,6 +1244,7 @@ declare type FieldBase<TEditable, TGroup> = {
1189
1244
  editable?: TEditable | undefined;
1190
1245
  };
1191
1246
 
1247
+ /** One declared field entry as authored and stored: name, value kind, and its scope's sourcing and editability. */
1192
1248
  declare type FieldEntry = FieldEntryFields<Editable, string[]>;
1193
1249
 
1194
1250
  /** Type-mirror of {@link fieldEntryFields}: a raw field entry of the given
@@ -1201,6 +1257,8 @@ declare type FieldEntryFields<TEditable, TGroup> = FieldBase<
1201
1257
  options?: ChoiceOptions | undefined;
1202
1258
  validation?: ScalarValidation | undefined;
1203
1259
  types?: string[] | undefined;
1260
+ /** Non-empty assignment eligibility constraint. User roles apply aliases; collective roles match literally. */
1261
+ roles?: string[] | undefined;
1204
1262
  fields?: FieldShape[] | undefined;
1205
1263
  of?: FieldShape[] | undefined;
1206
1264
  };
@@ -1212,6 +1270,14 @@ declare type FieldReadExpr = {
1212
1270
  path?: string | undefined;
1213
1271
  };
1214
1272
 
1273
+ /**
1274
+ * A sub-field shape used inside an `object`'s `fields` or an `array`'s `of` —
1275
+ * lighter than {@link FieldEntry}: no `initialValue`/`editable`/`required`,
1276
+ * since a sub-field's value comes from the parent. An `object` kind requires
1277
+ * non-empty `fields` and no `of`; an `array` kind requires non-empty `of` and
1278
+ * no `fields`; every other kind requires neither — enforced at parse, not
1279
+ * visible in this type.
1280
+ */
1215
1281
  declare interface FieldShape {
1216
1282
  type: FieldValueKind;
1217
1283
  name: string;
@@ -1219,10 +1285,19 @@ declare interface FieldShape {
1219
1285
  description?: string | undefined;
1220
1286
  options?: ChoiceOptions | undefined;
1221
1287
  validation?: ScalarValidation | undefined;
1288
+ /** Non-empty assignment eligibility constraint. User roles apply aliases; collective roles match literally. */
1289
+ roles?: string[] | undefined;
1222
1290
  fields?: FieldShape[] | undefined;
1223
1291
  of?: FieldShape[] | undefined;
1224
1292
  }
1225
1293
 
1294
+ /**
1295
+ * How a field seeds its `initialValue`, once at materialisation (advisory
1296
+ * after — the field stays freely editable). Absent means working memory: the
1297
+ * field starts empty and an op fills it later, spelled by omission rather
1298
+ * than an arm. Distinct from {@link ValueExpr}, an op's write payload; they
1299
+ * overlap only on the literal and field-read arms.
1300
+ */
1226
1301
  declare type FieldSource = FieldSourceInternal;
1227
1302
 
1228
1303
  declare type FieldSourceInternal =
@@ -1265,12 +1340,22 @@ export declare function groq(
1265
1340
  ...values: unknown[]
1266
1341
  ): string;
1267
1342
 
1343
+ /** A named readiness condition. Activities accept only `'groq'`; workflow
1344
+ * `start.requirements` also accepts `'singleSubject'` — see {@link StartRequirement}. */
1268
1345
  declare type GroqRequirement = RequirementBase & {
1269
1346
  type: "groq";
1270
1347
  query: string;
1271
1348
  };
1272
1349
 
1273
- /** Type-mirror of {@link GroupSchema} — one declared group. */
1350
+ /**
1351
+ * A declared "what belongs together" tag: the workflow root, a stage, or an
1352
+ * activity declares named groups, and field entries, activities, and actions
1353
+ * opt in via `group`. Purely advisory — the engine stores and validates names
1354
+ * (unique per level, every reference resolves) and never acts on them; a
1355
+ * consumer decides what a group means for its medium. The same name declared
1356
+ * at several levels is intentional nesting, addressed per level; the engine
1357
+ * never merges them.
1358
+ */
1274
1359
  declare type Group = {
1275
1360
  name: string;
1276
1361
  title?: string | undefined;
@@ -1278,6 +1363,14 @@ declare type Group = {
1278
1363
  kind?: GroupKind | undefined;
1279
1364
  };
1280
1365
 
1366
+ /**
1367
+ * Advisory classification of a declared {@link Group} by its informational
1368
+ * ROLE, never a rendering treatment: `'core'` marks content central to
1369
+ * understanding the workflow (condensed views include these first);
1370
+ * `'details'` marks depth on demand. Unset = a plain group. Consumers
1371
+ * reading a definition as data MUST treat an unknown kind as unset — growing
1372
+ * this list is an engine version bump, like every stored enum.
1373
+ */
1281
1374
  declare const GROUP_KINDS: readonly ["core", "details"];
1282
1375
 
1283
1376
  declare type GroupKind = (typeof GROUP_KINDS)[number];
@@ -1294,6 +1387,27 @@ declare type GroupKind = (typeof GROUP_KINDS)[number];
1294
1387
  */
1295
1388
  declare type GroupMembership = string | string[];
1296
1389
 
1390
+ /**
1391
+ * A lake mutation guard. A FOREIGN CONTRACT mirrored 1:1: `match`,
1392
+ * `predicate`, and `metadata` are the content lake's persisted guard-document
1393
+ * API, not engine-invented surface — the stored form keeps the lake's
1394
+ * vocabulary verbatim. The engine adds exactly two things: `name` (a
1395
+ * lake-id-segment, `^[a-z0-9][a-z0-9-]*$`, unique per definition — the lake
1396
+ * `_id` derives from `(instanceId, name)` at stage entry) and the deploy-time
1397
+ * read VALUES on `match.idRefs` / `metadata` (a typed {@link GuardRead} when
1398
+ * authoring, resolved to bare values at deploy). `match` selects mutations by
1399
+ * `types` (empty matches any), `idRefs` (field reads resolved to bare ids),
1400
+ * `idPatterns` (bare glob ids), and `actions` (at least one). `predicate` is
1401
+ * lake GROQ in a distinct delta-mode eval context (`before()`/`after()`,
1402
+ * `mutation`, `guard`, `identity()`, bare ids/fields only): strictly `true`
1403
+ * ALLOWS the mutation; anything else — false, null, an evaluation error, or
1404
+ * an omitted/empty predicate — DENIES. `metadata` is the only bridge from
1405
+ * that eval context (which cannot see `$fields`) to workflow fields, read as
1406
+ * `guard.metadata.*` and re-synced by the post-field-op guard refresh. The
1407
+ * lake does not enforce the guard document type yet: a deployed guard denies
1408
+ * optimistically engine-side, and the lake ACL is the only hard gate until
1409
+ * guard enforcement ships.
1410
+ */
1297
1411
  declare type Guard = v.InferOutput<typeof GuardSchema>;
1298
1412
 
1299
1413
  /**
@@ -1308,14 +1422,8 @@ export declare const GUARD_PREDICATE_VARS: readonly {
1308
1422
  description: string;
1309
1423
  }[];
1310
1424
 
1311
- /** Stored guards carry the printed string reads (the deploy resolver's input). */
1312
1425
  declare const GuardSchema: v.StrictObjectSchema<
1313
1426
  {
1314
- /**
1315
- * Lake-id-segment grammar (`^[a-z0-9][a-z0-9-]*$`, deploy-enforced): the
1316
- * guard's lake `_id` derives from `(instanceId, name)` at stage entry.
1317
- * Unique per definition.
1318
- */
1319
1427
  name: v.SchemaWithPipe<
1320
1428
  readonly [
1321
1429
  v.StringSchema<undefined>,
@@ -1326,7 +1434,6 @@ declare const GuardSchema: v.StrictObjectSchema<
1326
1434
  description: v.OptionalSchema<v.StringSchema<undefined>, undefined>;
1327
1435
  match: v.StrictObjectSchema<
1328
1436
  {
1329
- /** Subject `_type`(s); empty matches any type. */
1330
1437
  types: v.OptionalSchema<
1331
1438
  v.ArraySchema<
1332
1439
  v.SchemaWithPipe<
@@ -1339,7 +1446,6 @@ declare const GuardSchema: v.StrictObjectSchema<
1339
1446
  >,
1340
1447
  undefined
1341
1448
  >;
1342
- /** Target docs as field reads (or the instance itself), resolved at deploy to bare ids + the resource. */
1343
1449
  idRefs: v.OptionalSchema<
1344
1450
  v.ArraySchema<
1345
1451
  v.SchemaWithPipe<
@@ -1352,7 +1458,6 @@ declare const GuardSchema: v.StrictObjectSchema<
1352
1458
  >,
1353
1459
  undefined
1354
1460
  >;
1355
- /** Glob id patterns (bare, resource-local). */
1356
1461
  idPatterns: v.OptionalSchema<
1357
1462
  v.ArraySchema<
1358
1463
  v.SchemaWithPipe<
@@ -1384,22 +1489,7 @@ declare const GuardSchema: v.StrictObjectSchema<
1384
1489
  },
1385
1490
  undefined
1386
1491
  >;
1387
- /**
1388
- * Lake GROQ predicate — a distinct eval context: delta-mode GROQ
1389
- * reading the `before()`/`after()` natives, `mutation`, `guard`, and
1390
- * `identity()`. Bare ids/fields only. Polarity: a result of strictly
1391
- * `true` ALLOWS the matched mutation; anything else (false, null, an
1392
- * evaluation error) DENIES. Omitted or empty means UNCONDITIONAL DENY.
1393
- */
1394
1492
  predicate: v.OptionalSchema<v.StringSchema<undefined>, undefined>;
1395
- /**
1396
- * Projected workflow fields the predicate reads as `guard.metadata.*` —
1397
- * the only bridge from the lake eval context (which cannot see `$fields`)
1398
- * to workflow fields. Each value is a deploy-time read — a typed
1399
- * {@link GuardRead} when authoring, the printed string spelling once
1400
- * stored — resolved into a bare value at deploy and re-synced by the
1401
- * post-field-op guard refresh.
1402
- */
1403
1493
  metadata: v.OptionalSchema<
1404
1494
  v.RecordSchema<
1405
1495
  v.SchemaWithPipe<
@@ -1427,17 +1517,22 @@ declare type LiteralExpr = {
1427
1517
  value: unknown;
1428
1518
  };
1429
1519
 
1430
- declare type ManualTarget = v.InferOutput<typeof StoredManualTargetSchema>;
1431
-
1432
1520
  /**
1433
- * `notes`an append-only audit/comment log. Sugar over `array of object
1434
- * { body, actor, at }` (the `actor`/`at` sub-fields match the `audit` op's
1435
- * stamp names, so it pairs with it). Never a stored kind.
1521
+ * Off-system deep-link target render-only metadata whose presence marks an
1522
+ * activity as off-system (BPMN Manual Task). Either a static URL, or a field
1523
+ * reference whose resolved document the consumer opens; deploy checks the
1524
+ * `field` variant points at a doc-valued entry.
1436
1525
  */
1526
+ declare type ManualTarget = v.InferOutput<typeof StoredManualTargetSchema>;
1527
+
1528
+ /** An append-only audit/comment log: sugar over `array of object {body, actor, at}` — the `actor`/`at`
1529
+ * names match the `audit` op's stamp fields, so it pairs with it. Never a stored kind. */
1437
1530
  declare type NotesField = FieldBase<AuthoringEditable, GroupMembership> & {
1438
1531
  type: "notes";
1439
1532
  };
1440
1533
 
1534
+ /** A `field.updateWhere` / `field.removeWhere` op's `where` selects rows to
1535
+ * mutate with rendered-scope GROQ (`$row`, `$params` bound) — row selection, not a gate; an unevaluable row never matches. */
1441
1536
  declare type Op = v.InferOutput<typeof StoredOpSchema>;
1442
1537
 
1443
1538
  declare type RequirementBase = {
@@ -1454,35 +1549,15 @@ declare type RequirementBase = {
1454
1549
  */
1455
1550
  export declare const RESERVED_CONDITION_VARS: readonly string[];
1456
1551
 
1457
- declare type RoleAliases = v.InferOutput<typeof RoleAliasesSchema>;
1458
-
1459
1552
  /**
1460
- * Role aliasing the "can be fulfilled by" map, an authoring convenience.
1461
- * A `roles` gate (or an `assignees` entry) names the role the author writes;
1462
- * but the SAME capability is often carried by different role names depending
1463
- * on how a given project deploys its Content Lake roles, and several roles may
1464
- * legitimately do the job. Rather than enumerate every equivalent role inline
1465
- * in each gate — or fork the definition per deployment — declare once here
1466
- * which other roles also fulfill it.
1467
- *
1468
- * Each key is a role a gate/assignee names; its value lists the roles that
1469
- * also satisfy it. The reserved key `"*"` lists roles that fulfill ANY gate
1470
- * (e.g. `"*": ["administrator"]` — whatever this deployment's broad role is).
1471
- * `"*"` is the spelling authors write; it is rewritten to a lake-safe stored
1472
- * key before the definition is persisted, since the Content Lake rejects `"*"`
1473
- * as a document attribute name (see {@link normalizeRoleAliases}).
1474
- *
1475
- * Applied as an in-place expansion of the REQUIRED side, never the actor's
1476
- * roles: the `roles` gate bakes the expanded membership into its desugared
1477
- * GROQ at define time; `$assigned` expands the assignee's role at match time
1478
- * (see {@link expandRequiredRoles}). Carried into the stored definition for
1479
- * that runtime half.
1480
- *
1481
- * Advisory, like every engine gate — an alias only predicts what the
1482
- * deployment's Content Lake ACLs already allow, it never grants access. An
1483
- * alias the lake won't honor makes the gate predict "allowed" for a write the
1484
- * lake then rejects, so keep it true to what's actually deployed.
1553
+ * Roles that may fulfil each authored role. Aliases widen action gates,
1554
+ * `$assigned`, and assignment-field user eligibility by expanding the required
1555
+ * side; they never alter an actor's roles. Collective role assignees remain
1556
+ * literal ownership values and are not widened by this map. The authored `"*"`
1557
+ * key lists universal fulfillers and is normalized before persistence.
1485
1558
  */
1559
+ declare type RoleAliases = v.InferOutput<typeof RoleAliasesSchema>;
1560
+
1486
1561
  declare const RoleAliasesSchema: v.RecordSchema<
1487
1562
  v.SchemaWithPipe<
1488
1563
  readonly [
@@ -1518,10 +1593,32 @@ declare interface ScalarValidation {
1518
1593
  max?: number | undefined;
1519
1594
  }
1520
1595
 
1596
+ declare type Semantic = SignalSemantic | CustomSemantic;
1597
+
1598
+ declare const SIGNAL_SEMANTICS: readonly [
1599
+ "signal.positive",
1600
+ "signal.caution",
1601
+ "signal.critical",
1602
+ ];
1603
+
1604
+ declare type SignalSemantic = (typeof SIGNAL_SEMANTICS)[number];
1605
+
1521
1606
  declare type SingleSubjectRequirement = RequirementBase & {
1522
1607
  type: "singleSubject";
1523
1608
  };
1524
1609
 
1610
+ /**
1611
+ * A pure container — name, fields, guards, activities, transitions, no
1612
+ * behaviour of its own. Activities own enter, transitions own exit and
1613
+ * arrival; a stage with no transitions IS terminal (structural, nothing to
1614
+ * declare or mis-declare). `guards` are lake mutation guards active while
1615
+ * the stage holds, each compiling to a persisted guard document deployed on
1616
+ * stage entry and retracted on exit. `editable` is a tighten-only override
1617
+ * for the time the stage holds, keyed by an in-scope field name: the field's
1618
+ * own `editable` is the ceiling, ANDed with the stage value at runtime, so an
1619
+ * override can only NARROW — never open a field the baseline left closed. An
1620
+ * unlisted field inherits its baseline.
1621
+ */
1525
1622
  declare type Stage = StageFields<
1526
1623
  FieldEntry,
1527
1624
  Activity,
@@ -1533,6 +1630,7 @@ declare type Stage = StageFields<
1533
1630
  /** Type-mirror of {@link stageFields}, parameterised over field/activity/transition/guard/editable. */
1534
1631
  declare type StageFields<TField, TActivity, TTransition, TGuard, TEditable> = {
1535
1632
  name: string;
1633
+ semantics?: Semantic[] | undefined;
1536
1634
  title?: string | undefined;
1537
1635
  description?: string | undefined;
1538
1636
  groups?: Group[] | undefined;
@@ -1545,13 +1643,23 @@ declare type StageFields<TField, TActivity, TTransition, TGuard, TEditable> = {
1545
1643
 
1546
1644
  declare const START_KINDS: readonly ["interactive", "autonomous"];
1547
1645
 
1646
+ /**
1647
+ * How standalone runs of this workflow begin. `filter` is a READ-SIDE
1648
+ * visibility predicate — "should a start surface offer this workflow for
1649
+ * this document?" — evaluated by `definitionsForDocument`/applicability in
1650
+ * the browse-time-pure start-filter context (`$tag`/`$definition`/`$now`
1651
+ * bound; `$fields` cannot exist before inputs do, so a `$fields` read here
1652
+ * is deploy-rejected). It is NOT a `startInstance` gate; the verb never
1653
+ * reads it. `requirements` are named readiness checks evaluated in author
1654
+ * order in the start-time context (GROQ nodes add `$fields`; `singleSubject`
1655
+ * is the one-in-flight-run-per-subject rule) — every node must pass before
1656
+ * `startInstance` commits. Both are advisory like every engine-side check;
1657
+ * the Content Lake remains the only enforcement point.
1658
+ */
1548
1659
  declare type StartBlock = StartFields & {
1549
1660
  kind: StartKind;
1550
1661
  };
1551
1662
 
1552
- /** Type-mirror of {@link startFields}: how standalone runs of this workflow
1553
- * begin. Stored requires `kind` (desugar fills the `'interactive'` default);
1554
- * authoring may omit it — so each variant declares it. */
1555
1663
  declare type StartFields = {
1556
1664
  filter?: string | undefined;
1557
1665
  requirements?: StartRequirement[] | undefined;
@@ -1568,17 +1676,9 @@ declare type StartFields = {
1568
1676
  */
1569
1677
  declare type StartKind = (typeof START_KINDS)[number];
1570
1678
 
1679
+ /** Every named readiness requirement accepted by workflow `start.requirements`. */
1571
1680
  declare type StartRequirement = GroqRequirement | SingleSubjectRequirement;
1572
1681
 
1573
- /**
1574
- * Declared editability of a field — the generic edit seam's gate. Default
1575
- * (absent) is NOT editable: a field is op-only engine working memory unless the
1576
- * modeler opens it. The stored form is `true` (editable by anyone within the
1577
- * field's scope window) or an EDIT CONDITION — rendered-scope GROQ (`$actor`,
1578
- * `$can`, `$fields`, `$assigned`), checked like an action filter to decide
1579
- * who-may-edit. ADVISORY like every engine gate — it disables the inline field
1580
- * and explains; a {@link Guard} declares the intended write-lock.
1581
- */
1582
1682
  declare const StoredEditableSchema: v.UnionSchema<
1583
1683
  [
1584
1684
  v.LiteralSchema<true, undefined>,
@@ -1658,6 +1758,28 @@ declare const StoredOpSchema: v.VariantSchema<
1658
1758
  },
1659
1759
  undefined
1660
1760
  >,
1761
+ v.StrictObjectSchema<
1762
+ {
1763
+ readonly type: v.LiteralSchema<"field.setIfMissing", undefined>;
1764
+ readonly target: v.StrictObjectSchema<
1765
+ {
1766
+ readonly scope: v.PicklistSchema<
1767
+ readonly ["workflow", "stage", "activity"],
1768
+ string
1769
+ >;
1770
+ readonly field: v.SchemaWithPipe<
1771
+ readonly [
1772
+ v.StringSchema<undefined>,
1773
+ v.MinLengthAction<string, 1, "must be a non-empty string">,
1774
+ ]
1775
+ >;
1776
+ },
1777
+ undefined
1778
+ >;
1779
+ readonly value: v.GenericSchema<ValueExprInternal>;
1780
+ },
1781
+ undefined
1782
+ >,
1661
1783
  v.StrictObjectSchema<
1662
1784
  {
1663
1785
  readonly type: v.LiteralSchema<"field.unset", undefined>;
@@ -1701,6 +1823,56 @@ declare const StoredOpSchema: v.VariantSchema<
1701
1823
  },
1702
1824
  undefined
1703
1825
  >,
1826
+ v.StrictObjectSchema<
1827
+ {
1828
+ readonly type: v.LiteralSchema<"field.inc", undefined>;
1829
+ readonly target: v.StrictObjectSchema<
1830
+ {
1831
+ readonly scope: v.PicklistSchema<
1832
+ readonly ["workflow", "stage", "activity"],
1833
+ string
1834
+ >;
1835
+ readonly field: v.SchemaWithPipe<
1836
+ readonly [
1837
+ v.StringSchema<undefined>,
1838
+ v.MinLengthAction<string, 1, "must be a non-empty string">,
1839
+ ]
1840
+ >;
1841
+ },
1842
+ undefined
1843
+ >;
1844
+ readonly value: v.OptionalSchema<
1845
+ v.GenericSchema<ValueExprInternal>,
1846
+ undefined
1847
+ >;
1848
+ },
1849
+ undefined
1850
+ >,
1851
+ v.StrictObjectSchema<
1852
+ {
1853
+ readonly type: v.LiteralSchema<"field.dec", undefined>;
1854
+ readonly target: v.StrictObjectSchema<
1855
+ {
1856
+ readonly scope: v.PicklistSchema<
1857
+ readonly ["workflow", "stage", "activity"],
1858
+ string
1859
+ >;
1860
+ readonly field: v.SchemaWithPipe<
1861
+ readonly [
1862
+ v.StringSchema<undefined>,
1863
+ v.MinLengthAction<string, 1, "must be a non-empty string">,
1864
+ ]
1865
+ >;
1866
+ },
1867
+ undefined
1868
+ >;
1869
+ readonly value: v.OptionalSchema<
1870
+ v.GenericSchema<ValueExprInternal>,
1871
+ undefined
1872
+ >;
1873
+ },
1874
+ undefined
1875
+ >,
1704
1876
  v.StrictObjectSchema<
1705
1877
  {
1706
1878
  readonly type: v.LiteralSchema<"field.updateWhere", undefined>;
@@ -1776,18 +1948,23 @@ declare const StoredOpSchema: v.VariantSchema<
1776
1948
  undefined
1777
1949
  >;
1778
1950
 
1951
+ /**
1952
+ * Fan-out declared as an action's `spawn`, read back as `$subworkflows`.
1953
+ * `forEach` is GROQ producing one row per subworkflow (bound as `$row`); each
1954
+ * row needs an identity the engine can adopt on re-entry (`_key` ?? `_id` ??
1955
+ * GDR `id`, or the value itself for a scalar row) or the spawn fails.
1956
+ * `definition` resolves by stable `name`, ordered `version desc` unless
1957
+ * pinned. `with` seeds each child's initial fields; `context` delivers extra
1958
+ * parent-scope values into the child's `$context`. `onExit` governs only
1959
+ * still-live children when the cohort's scope stops applying: `'detach'`
1960
+ * (default) lets them run to completion, `'abort'` kills them recursively —
1961
+ * always an authored choice, never automatic. Whether the PARENT may move at
1962
+ * all is a separate gate over `$subworkflows`.
1963
+ */
1779
1964
  declare type Subworkflows = v.InferOutput<typeof SubworkflowsSchema>;
1780
1965
 
1781
1966
  declare const SubworkflowsSchema: v.StrictObjectSchema<
1782
1967
  {
1783
- /**
1784
- * GROQ producing one row per subworkflow; each row binds as `$row`. Every
1785
- * row must carry an identity the engine can adopt against on re-entry:
1786
- * `_key` ?? `_id` ?? GDR `id` for object rows (a GDR value — `{id, type}`
1787
- * with a GDR-URI `id`, the rows a `doc.refs` field stores — keys on its
1788
- * `id`; mint a `_key` in the projection for synthetic rows), the value
1789
- * itself for scalar rows. A row without an identity fails the spawn.
1790
- */
1791
1968
  readonly forEach: v.SchemaWithPipe<
1792
1969
  readonly [
1793
1970
  v.StringSchema<undefined>,
@@ -1821,7 +1998,6 @@ declare const SubworkflowsSchema: v.StrictObjectSchema<
1821
1998
  },
1822
1999
  undefined
1823
2000
  >;
1824
- /** Initial fields for each subworkflow — entry name → GROQ over `$row` + the parent scope. */
1825
2001
  readonly with: v.OptionalSchema<
1826
2002
  v.RecordSchema<
1827
2003
  v.SchemaWithPipe<
@@ -1840,11 +2016,6 @@ declare const SubworkflowsSchema: v.StrictObjectSchema<
1840
2016
  >,
1841
2017
  undefined
1842
2018
  >;
1843
- /**
1844
- * Extra values evaluated in the parent's rendered scope at spawn time and
1845
- * delivered into each subworkflow's `$context` bag — the parent→child
1846
- * handoff.
1847
- */
1848
2019
  readonly context: v.OptionalSchema<
1849
2020
  v.RecordSchema<
1850
2021
  v.SchemaWithPipe<
@@ -1863,16 +2034,6 @@ declare const SubworkflowsSchema: v.StrictObjectSchema<
1863
2034
  >,
1864
2035
  undefined
1865
2036
  >;
1866
- /**
1867
- * What happens to still-live children when their cohort's scope stops
1868
- * applying — the spawning stage exits, or a re-fire's `forEach` no longer
1869
- * discovers their row. `'detach'` (the default) lets them run to
1870
- * completion outside the gate; `'abort'` kills them (recursively). The
1871
- * engine never destroys in-flight work implicitly — `'abort'` is always
1872
- * an authored choice. Note this governs only the CHILDREN's fate; whether
1873
- * the parent may move at all is what gates (conditions over
1874
- * `$subworkflows`) decide.
1875
- */
1876
2037
  readonly onExit: v.OptionalSchema<
1877
2038
  v.PicklistSchema<readonly ["detach", "abort"], string>,
1878
2039
  undefined
@@ -1881,6 +2042,14 @@ declare const SubworkflowsSchema: v.StrictObjectSchema<
1881
2042
  undefined
1882
2043
  >;
1883
2044
 
2045
+ /**
2046
+ * The statuses an activity can be resolved INTO — what `status.set` accepts.
2047
+ * A health axis, not a decision axis: a routine decision (decline, send back,
2048
+ * hold) resolves `done` and routes via a field write; `failed` means the work
2049
+ * genuinely could not complete. Only `done`/`skipped` satisfy
2050
+ * `$allActivitiesDone` — a `failed` activity blocks it permanently, surfacing
2051
+ * via `$anyActivityFailed`.
2052
+ */
1884
2053
  declare const TERMINAL_ACTIVITY_STATUSES: readonly [
1885
2054
  "done",
1886
2055
  "skipped",
@@ -1890,19 +2059,22 @@ declare const TERMINAL_ACTIVITY_STATUSES: readonly [
1890
2059
  declare type TerminalActivityStatus =
1891
2060
  (typeof TERMINAL_ACTIVITY_STATUSES)[number];
1892
2061
 
1893
- /**
1894
- * `todoList` ad-hoc, status-tracked work items. Sugar over `array of object
1895
- * { label, status, assignee?, dueDate? }`; a plain checklist is this used with
1896
- * `{label, status}` only (open ↔ done). Never a stored kind.
1897
- *
1898
- * The `dueDate` column is a `date` NAMED `dueDate`, not the {@link
1899
- * FieldValueMap.dueDate} kind — that kind reserves one deadline slot per level,
1900
- * and a repeating row has nothing to reserve.
1901
- */
2062
+ /** Ad-hoc, status-tracked work items: sugar over `array of object {label, status, assignee?, dueDate?}`; a plain checklist is that with `{label, status}` alone.
2063
+ * Its `dueDate` is a `date` column named `dueDate`, not the elevated `dueDate` kind, which reserves one deadline slot per level. Never a stored kind. */
1902
2064
  declare type TodoListField = FieldBase<AuthoringEditable, GroupMembership> & {
1903
2065
  type: "todoList";
1904
2066
  };
1905
2067
 
2068
+ /**
2069
+ * A pure edge — `{name, when, to}` plus presentation, no ops or effects
2070
+ * (structure never does; only actions do). Every transition is evaluated on
2071
+ * every commit and cascade; the first truthy `when` in declaration order
2072
+ * fires. No action coupling: a routing difference is written into fields by
2073
+ * an action and read by the trigger — arrival work is a `when: 'true'`
2074
+ * action in the destination stage, and exit work is an action in the source
2075
+ * stage whose `when` repeats this transition's condition (the hop rule
2076
+ * guarantees it commits before the move).
2077
+ */
1906
2078
  declare type Transition = TransitionFields & {
1907
2079
  when: string;
1908
2080
  };
@@ -1942,6 +2114,16 @@ declare type ValueExprInternal =
1942
2114
 
1943
2115
  declare const WORKFLOW_LIFECYCLES: readonly ["standalone", "child"];
1944
2116
 
2117
+ /**
2118
+ * `deployments` names must be unique (the selector deployment-targeted
2119
+ * commands resolve by), and each `(workflowResource, tag)` pair must be
2120
+ * unique — that pair is the storage partition, so two deployments sharing
2121
+ * both would fight over definition versions. `telemetry`, when set, replaces
2122
+ * the CLI's built-in Sanity-intake shell entirely: every event flows to this
2123
+ * logger unconditionally (CI and `DO_NOT_TRACK` included), and consent,
2124
+ * environment suppression, and transport become this implementation's
2125
+ * business.
2126
+ */
1945
2127
  declare type WorkflowConfig = v.InferOutput<typeof WorkflowConfigSchema>;
1946
2128
 
1947
2129
  /**
@@ -2216,6 +2398,7 @@ declare const WorkflowConfigSchema: v.ObjectSchema<
2216
2398
  v.CustomSchema<
2217
2399
  {
2218
2400
  name: string;
2401
+ semantics?: Semantic[] | undefined;
2219
2402
  title: string;
2220
2403
  description?: string | undefined;
2221
2404
  groups?: Group[] | undefined;
@@ -2234,6 +2417,7 @@ declare const WorkflowConfigSchema: v.ObjectSchema<
2234
2417
  v.MinLengthAction<
2235
2418
  {
2236
2419
  name: string;
2420
+ semantics?: Semantic[] | undefined;
2237
2421
  title: string;
2238
2422
  description?: string | undefined;
2239
2423
  groups?: Group[] | undefined;
@@ -2301,6 +2485,7 @@ declare const WorkflowConfigSchema: v.ObjectSchema<
2301
2485
  | undefined;
2302
2486
  definitions: {
2303
2487
  name: string;
2488
+ semantics?: Semantic[] | undefined;
2304
2489
  title: string;
2305
2490
  description?: string | undefined;
2306
2491
  groups?: Group[] | undefined;
@@ -2362,6 +2547,7 @@ declare const WorkflowConfigSchema: v.ObjectSchema<
2362
2547
  | undefined;
2363
2548
  definitions: {
2364
2549
  name: string;
2550
+ semantics?: Semantic[] | undefined;
2365
2551
  title: string;
2366
2552
  description?: string | undefined;
2367
2553
  groups?: Group[] | undefined;
@@ -2421,6 +2607,7 @@ declare const WorkflowConfigSchema: v.ObjectSchema<
2421
2607
  | undefined;
2422
2608
  definitions: {
2423
2609
  name: string;
2610
+ semantics?: Semantic[] | undefined;
2424
2611
  title: string;
2425
2612
  description?: string | undefined;
2426
2613
  groups?: Group[] | undefined;
@@ -2482,6 +2669,7 @@ declare const WorkflowConfigSchema: v.ObjectSchema<
2482
2669
  | undefined;
2483
2670
  definitions: {
2484
2671
  name: string;
2672
+ semantics?: Semantic[] | undefined;
2485
2673
  title: string;
2486
2674
  description?: string | undefined;
2487
2675
  groups?: Group[] | undefined;
@@ -2541,6 +2729,7 @@ declare const WorkflowConfigSchema: v.ObjectSchema<
2541
2729
  | undefined;
2542
2730
  definitions: {
2543
2731
  name: string;
2732
+ semantics?: Semantic[] | undefined;
2544
2733
  title: string;
2545
2734
  description?: string | undefined;
2546
2735
  groups?: Group[] | undefined;
@@ -2558,14 +2747,6 @@ declare const WorkflowConfigSchema: v.ObjectSchema<
2558
2747
  >,
2559
2748
  ]
2560
2749
  >;
2561
- /**
2562
- * Custom telemetry destination for the CLI. When set, the CLI's built-in
2563
- * Sanity-intake shell is not constructed and none of its policy applies:
2564
- * every event — the command trace and the engine vocabulary — flows to
2565
- * this logger unconditionally (CI and `DO_NOT_TRACK` environments
2566
- * included). Consent, environment suppression, transport, and destination
2567
- * are wholly this implementation's business.
2568
- */
2569
2750
  readonly telemetry: v.OptionalSchema<
2570
2751
  v.CustomSchema<
2571
2752
  WorkflowTelemetryLogger,
@@ -2577,6 +2758,21 @@ declare const WorkflowConfigSchema: v.ObjectSchema<
2577
2758
  undefined
2578
2759
  >;
2579
2760
 
2761
+ /**
2762
+ * `name` is a lake-id-segment (`^[a-z0-9][a-z0-9-]*$`) that interpolates into
2763
+ * every deployed document id (`<tag>.<name>.v<version>`) — stable identity
2764
+ * that instances pin to and subworkflows resolve by. `lifecycle: 'child'`
2765
+ * marks a spawn-only definition, instantiated by a parent via an action's
2766
+ * `spawn`, never started cold from a picker (omitted ⇒ `'standalone'`,
2767
+ * startable); advisory only — consumers filter start pickers on it (see
2768
+ * {@link isStartableDefinition}), the engine does not itself refuse a
2769
+ * `startInstance` on a `'child'` definition. `start` is meaningless
2770
+ * (deploy-rejected) on a spawn-only definition; omitted, it means
2771
+ * interactive semantics with no predicates. `predicates` are nullary named
2772
+ * conditions — each `name: groq` entry is pre-evaluated and bound as the
2773
+ * boolean `$name` var; redefining a built-in var is a deploy error, never a
2774
+ * silent shadow.
2775
+ */
2580
2776
  declare type WorkflowDefinition = v.InferOutput<
2581
2777
  typeof WorkflowDefinitionSchema
2582
2778
  >;
@@ -2586,48 +2782,43 @@ declare type WorkflowDefinition = v.InferOutput<
2586
2782
  * every reference scope resolved. Cross-field invariants (unique names,
2587
2783
  * transition targets, effect-name uniqueness, predicate shadowing) are
2588
2784
  * checked by `checkWorkflowInvariants` after desugar — see `defineWorkflow`.
2785
+ * Carries NO `version`: a definition's version and content fingerprint are
2786
+ * stamped onto the deployed document at deploy time, derived from the
2787
+ * content itself, so redeploying identical content is a no-op and any
2788
+ * change mints the next version.
2589
2789
  *
2590
- * Carries NO `version` the author never writes one. A definition's version
2591
- * (and its content fingerprint) are stamped onto the deployed *document* at
2592
- * deploy time, derived from the content itself; see `DeployedDefinition` and
2593
- * `planDefinitionDeploy` in `api/deploy.ts`. The author's content is the sole
2594
- * source of identity: redeploying identical content is a no-op, any change
2595
- * mints the next version.
2790
+ * Exported (module-level, not package API) for the model-surface gate's
2791
+ * coverage test and for `parseStoredDefinition` the boundary parse for a
2792
+ * definition that did not come out of `defineWorkflow` in-process; trusted
2793
+ * in-process desugar output is never re-parsed.
2596
2794
  */
2597
2795
  declare const WorkflowDefinitionSchema: v.GenericSchema<
2598
2796
  WorkflowFields<FieldEntry, Stage, StartBlock>
2599
2797
  >;
2600
2798
 
2601
2799
  /** One deployment as loaded from a config: the floor is optional/unverified so
2602
- * a command that never selects a deployment can hold a stale or missing
2603
- * acknowledgement. Deployment-scoped paths assert before they act; authors
2604
- * write {@link WorkflowDeploymentInput}. */
2800
+ * commands that do not submit definitions can hold a missing acknowledgement.
2801
+ * Definition-submission paths compare it with their selected definitions; authors write
2802
+ * {@link WorkflowDeploymentInput}. */
2605
2803
  declare type WorkflowDeployment = WorkflowConfig["deployments"][number];
2606
2804
 
2607
2805
  /**
2608
- * What an author writes for one deployment: the current reader floor as the
2609
- * reviewed literal. Compile-time only omitting it or setting a wrong value
2610
- * is a type error in the editor. Runtime parse still tolerates a stale or
2611
- * missing floor on {@link WorkflowDeployment} so commands that never select a
2612
- * deployment still run; deployment-scoped paths assert the selected
2613
- * deployment (instance-id commands do not).
2806
+ * What an author writes for one deployment: the highest reader model verified
2807
+ * across runtimes sharing its workflow resource. Runtime validation compares
2808
+ * it with the submitted definitions, so a dependency upgrade alone does not
2809
+ * require changing the literal.
2614
2810
  */
2615
2811
  declare type WorkflowDeploymentInput = Omit<
2616
2812
  WorkflowDeployment,
2617
2813
  "expectedMinReaderModel"
2618
2814
  > & {
2619
- expectedMinReaderModel: typeof DATA_MODEL_MIN_READER;
2815
+ expectedMinReaderModel: number;
2620
2816
  };
2621
2817
 
2622
2818
  /** Type-mirror of {@link workflowFields}, parameterised over field/stage/start. */
2623
2819
  declare type WorkflowFields<TField, TStage, TStart> = {
2624
- /**
2625
- * Lake-id-segment grammar (`^[a-z0-9][a-z0-9-]*$`, deploy-enforced): the
2626
- * name interpolates into every deployed document id
2627
- * (`<tag>.<name>.v<version>`). Stable identity — instances pin to it,
2628
- * subworkflows resolve by it.
2629
- */
2630
2820
  name: string;
2821
+ semantics?: Semantic[] | undefined;
2631
2822
  title: string;
2632
2823
  description?: string | undefined;
2633
2824
  groups?: Group[] | undefined;