@sanity/workflow-engine 0.17.0 → 0.19.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.d.cts CHANGED
@@ -40,17 +40,15 @@ export declare function abortReason(
40
40
  ): string | undefined;
41
41
 
42
42
  /**
43
- * The structured half of applicability: does a required subject entry
44
- * ({@link isSubjectEntry} — `doc.ref` / `doc.refs`, workflow scope) accept
45
- * `documentType`? Name-blind and EXISTENTIAL: ANY required ref entry counts
46
- * a multi-input definition (say, contract + counterparty) surfaces from
47
- * either document's picker, and the start dialog collects the remaining
48
- * required entries (their fail-hard validation backstops). An entry without
49
- * `types` accepts any type; a definition with NO required ref entry takes no
50
- * subject and never matches. Cheap and indexable — no GROQ evaluation — so a
51
- * consumer can pre-filter before loading document content. (`required` is
52
- * pinned to caller-filled `input` entries by a deploy invariant, so it alone
53
- * identifies the handoff.)
43
+ * The structured half of applicability: does the definition's subject entry
44
+ * ({@link isSubjectEntry} — the `subject` kind, workflow scope, at most one
45
+ * by deploy invariant) accept `documentType`? The kind is the discriminator,
46
+ * so a definition surfaces from its SUBJECT's document picker and nowhere
47
+ * else; the start dialog collects the remaining required entries (their
48
+ * fail-hard validation backstops). A subject without `types` accepts any
49
+ * type; a definition with NO subject entry takes no subject and never
50
+ * matches. Cheap and indexable — no GROQ evaluation — so a consumer can
51
+ * pre-filter before loading document content.
54
52
  */
55
53
  export declare function acceptsDocumentType(
56
54
  definition: Pick<ApplicabilitySource, "fields">,
@@ -83,6 +81,11 @@ export declare type Action = ActionFields<Op, string[]> & {
83
81
  roles?: string[] | undefined;
84
82
  };
85
83
 
84
+ export declare const ACTION_SEMANTICS: readonly [
85
+ "decision.accept",
86
+ "decision.decline",
87
+ ];
88
+
86
89
  /**
87
90
  * The engine's per-reason detail fragment — the same wording
88
91
  * {@link ActionDisabledError} embeds in its message. Exported so a dev-facing
@@ -124,6 +127,8 @@ export declare type ActionDisabledReason = Exclude<
124
127
 
125
128
  export declare interface ActionEvaluation {
126
129
  action: Action;
130
+ /** The action's advisory workflow meaning, unchanged from its definition. */
131
+ semantics?: ActionSemantic[] | undefined;
127
132
  allowed: boolean;
128
133
  /**
129
134
  * The action is cascade-fired (`when`): the engine fires it on truth, it
@@ -135,6 +140,19 @@ export declare interface ActionEvaluation {
135
140
  triggered?: true;
136
141
  /** Present iff `allowed === false`. The first failing gate wins. */
137
142
  disabledReason?: DisabledReason;
143
+ /**
144
+ * What firing this action would do to the flow RIGHT NOW — the fire
145
+ * replayed in memory on the engine's own machinery (ops, the triggered
146
+ * fixpoint, transition selection) against this projection's state, and
147
+ * conditional on the commit landing (rejectability is `allowed` /
148
+ * `disabledReason`'s story). Omitted when the consequence depends on
149
+ * inputs the projection doesn't hold — caller params, a spawn's
150
+ * dataset-driven fan-out, a terminal instance, a stage visit whose
151
+ * entries have diverged from the pinned definition — and on cascade-fired
152
+ * actions, which are never a caller's to fire. Advisory like every
153
+ * derived verdict: a placement/phrasing hint, never a gate.
154
+ */
155
+ firing?: FiringConsequence;
138
156
  /** Derived state of the action's `filter` gate — why it holds or fails,
139
157
  * atom by atom. Present iff the action declares a filter. */
140
158
  insight?: ConditionInsight;
@@ -147,6 +165,7 @@ export declare interface ActionEvaluation {
147
165
  * group-membership grammars. */
148
166
  declare type ActionFields<TOp, TGroup> = {
149
167
  name: string;
168
+ semantics?: ActionSemantic[] | undefined;
150
169
  title?: string | undefined;
151
170
  description?: string | undefined;
152
171
  group?: TGroup | undefined;
@@ -168,36 +187,131 @@ export declare type ActionParam = v.InferOutput<typeof ActionParamSchema>;
168
187
  * effects: missing required params → ActionParamsInvalidError, action
169
188
  * does not commit. Resolved values feed `ValueExpr.param` lookups.
170
189
  */
171
- declare const ActionParamSchema: v.StrictObjectSchema<
172
- {
173
- readonly type: v.PicklistSchema<
174
- readonly [
175
- "string",
176
- "number",
177
- "boolean",
178
- "url",
179
- "dateTime",
180
- "actor",
181
- "doc.ref",
182
- "doc.refs",
183
- "json",
184
- ],
185
- `Invalid option: expected one of ${string}`
186
- >;
187
- readonly name: v.SchemaWithPipe<
188
- readonly [
189
- v.StringSchema<undefined>,
190
- v.MinLengthAction<string, 1, "must be a non-empty string">,
191
- ]
192
- >;
193
- readonly title: v.OptionalSchema<v.StringSchema<undefined>, undefined>;
194
- readonly description: v.OptionalSchema<
195
- v.StringSchema<undefined>,
190
+ declare const ActionParamSchema: v.SchemaWithPipe<
191
+ readonly [
192
+ v.StrictObjectSchema<
193
+ {
194
+ readonly type: v.PicklistSchema<
195
+ readonly [
196
+ "string",
197
+ "number",
198
+ "boolean",
199
+ "url",
200
+ "dateTime",
201
+ "actor",
202
+ "doc.ref",
203
+ "doc.refs",
204
+ "json",
205
+ ],
206
+ `Invalid option: expected one of ${string}`
207
+ >;
208
+ readonly name: v.SchemaWithPipe<
209
+ readonly [
210
+ v.StringSchema<undefined>,
211
+ v.MinLengthAction<string, 1, "must be a non-empty string">,
212
+ ]
213
+ >;
214
+ readonly title: v.OptionalSchema<v.StringSchema<undefined>, undefined>;
215
+ readonly description: v.OptionalSchema<
216
+ v.StringSchema<undefined>,
217
+ undefined
218
+ >;
219
+ readonly required: v.OptionalSchema<
220
+ v.BooleanSchema<undefined>,
221
+ undefined
222
+ >;
223
+ readonly options: v.OptionalSchema<
224
+ v.GenericSchema<ChoiceOptions>,
225
+ undefined
226
+ >;
227
+ readonly validation: v.OptionalSchema<
228
+ v.GenericSchema<ScalarValidation>,
229
+ undefined
230
+ >;
231
+ },
196
232
  undefined
197
- >;
198
- readonly required: v.OptionalSchema<v.BooleanSchema<undefined>, undefined>;
199
- },
200
- undefined
233
+ >,
234
+ v.CheckAction<
235
+ {
236
+ type:
237
+ | "string"
238
+ | "number"
239
+ | "boolean"
240
+ | "doc.ref"
241
+ | "doc.refs"
242
+ | "url"
243
+ | "actor"
244
+ | "dateTime"
245
+ | "json";
246
+ name: string;
247
+ title?: string | undefined;
248
+ description?: string | undefined;
249
+ required?: boolean | undefined;
250
+ options?: ChoiceOptions | undefined;
251
+ validation?: ScalarValidation | undefined;
252
+ },
253
+ (
254
+ issue: v.CheckIssue<{
255
+ type:
256
+ | "string"
257
+ | "number"
258
+ | "boolean"
259
+ | "doc.ref"
260
+ | "doc.refs"
261
+ | "url"
262
+ | "actor"
263
+ | "dateTime"
264
+ | "json";
265
+ name: string;
266
+ title?: string | undefined;
267
+ description?: string | undefined;
268
+ required?: boolean | undefined;
269
+ options?: ChoiceOptions | undefined;
270
+ validation?: ScalarValidation | undefined;
271
+ }>,
272
+ ) => string
273
+ >,
274
+ v.CheckAction<
275
+ {
276
+ type:
277
+ | "string"
278
+ | "number"
279
+ | "boolean"
280
+ | "doc.ref"
281
+ | "doc.refs"
282
+ | "url"
283
+ | "actor"
284
+ | "dateTime"
285
+ | "json";
286
+ name: string;
287
+ title?: string | undefined;
288
+ description?: string | undefined;
289
+ required?: boolean | undefined;
290
+ options?: ChoiceOptions | undefined;
291
+ validation?: ScalarValidation | undefined;
292
+ },
293
+ (
294
+ issue: v.CheckIssue<{
295
+ type:
296
+ | "string"
297
+ | "number"
298
+ | "boolean"
299
+ | "doc.ref"
300
+ | "doc.refs"
301
+ | "url"
302
+ | "actor"
303
+ | "dateTime"
304
+ | "json";
305
+ name: string;
306
+ title?: string | undefined;
307
+ description?: string | undefined;
308
+ required?: boolean | undefined;
309
+ options?: ChoiceOptions | undefined;
310
+ validation?: ScalarValidation | undefined;
311
+ }>,
312
+ ) => string
313
+ >,
314
+ ]
201
315
  >;
202
316
 
203
317
  /**
@@ -242,6 +356,8 @@ export declare function actionRendering(action: {
242
356
  | undefined;
243
357
  }): "absent" | "automation" | "button";
244
358
 
359
+ export declare type ActionSemantic = (typeof ACTION_SEMANTICS)[number];
360
+
245
361
  /** The fireable-action verdict for one action on an activity — its `allowed`
246
362
  * state, structured `disabledReason`, and declared params, tagged with the
247
363
  * owning activity. The per-action atom both projections share:
@@ -459,6 +575,26 @@ export declare const ACTOR_KINDS: readonly ["person", "agent", "system"];
459
575
 
460
576
  export declare type ActorKind = (typeof ACTOR_KINDS)[number];
461
577
 
578
+ export declare type ActorResolution<User> =
579
+ | {
580
+ readonly status: "resolved";
581
+ readonly actor: PersonActor;
582
+ readonly user: User;
583
+ }
584
+ | {
585
+ readonly status: "missing";
586
+ readonly actor: PersonActor;
587
+ }
588
+ | {
589
+ readonly status: "inaccessible";
590
+ readonly actor: PersonActor;
591
+ readonly cause?: unknown;
592
+ }
593
+ | {
594
+ readonly status: "not-person";
595
+ readonly actor: Actor;
596
+ };
597
+
462
598
  export { analyzeCondition };
463
599
 
464
600
  /** The definition surface the start contexts read — structural, so authored,
@@ -508,6 +644,11 @@ export declare function assertReadableModel<
508
644
  },
509
645
  >(doc: T): T;
510
646
 
647
+ export declare function assertReaderModelAcknowledgement(
648
+ expectedMinReaderModel: unknown,
649
+ context?: string,
650
+ ): asserts expectedMinReaderModel is typeof DATA_MODEL_MIN_READER;
651
+
511
652
  /**
512
653
  * One member of an `assignees`-kind entry's value — and the value of the
513
654
  * singular `assignee` kind. The WHO-FOR spec the inbox reverse-query and the
@@ -1355,10 +1496,10 @@ export declare interface AvailableActionsResult {
1355
1496
  /**
1356
1497
  * Type each caller-supplied name→value against the workflow's declared field
1357
1498
  * entries — the engine takes typed {@link InitialFieldValue}s, and a value's
1358
- * type IS its declared entry's kind. Only `input`-sourced entries read
1359
- * caller values (the engine silently ignores the rest), so anything else
1360
- * fails here, naming the fields that ARE settable; value validation stays
1361
- * in the engine.
1499
+ * type IS its declared entry's kind. Only `input`-sourced entries read caller
1500
+ * values, so anything else fails here, naming the fields that ARE settable.
1501
+ * The engine repeats this structural validation at its contract boundary;
1502
+ * value validation also stays there.
1362
1503
  */
1363
1504
  export declare function buildInitialFields({
1364
1505
  declared,
@@ -1422,6 +1563,17 @@ export declare interface ChildrenArgs extends InstanceRefArgs {
1422
1563
  activity?: string;
1423
1564
  }
1424
1565
 
1566
+ export declare interface ChoiceOption {
1567
+ title: string;
1568
+ value: ChoiceValue;
1569
+ }
1570
+
1571
+ export declare interface ChoiceOptions {
1572
+ list: ChoiceOption[];
1573
+ }
1574
+
1575
+ export declare type ChoiceValue = string | number;
1576
+
1425
1577
  /**
1426
1578
  * The action half of the mirrored claim pair. `field` references an
1427
1579
  * author-declared actor-valued entry (the pair's other half), resolved
@@ -1482,6 +1634,21 @@ export declare function clientConfigFromResource(res: WorkflowResource):
1482
1634
  * resolves to a client, or the router throws. */
1483
1635
  declare type ClientForGdr = (parsed: ParsedGdr) => WorkflowClient;
1484
1636
 
1637
+ /** Native project-user response returned by Sanity's project API. */
1638
+ export declare interface ClientProjectUser {
1639
+ readonly id: string;
1640
+ readonly displayName?: string;
1641
+ readonly email?: string;
1642
+ readonly imageUrl?: string | null;
1643
+ readonly [key: string]: unknown;
1644
+ }
1645
+
1646
+ /** Project-user directory for CLI, MCP, and server runtimes using the engine client. */
1647
+ export declare function clientProjectUserDirectory(
1648
+ client: WorkflowClient,
1649
+ projectId: string,
1650
+ ): ProjectUserDirectory<ClientProjectUser>;
1651
+
1485
1652
  /**
1486
1653
  * The engine's single source of "now".
1487
1654
  *
@@ -1518,6 +1685,42 @@ declare type Clocked<T> = T & {
1518
1685
  clock?: Clock;
1519
1686
  };
1520
1687
 
1688
+ declare interface CommitEffectOpsArgs extends DedupableOperationArgs {
1689
+ /** The `_key` of the pending effect being reported on. */
1690
+ effectKey: string;
1691
+ /**
1692
+ * Required here, unlike the other dedupable verbs: the engine cannot
1693
+ * assume a supplied field op is idempotent, so every mid-dispatch report
1694
+ * must be retry-safe. (The runtime check remains for untyped callers.)
1695
+ */
1696
+ idempotencyKey: string;
1697
+ /**
1698
+ * The exact-claim identity handed to the reporting dispatch. The commit
1699
+ * re-reads the instance and rejects (writing nothing) unless the entry's
1700
+ * live claim carries this token unexpired — so an expired, released, or
1701
+ * superseded handler cannot update state. A successful commit renews the
1702
+ * claim's lease.
1703
+ */
1704
+ claimToken: string;
1705
+ /**
1706
+ * Mid-dispatch field state, `field.*` ops only — validated and applied
1707
+ * exactly like completion ops (same applier, same target resolution
1708
+ * against the current open stage, workflow-/stage-scope only, never
1709
+ * `status.set`). Must be non-empty. Completion ops remain the final
1710
+ * atomic result committed when the handler returns; these are separately
1711
+ * committed and observable before it.
1712
+ */
1713
+ ops: FieldOp[];
1714
+ /** Lease duration the successful commit renews the claim to — the
1715
+ * drain's `effectLeaseMs`. Default `DEFAULT_EFFECT_LEASE_MS` (5 min). */
1716
+ leaseMs?: number;
1717
+ }
1718
+
1719
+ export declare interface CommitOpsRequest {
1720
+ ops: FieldOp[];
1721
+ idempotencyKey: string;
1722
+ }
1723
+
1521
1724
  export { ComparisonOp };
1522
1725
 
1523
1726
  /**
@@ -1595,6 +1798,20 @@ export declare function computeDiffEntries<
1595
1798
  target: DeployTarget;
1596
1799
  }): Promise<DiffEntry[]>;
1597
1800
 
1801
+ /** {@link ConcurrentCompleteEffectError}'s mid-dispatch sibling: a
1802
+ * `commitEffectOps` commit lost every optimistic-locking attempt. Nothing
1803
+ * was written; the report may be retried under the same idempotency key. */
1804
+ export declare class ConcurrentCommitEffectOpsError extends WorkflowError<"concurrent-commit-effect-ops"> {
1805
+ readonly instanceId: string;
1806
+ readonly effectKey: string;
1807
+ readonly attempts: number;
1808
+ constructor(args: {
1809
+ instanceId: string;
1810
+ effectKey: string;
1811
+ attempts: number;
1812
+ });
1813
+ }
1814
+
1598
1815
  /**
1599
1816
  * Completion twin of {@link ConcurrentFireActionError}: a `completeEffect`
1600
1817
  * commit lost the optimistic-locking race on every attempt. Same contract —
@@ -1949,7 +2166,9 @@ export declare class ContractViolationError extends WorkflowError<"contract-viol
1949
2166
  * `completeEffect` — the runtime still decides when to drain and
1950
2167
  * reports outcomes via `completeEffect`.
1951
2168
  */
1952
- export declare function createEngine(args: CreateEngineArgs): Engine;
2169
+ export declare function createEngine<Client extends WorkflowClient>(
2170
+ args: CreateEngineArgs<Client>,
2171
+ ): Engine;
1953
2172
 
1954
2173
  /**
1955
2174
  * The {@link EngineScopeArgs} scope pinned at construction, plus the
@@ -1959,8 +2178,11 @@ export declare function createEngine(args: CreateEngineArgs): Engine;
1959
2178
  * partition is the only thing keeping reads and writes off the wrong
1960
2179
  * environment.
1961
2180
  */
1962
- export declare interface CreateEngineArgs extends EngineScopeArgs {
1963
- effectHandlers?: Record<string, EffectHandler>;
2181
+ export declare interface CreateEngineArgs<
2182
+ Client extends WorkflowClient = WorkflowClient,
2183
+ > extends EngineScopeArgs {
2184
+ client: Client;
2185
+ effectHandlers?: Record<string, EffectHandler<Client>>;
1964
2186
  missingHandler?: MissingHandlerPolicy;
1965
2187
  loggerFactory?: LoggerFactory;
1966
2188
  /**
@@ -2012,19 +2234,88 @@ export declare function createTelemetryIntake(args: {
2012
2234
  }): TelemetryIntake;
2013
2235
 
2014
2236
  /**
2015
- * The reader floor the current model imposes — the compatibility half of
2016
- * {@link MODEL_STAMP}, stamped as `minReaderModel`: the oldest engine model
2017
- * that can safely interpret a document written at {@link DATA_MODEL_VERSION}.
2018
- * An additive change leaves it untouched (older engines read newer docs
2019
- * fine mixed fleets of Functions, Studios, and CLIs are the steady state);
2020
- * ONLY a breaking shape change raises it, and doing so is a declared,
2021
- * DATAMODEL.md-logged decision to fence out older readers.
2237
+ * The append-only, machine-readable counterpart of the model log in
2238
+ * `DATAMODEL.md`. It records compatibility decisions; the prose log retains
2239
+ * the reasoning, absent-value semantics, and old-writer round-trip proof.
2240
+ */
2241
+ export declare const DATA_MODEL_CHANGES: readonly [
2242
+ Readonly<{
2243
+ id: "governed-model-stamps";
2244
+ introducedInModel: 1;
2245
+ minReaderModel: 0;
2246
+ documentTypes: readonly ["definition", "instance"];
2247
+ compatibility: "additive";
2248
+ applicability: "unconditional";
2249
+ summary: "Definition and instance documents carry model provenance and reader-floor stamps.";
2250
+ }>,
2251
+ Readonly<{
2252
+ id: "subject-field-kind";
2253
+ introducedInModel: 2;
2254
+ minReaderModel: 0;
2255
+ documentTypes: readonly ["definition", "instance"];
2256
+ compatibility: "additive";
2257
+ applicability: "detectable";
2258
+ summary: "A workflow-level subject field identifies the document a workflow is about.";
2259
+ }>,
2260
+ Readonly<{
2261
+ id: "typed-scalar-choice-lists";
2262
+ introducedInModel: 2;
2263
+ minReaderModel: 2;
2264
+ documentTypes: readonly ["definition", "instance"];
2265
+ compatibility: "reader-floor";
2266
+ applicability: "detectable";
2267
+ summary: "Scalar fields may constrain writes to a persisted typed choice list.";
2268
+ }>,
2269
+ Readonly<{
2270
+ id: "action-semantics";
2271
+ introducedInModel: 2;
2272
+ minReaderModel: 0;
2273
+ documentTypes: readonly ["definition"];
2274
+ compatibility: "additive";
2275
+ applicability: "detectable";
2276
+ summary: "Ordinary actions may carry a closed bag of advisory workflow semantics.";
2277
+ }>,
2278
+ Readonly<{
2279
+ id: "inclusive-scalar-bounds";
2280
+ introducedInModel: 2;
2281
+ minReaderModel: 2;
2282
+ documentTypes: readonly ["definition", "instance"];
2283
+ compatibility: "reader-floor";
2284
+ applicability: "detectable";
2285
+ summary: "String, text, and number values may carry persisted inclusive bounds.";
2286
+ }>,
2287
+ Readonly<{
2288
+ id: "progress-field-kind";
2289
+ introducedInModel: 3;
2290
+ minReaderModel: 0;
2291
+ documentTypes: readonly ["definition", "instance"];
2292
+ compatibility: "additive";
2293
+ applicability: "detectable";
2294
+ summary: "A progress field kind carries application-defined 0–100 completion.";
2295
+ }>,
2296
+ Readonly<{
2297
+ id: "effect-claim-tokens";
2298
+ introducedInModel: 3;
2299
+ minReaderModel: 0;
2300
+ documentTypes: readonly ["instance"];
2301
+ compatibility: "additive";
2302
+ applicability: "detectable";
2303
+ summary: "Pending-effect claims carry an exact-claim token gating mid-dispatch state reports.";
2304
+ }>,
2305
+ ];
2306
+
2307
+ /**
2308
+ * The maximum reader floor this writer can emit. Individual documents derive
2309
+ * their `minReaderModel` from the compatibility-bearing features actually
2310
+ * present; a document written at {@link DATA_MODEL_VERSION} may therefore
2311
+ * carry a lower floor. Raising this maximum is a declared, DATAMODEL.md-logged
2312
+ * decision that requires readers-first fleet sequencing.
2022
2313
  */
2023
- export declare const DATA_MODEL_MIN_READER = 0;
2314
+ export declare const DATA_MODEL_MIN_READER = 2;
2024
2315
 
2025
2316
  /**
2026
2317
  * The engine's persisted data-model version — the provenance half of
2027
- * {@link MODEL_STAMP}, stamped as `modelVersion` on every engine-owned
2318
+ * the model stamp, written as `modelVersion` on every engine-owned
2028
2319
  * document at its construction and persist choke-points. Conforms-to
2029
2320
  * semantics: the stamp means "this document conforms to model N now" —
2030
2321
  * instances are re-stamped on every full persist, so mixed-version fleets
@@ -2035,7 +2326,19 @@ export declare const DATA_MODEL_MIN_READER = 0;
2035
2326
  * job. Declare every bump in `DATAMODEL.md`; the model-surface snapshot test
2036
2327
  * keeps undeclared drift red.
2037
2328
  */
2038
- export declare const DATA_MODEL_VERSION = 1;
2329
+ export declare const DATA_MODEL_VERSION = 3;
2330
+
2331
+ export declare interface DataModelChange {
2332
+ readonly id: string;
2333
+ readonly introducedInModel: number;
2334
+ readonly minReaderModel: number;
2335
+ readonly documentTypes: readonly DataModelDocumentType[];
2336
+ readonly compatibility: "additive" | "reader-floor";
2337
+ readonly applicability: "unconditional" | "detectable";
2338
+ readonly summary: string;
2339
+ }
2340
+
2341
+ export declare type DataModelDocumentType = "definition" | "instance";
2039
2342
 
2040
2343
  /**
2041
2344
  * Split a dataset resource id (`<projectId>.<dataset>`) into its parts — the
@@ -2056,9 +2359,10 @@ export declare type DeclaredExecutionContext = Pick<
2056
2359
 
2057
2360
  /**
2058
2361
  * The {@link OperationArgs} of the verbs that own a discrete commit —
2059
- * `fireAction`, `editField`, `completeEffect`, `setStage`, `abortInstance`.
2060
- * `tick` deliberately takes the plain base: it owns no commit of its own and
2061
- * re-derives everything, so retrying it blind is already safe.
2362
+ * `fireAction`, `editField`, `completeEffect`, `commitEffectOps`, `setStage`,
2363
+ * `abortInstance`. `tick` deliberately takes the plain base: it owns no
2364
+ * commit of its own and re-derives everything, so retrying it blind is
2365
+ * already safe.
2062
2366
  */
2063
2367
  export declare interface DedupableOperationArgs extends OperationArgs {
2064
2368
  /**
@@ -2211,6 +2515,10 @@ export declare interface DefinitionsForDocumentArgs {
2211
2515
  * perspective the caller loaded the document with.
2212
2516
  */
2213
2517
  document: CandidateDocument;
2518
+ /** Resource-qualified identity of `document`. Required when an applicable
2519
+ * definition's `start.filter` reads `$subjectHasInFlightInstance`; the
2520
+ * loaded value's bare `_id` cannot distinguish resources. */
2521
+ subject?: GdrUri;
2214
2522
  }
2215
2523
 
2216
2524
  /** A definition-level site address: every runtime {@link InsightSite}, plus
@@ -2335,6 +2643,8 @@ export declare interface DeployDefinitionResult {
2335
2643
  export declare interface DeployDefinitionsArgs<
2336
2644
  T extends WorkflowDefinitionInput<T> = WorkflowDefinition,
2337
2645
  > {
2646
+ /** Reviewed literal acknowledging the installed writer's maximum reader-floor capability. */
2647
+ expectedMinReaderModel: typeof DATA_MODEL_MIN_READER;
2338
2648
  /**
2339
2649
  * Resource-alias bindings for this deploy (alias name → physical resource).
2340
2650
  * A deploy-time abstraction ONLY: every `@<alias>:` reference in a
@@ -2392,7 +2702,7 @@ export declare type DeployedDefinition = WorkflowDefinition & {
2392
2702
  *
2393
2703
  * An aborted instance also no-ops: it parks on its stage forever, so a stale
2394
2704
  * deploy landing after abort's retract would re-lock the subjects with no
2395
- * remaining path to lift them. The gate is `abortedAt`, not `completedAt` —
2705
+ * remaining path to delete them. The gate is `abortedAt`, not `completedAt` —
2396
2706
  * a normal move *into* a terminal stage stamps `completedAt` in the same
2397
2707
  * persist and must still deploy that stage's guards.
2398
2708
  */
@@ -2404,6 +2714,7 @@ export declare function deployStageGuards(args: StageGuardArgs): Promise<void>;
2404
2714
  * definitions themselves — carrying `resourceAliases` here is what keeps a diff
2405
2715
  * fingerprinting the same physical content `deployDefinitions` would. */
2406
2716
  export declare interface DeployTarget {
2717
+ expectedMinReaderModel: typeof DATA_MODEL_MIN_READER;
2407
2718
  tag: string;
2408
2719
  workflowResource: WorkflowResource;
2409
2720
  resourceAliases?: ResourceAliases;
@@ -2746,7 +3057,7 @@ export declare type DisabledReason =
2746
3057
  /**
2747
3058
  * The actor's grants on an involved subject's resource don't allow the
2748
3059
  * content write the action's effects would perform there. Forecast
2749
- * per-resource: each subject named by a `doc.ref`/`doc.refs`/`release.ref`
3060
+ * per-resource: each subject named by a `doc.ref`/`subject`/`doc.refs`/`release.ref`
2750
3061
  * field entry outside the workflow's own resource is checked against
2751
3062
  * THAT resource's ACL. Advisory like every engine verdict — the subject's
2752
3063
  * lake still enforces; and it degrades open: a resource whose grants
@@ -2941,6 +3252,7 @@ export declare interface EditableFieldEvaluation {
2941
3252
  name: string;
2942
3253
  type: FieldKind;
2943
3254
  title?: string;
3255
+ validation?: ScalarValidation;
2944
3256
  /** Current resolved value; `undefined` until the field is first resolved. */
2945
3257
  value: unknown;
2946
3258
  /** Whether THIS actor may edit the field right now (window + predicate + guard). */
@@ -3055,6 +3367,16 @@ export declare type EditMode = "set" | "append" | "unset";
3055
3367
 
3056
3368
  export declare type Effect = v.InferOutput<typeof EffectSchema>;
3057
3369
 
3370
+ /** Total commits one dispatch may make — the runaway-handler bound: without
3371
+ * it, a looping reporter renews its own lease and appends history forever.
3372
+ * 2× the ceiling of 1%-granularity progress reporting. */
3373
+ export declare const EFFECT_COMMIT_DISPATCH_CAP = 200;
3374
+
3375
+ /** Pending mid-dispatch commits one dispatch may hold before `commitOps` /
3376
+ * `setProgress` throws synchronously. An awaiting handler never reaches it
3377
+ * (its queue depth stays ≤ 1). */
3378
+ export declare const EFFECT_COMMIT_QUEUE_DEPTH = 32;
3379
+
3058
3380
  /**
3059
3381
  * Every terminal state an effect run can record. `done` and `failed` are
3060
3382
  * reported through completion ({@link EffectCompletionStatus}); `cancelled`
@@ -3064,6 +3386,22 @@ export declare type Effect = v.InferOutput<typeof EffectSchema>;
3064
3386
  */
3065
3387
  declare const EFFECT_RUN_STATUSES: readonly ["done", "failed", "cancelled"];
3066
3388
 
3389
+ /**
3390
+ * A `ctx.commitOps` / `ctx.setProgress` call hit one of the dispatch's
3391
+ * bounds. Thrown synchronously at the call site — see the module doc for why
3392
+ * a rejection would be invisible to exactly the caller the bound exists for.
3393
+ */
3394
+ export declare class EffectCommitQueueOverflowError extends WorkflowError<"effect-commit-queue-overflow"> {
3395
+ readonly effectKey: string;
3396
+ readonly bound: "queue-depth" | "dispatch-cap";
3397
+ readonly limit: number;
3398
+ constructor(args: {
3399
+ effectKey: string;
3400
+ bound: "queue-depth" | "dispatch-cap";
3401
+ limit: number;
3402
+ });
3403
+ }
3404
+
3067
3405
  /** The outcomes a completer may report through `completeEffect` — a run
3068
3406
  * either succeeded or failed. `cancelled` is not reportable: only an abort
3069
3407
  * stamps it, on entries that never dispatched. */
@@ -3072,6 +3410,20 @@ export declare type EffectCompletionStatus = Exclude<
3072
3410
  "cancelled"
3073
3411
  >;
3074
3412
 
3413
+ export declare type EffectHandler<
3414
+ Client extends WorkflowClient = WorkflowClient,
3415
+ > = {
3416
+ /** Bivariant so a concretely typed handler registry remains readable from
3417
+ * the non-generic Engine surface; only the typed drain invokes handlers. */
3418
+ bivarianceHack(
3419
+ params: Record<string, unknown>,
3420
+ ctx: EffectHandlerContext<Client>,
3421
+ ): Promise<{
3422
+ outputs?: Record<string, unknown>;
3423
+ ops?: FieldOp[];
3424
+ } | void>;
3425
+ }["bivarianceHack"];
3426
+
3075
3427
  /**
3076
3428
  * External effect handler — invoked at drain time with the resolved
3077
3429
  * `params` and a context. Returning `outputs` records them on the run's
@@ -3082,8 +3434,10 @@ export declare type EffectCompletionStatus = Exclude<
3082
3434
  * applier as an action's field ops (so a created doc's ref enters `$fields`, or
3083
3435
  * a screened outcome lands in a field the activity/stage gate reads). Effects
3084
3436
  * report results as field state, never by flipping an activity status, so `ops`
3085
- * excludes `status.set`. Throwing marks the effect as failed (and returns no
3086
- * `ops`).
3437
+ * excludes `status.set`. Unlike definition-authored field ops, completion ops
3438
+ * have no authoring location from which to infer a target scope: every returned
3439
+ * op must explicitly set `target.scope` to `'workflow'` or `'stage'`. Throwing
3440
+ * marks the effect as failed (and returns no `ops`).
3087
3441
  *
3088
3442
  * **Delivery is at-least-once — a handler MAY run more than once for the
3089
3443
  * same effect.** Two overlaps produce a double-run: the dispatching process
@@ -3101,38 +3455,66 @@ export declare type EffectCompletionStatus = Exclude<
3101
3455
  * already completed; derive external-system identifiers from `ctx.effectKey`
3102
3456
  * so the receiving system can dedupe the overlap the ledger can't see.
3103
3457
  */
3104
- export declare type EffectHandler = (
3105
- params: Record<string, unknown>,
3106
- ctx: {
3107
- /** The engine's own client — bound to the workflow resource the
3108
- * instance lives in. Use it for same-resource subjects; for a
3109
- * cross-resource subject, route through {@link clientFor} instead. */
3110
- client: WorkflowClient;
3111
- /**
3112
- * Resolve the client bound to a subject doc's own resource. A handler
3113
- * patches the SUBJECT (which may live in a different Sanity resource
3114
- * than the instance split-dataset GDR deploys); the drainer's
3115
- * `completeEffect` writes the INSTANCE through {@link client}. One
3116
- * client can't address both, so a handler that patches a foreign
3117
- * subject must route its write here.
3118
- *
3119
- * Pass the subject's GDR the URI a binding like `$fields.subject._id`
3120
- * resolves to (the hydrated doc's `_id`), or a full
3121
- * {@link GlobalDocumentReference}. Returns the `resourceClients` client
3122
- * for that resource when one is mapped, {@link client} for the workflow
3123
- * resource itself, and a sibling derived from {@link client}'s
3124
- * credentials otherwise. Throws if `ref` isn't a GDR a bare id can't
3125
- * be routed, so failing loud beats silently patching the wrong dataset.
3126
- */
3127
- clientFor: (ref: GdrUri | GlobalDocumentReference) => WorkflowClient;
3128
- instanceId: string;
3129
- effectKey: string;
3130
- log: (message: string, extra?: Record<string, unknown>) => void;
3131
- },
3132
- ) => Promise<{
3133
- outputs?: Record<string, unknown>;
3134
- ops?: FieldOp[];
3135
- } | void>;
3458
+ declare type EffectHandlerContext<Client extends WorkflowClient> = {
3459
+ /**
3460
+ * The exact concrete client supplied to `createEngine`, bound to the
3461
+ * workflow resource rather than an
3462
+ * engine wrapper. Its class identity, namespaces, configuration, and
3463
+ * credentials are preserved. Handler-owned requests are not automatically
3464
+ * tagged by the engine.
3465
+ */
3466
+ client: Client;
3467
+ /**
3468
+ * Resolve the client bound to a subject doc's own resource. A handler
3469
+ * patches the SUBJECT (which may live in a different Sanity resource
3470
+ * than the instance split-dataset GDR deploys); the drainer's
3471
+ * `completeEffect` writes the INSTANCE through {@link client}. One
3472
+ * client can't address both, so a handler that patches a foreign
3473
+ * subject must route its write here.
3474
+ *
3475
+ * Pass the subject's GDR — the URI a binding like `$fields.subject._id`
3476
+ * resolves to (the hydrated doc's `_id`), or a full
3477
+ * {@link GlobalDocumentReference}. Returns the `resourceClients` client
3478
+ * for that resource when one is mapped, {@link client} for the workflow
3479
+ * resource itself, and a sibling derived from {@link client}'s
3480
+ * credentials otherwise. Mapped clients are returned unchanged; an
3481
+ * unmapped foreign resource necessarily returns a configured sibling.
3482
+ * Throws if `ref` isn't a GDR — a bare id can't
3483
+ * be routed, so failing loud beats silently patching the wrong dataset.
3484
+ */
3485
+ clientFor: (ref: GdrUri | GlobalDocumentReference) => WorkflowClient;
3486
+ instanceId: string;
3487
+ effectKey: string;
3488
+ log: (message: string, extra?: Record<string, unknown>) => void;
3489
+ /**
3490
+ * Commit mid-dispatch field state as a real engine transaction —
3491
+ * validated like completion ops (`field.*` only, never `status.set`),
3492
+ * gated on THIS dispatch's exact claim (a stale/superseded claim
3493
+ * rejects before writing), history + idempotency recorded, guards
3494
+ * refreshed, cascade run, and the claim's lease renewed in the same
3495
+ * commit. Calls enqueue synchronously into a bounded per-dispatch FIFO
3496
+ * and execute strictly in call order, one at a time — forgetting to
3497
+ * `await` cannot create same-handler write races, and overflow (or the
3498
+ * per-dispatch commit cap) throws synchronously at the call site.
3499
+ * Await each call anyway: that is where errors surface promptly and
3500
+ * engine commit latency paces the reporter. `idempotencyKey` is
3501
+ * required — the engine does not assume a supplied op is idempotent.
3502
+ * An accepted-but-unawaited commit that fails still fails the effect
3503
+ * at settlement; the final completion always waits for this queue to
3504
+ * drain. Never coalesced.
3505
+ */
3506
+ commitOps: (req: CommitOpsRequest) => Promise<void>;
3507
+ /**
3508
+ * Report absolute progress — sugar over {@link commitOps} that
3509
+ * `field.set`s a number (a `progress` field's 0–100 contract is
3510
+ * enforced by the engine at commit). A bare string targets a
3511
+ * workflow-scope field; pass `{scope: 'stage', field}` for stage
3512
+ * scope. Unlike `commitOps`, PENDING sets to the same field coalesce
3513
+ * (latest value wins, one commit), so a tight reporting loop is safe
3514
+ * by construction; idempotency keys are engine-derived.
3515
+ */
3516
+ setProgress: (target: ProgressTarget, value: number) => Promise<void>;
3517
+ };
3136
3518
 
3137
3519
  export declare interface EffectHistoryEntry {
3138
3520
  _key: string;
@@ -3320,6 +3702,10 @@ export declare interface Engine {
3320
3702
  /** The resolved telemetry logger ({@link noopTelemetry} unless injected) —
3321
3703
  * exposed so adapters built on the engine log through the same seam. */
3322
3704
  readonly telemetry: WorkflowTelemetryLogger;
3705
+ /** Resolve durable actor provenance through this engine's project client. */
3706
+ resolveActor: (
3707
+ args: ResolveClientActorArgs,
3708
+ ) => Promise<ActorResolution<ClientProjectUser>>;
3323
3709
  deployDefinitions: <T extends WorkflowDefinitionInput<T>>(
3324
3710
  args: DeployDefinitionsArgs<T>,
3325
3711
  ) => Promise<DeployDefinitionsResult>;
@@ -3329,6 +3715,10 @@ export declare interface Engine {
3329
3715
  * reassign / reschedule / claim-by-hand / append-to-log, then cascade. */
3330
3716
  editField: (args: EditFieldArgs) => Promise<OperationResult>;
3331
3717
  completeEffect: (args: CompleteEffectArgs) => Promise<OperationResult>;
3718
+ /** Commit mid-dispatch field state from a running effect handler — the
3719
+ * verb behind `ctx.commitOps`. Gated on the dispatch's exact claim token;
3720
+ * a successful commit renews the claim's lease. */
3721
+ commitEffectOps: (args: CommitEffectOpsArgs) => Promise<OperationResult>;
3332
3722
  tick: (args: OperationArgs) => Promise<OperationResult>;
3333
3723
  /** Project the instance from an actor's perspective — per-action verdicts
3334
3724
  * with structured disabled reasons. Pure read. */
@@ -3351,7 +3741,7 @@ export declare interface Engine {
3351
3741
  getInstance: (args: InstanceRefArgs) => Promise<WorkflowInstance>;
3352
3742
  /** The reactive {@link WatchSet} for an instance — every document whose
3353
3743
  * change should re-evaluate it (the instance, its ancestors, and the docs
3354
- * named by `doc.ref`/`doc.refs`/`release.ref` field entries on the workflow scope
3744
+ * named by `doc.ref`/`subject`/`doc.refs`/`release.ref` field entries on the workflow scope
3355
3745
  * + current stage) as exploded {@link SubscriptionDocument}s, plus the
3356
3746
  * instance's read perspective. Fetches the instance, then derives. A
3357
3747
  * reactive adapter that already holds the live instance calls the pure
@@ -3366,8 +3756,9 @@ export declare interface Engine {
3366
3756
  * its own; the consumer drives it. */
3367
3757
  session: (args: SessionArgs) => InstanceSession;
3368
3758
  /** Every lake mutation guard this instance registered, unioned across the
3369
- * instance's own resource and the resource of each `doc.ref`/`doc.refs`
3370
- * GDR it holds in state. For coherency refresh and housekeeping. */
3759
+ * instance's own resource and the resource of each
3760
+ * `doc.ref`/`subject`/`doc.refs` GDR it holds in state. For coherency
3761
+ * refresh and housekeeping. */
3371
3762
  guardsForInstance: (args: InstanceRefArgs) => Promise<MutationGuardDoc[]>;
3372
3763
  /** Every lake mutation guard a workflow deployed (any version), across the
3373
3764
  * datasources its guards statically name — the workflow resource plus any
@@ -3386,14 +3777,14 @@ export declare interface Engine {
3386
3777
  * in-flight instance whose watch-set includes `document` (a resource-qualified
3387
3778
  * GDR URI). For a non-reactive, content-change-driven runtime deciding which
3388
3779
  * instances a changed doc should `tick`. Matches the same ref set the forward
3389
- * watch-set uses (self, ancestors, current-stage `doc.ref`/`doc.refs`/`release.ref`)
3780
+ * watch-set uses (self, ancestors, current-stage `doc.ref`/`subject`/`doc.refs`/`release.ref`)
3390
3781
  * via the shared `collectWatchRefs`. Sorted by `startedAt` asc. */
3391
3782
  instancesForDocument: (
3392
3783
  args: InstancesForDocumentArgs,
3393
3784
  ) => Promise<WorkflowInstance[]>;
3394
3785
  /** The startable half of {@link Engine.instancesForDocument}: the latest
3395
3786
  * deployed version of every definition that applies to the LOADED candidate
3396
- * document — startable, a required subject entry accepts its `_type`, and
3787
+ * document — startable, the `subject`-kind entry accepts its `_type`, and
3397
3788
  * `start.filter` (browse-time-pure — `$fields` never binds) passes. All
3398
3789
  * matches, name ascending; advisory — a start picker's filter, never
3399
3790
  * enforcement. */
@@ -3401,9 +3792,10 @@ export declare interface Engine {
3401
3792
  args: DefinitionsForDocumentArgs,
3402
3793
  ) => Promise<DeployedDefinition[]>;
3403
3794
  /** Pre-flight `startInstance`'s gates for a definition + the
3404
- * `initialFields` gathered so far: the `start.allowed` verdict with its
3405
- * insight (disable the start affordance on a definitive false AND say
3406
- * why) plus the still-missing required inputs. Bindability-aware — a
3795
+ * `initialFields` gathered so far: structurally invalid rows, the
3796
+ * `start.allowed` verdict with its insight, and still-missing required
3797
+ * inputs. `allowed` is the overall startability signal; `outcome` describes
3798
+ * only the condition. Bindability-aware — a
3407
3799
  * predicate reading a not-yet-supplied entry reports `'unevaluable'`
3408
3800
  * with the entries named in `unboundReads`, never a collapsed verdict.
3409
3801
  * Pure read; the enforcement moment is `startInstance` itself. */
@@ -3452,8 +3844,9 @@ export declare interface Engine {
3452
3844
  * housekeeping exports — derives its working client onto this version via
3453
3845
  * {@link WorkflowClient.withConfig}, and `resourceClients`-resolved clients
3454
3846
  * are rebound the same way. A caller's configured `apiVersion` therefore
3455
- * never reaches engine traffic (the caller's own client instance is
3456
- * untouched). The one exception is a client that lacks `withConfig` and so
3847
+ * never reaches engine-owned traffic (the caller's own client instance is
3848
+ * untouched). Effect handlers are host traffic and deliberately receive the
3849
+ * caller's configuration unchanged. The other exception is a client that lacks `withConfig` and so
3457
3850
  * cannot be rebound — it must be built to serve this version; see
3458
3851
  * {@link WorkflowClient.withConfig}.
3459
3852
  */
@@ -3520,9 +3913,9 @@ export declare interface EngineScopeArgs {
3520
3913
 
3521
3914
  /**
3522
3915
  * Pull the {@link GlobalDocumentReference} values out of `doc.ref` /
3523
- * `doc.refs` (content) field entries. Content only — release field entries come
3524
- * from {@link entryReleaseRefs}, so guard discovery (which reads this via
3525
- * `collectEntryDocUris`) stays scoped to content docs.
3916
+ * `subject` / `doc.refs` (content) field entries. Content only — release
3917
+ * field entries come from {@link entryReleaseRefs}, so guard discovery (which
3918
+ * reads this via `collectEntryDocUris`) stays scoped to content docs.
3526
3919
  */
3527
3920
  export declare function entryDocRefs(
3528
3921
  entries: unknown,
@@ -3648,14 +4041,15 @@ export declare interface EvaluateStartArgs {
3648
4041
  * Evaluate one `start.filter` in the start-filter context: `document` (may
3649
4042
  * be absent — a root read is then GROQ null, fail-closed or vacuous-pass by
3650
4043
  * shape) as the GROQ root, the {@link StartScope} bindings plus
3651
- * `$definition`, and — only when
3652
- * `analyzeCondition` says the filter reads the dataset — the scope's fetched
3653
- * slice as `*`. Cheap pure evaluation otherwise: no I/O rides a filter that
3654
- * never scans. GROQ null ("can't decide") is `false` — every consumer of
4044
+ * `$definition`, and — when `analyzeCondition` says the filter reads the
4045
+ * dataset or the filter reads `$subjectHasInFlightInstance` — the scope's
4046
+ * fetched slice as `*`. Cheap pure evaluation otherwise: no I/O rides a
4047
+ * filter that needs neither. GROQ null ("can't decide") is `false` — every consumer of
3655
4048
  * this verdict fails closed; a parse/evaluation THROW is a malformed
3656
- * predicate, not an unevaluable one — rethrown loud, naming the definition
3657
- * (only writable by bypassing deploy validation), so every read surface that
3658
- * evaluates the filter reports the same context. A failed slice FETCH
4049
+ * predicate, not an unevaluable one — rethrown loud, naming the definition,
4050
+ * so every read surface that evaluates the filter reports the same context.
4051
+ * A caller that omits the prospective subject required by the synthetic
4052
+ * variable also throws as a scope-contract error. A failed slice FETCH
3659
4053
  * propagates as itself: transport trouble, never definition blame.
3660
4054
  */
3661
4055
  export declare function evaluateStartFilter(args: {
@@ -3744,6 +4138,30 @@ export declare const EXECUTOR_CLASSIFICATIONS: readonly [
3744
4138
  export declare type ExecutorClassification =
3745
4139
  (typeof EXECUTOR_CLASSIFICATIONS)[number];
3746
4140
 
4141
+ /**
4142
+ * Expand every `@<alias>:` reference in a definition to the physical GDR prefix
4143
+ * its alias binds to, returning a definition that carries only physical
4144
+ * references. Fails closed — naming the definition + alias — when a referenced
4145
+ * alias isn't bound: the check that stops a portable definition from deploying
4146
+ * against the wrong (or no) resource.
4147
+ *
4148
+ * Runs at deploy (inside {@link planDefinitionDeploy}), BEFORE the content
4149
+ * fingerprint, so a deployed definition never carries a logical alias. The
4150
+ * stored references are physical, and a rebind (same source, a different alias
4151
+ * map) surfaces as changed content — a new version, never a silent shift in what
4152
+ * the workflow reads. A no-op when the definition references no aliases.
4153
+ *
4154
+ * Rewrites string VALUES only (via the shared {@link mapJsonStrings} deep-walk),
4155
+ * skipping the prose fields in {@link PROSE_KEYS}. A reference that stands alone
4156
+ * (the whole value is `@<alias>:<id>`, e.g. a literal `doc.ref`) must expand to a
4157
+ * well-formed GDR — a malformed one (`@content:a:b`, an empty id) is rejected
4158
+ * here rather than failing when an instance later reads it.
4159
+ */
4160
+ export declare function expandResourceAliases(
4161
+ definition: WorkflowDefinition,
4162
+ resourceAliases: ResourceAliases | undefined,
4163
+ ): WorkflowDefinition;
4164
+
3747
4165
  export { explainCondition };
3748
4166
 
3749
4167
  export { ExplainConditionArgs };
@@ -3769,7 +4187,7 @@ export { ExplainConditionArgs };
3769
4187
  */
3770
4188
  export declare function explainStartAllowed(args: {
3771
4189
  allowed: string;
3772
- definition: Pick<ApplicabilitySource, "name">;
4190
+ definition: Pick<ApplicabilitySource, "name" | "fields">;
3773
4191
  /** The caller's input entries as a `$fields` map — the engine verbs build
3774
4192
  * it with `startFieldsParam` (field resolution's projection), so the
3775
4193
  * predicate can only see values the resolution would persist. */
@@ -3819,6 +4237,10 @@ export declare const FIELD_KIND_DISPLAY: {
3819
4237
  title: string;
3820
4238
  description: string;
3821
4239
  };
4240
+ subject: {
4241
+ title: string;
4242
+ description: string;
4243
+ };
3822
4244
  "release.ref": {
3823
4245
  title: string;
3824
4246
  description: string;
@@ -3835,6 +4257,10 @@ export declare const FIELD_KIND_DISPLAY: {
3835
4257
  title: string;
3836
4258
  description: string;
3837
4259
  };
4260
+ progress: {
4261
+ title: string;
4262
+ description: string;
4263
+ };
3838
4264
  boolean: {
3839
4265
  title: string;
3840
4266
  description: string;
@@ -3887,10 +4313,12 @@ declare const FIELD_SCOPES: readonly ["workflow", "stage", "activity"];
3887
4313
  declare const FIELD_VALUE_KINDS: readonly [
3888
4314
  "doc.ref",
3889
4315
  "doc.refs",
4316
+ "subject",
3890
4317
  "release.ref",
3891
4318
  "string",
3892
4319
  "text",
3893
4320
  "number",
4321
+ "progress",
3894
4322
  "boolean",
3895
4323
  "date",
3896
4324
  "datetime",
@@ -3930,6 +4358,8 @@ declare type FieldEntryFields<TEditable, TGroup> = FieldBase<
3930
4358
  TGroup
3931
4359
  > & {
3932
4360
  type: FieldValueKind;
4361
+ options?: ChoiceOptions | undefined;
4362
+ validation?: ScalarValidation | undefined;
3933
4363
  types?: string[] | undefined;
3934
4364
  fields?: FieldShape[] | undefined;
3935
4365
  of?: FieldShape[] | undefined;
@@ -3985,6 +4415,8 @@ export declare interface FieldShape {
3985
4415
  name: string;
3986
4416
  title?: string | undefined;
3987
4417
  description?: string | undefined;
4418
+ options?: ChoiceOptions | undefined;
4419
+ validation?: ScalarValidation | undefined;
3988
4420
  fields?: FieldShape[] | undefined;
3989
4421
  of?: FieldShape[] | undefined;
3990
4422
  }
@@ -4018,11 +4450,19 @@ declare type FieldValueKind = (typeof FIELD_VALUE_KINDS)[number];
4018
4450
  export declare interface FieldValueMap {
4019
4451
  "doc.ref": GlobalDocumentReference | null;
4020
4452
  "doc.refs": GlobalDocumentReference[];
4453
+ /** THE document the workflow is about — same value as
4454
+ * {@link FieldValueMap."doc.ref"}, distinct kind so the runtime and UI
4455
+ * identify the subject deterministically (workflow scope, at most one). */
4456
+ subject: GlobalDocumentReference | null;
4021
4457
  "release.ref": ReleaseRef | null;
4022
4458
  string: string | null;
4023
4459
  /** Multiline string — same value as {@link FieldValueMap.string}, distinct kind for rendering. */
4024
4460
  text: string | null;
4025
4461
  number: number | null;
4462
+ /** Application-defined 0–100 completion — same stored value as
4463
+ * {@link FieldValueMap.number}, distinct kind so surfaces can elevate it;
4464
+ * always finite and within 0–100 inclusive (fractions allowed). */
4465
+ progress: number | null;
4026
4466
  boolean: boolean | null;
4027
4467
  /** Date-only (`YYYY-MM-DD`), no time component. */
4028
4468
  date: string | null;
@@ -4120,6 +4560,20 @@ export declare interface FireActionArgs extends DedupableOperationArgs {
4120
4560
  idempotent?: boolean;
4121
4561
  }
4122
4562
 
4563
+ /**
4564
+ * The flow consequence of one caller fire, computed by replaying it in
4565
+ * memory through the same machinery a real commit runs — never by a
4566
+ * parallel model of it. State-dependent: it answers "now", not "always".
4567
+ */
4568
+ export declare interface FiringConsequence {
4569
+ /** The replayed commit's cascade exits the current stage in its first
4570
+ * hop. `false` is a definite answer for the current state — including
4571
+ * a selection halted by an unevaluable trigger, which holds the stage. */
4572
+ exitsStage: boolean;
4573
+ /** The transition the selection picked, present iff `exitsStage`. */
4574
+ transition?: string;
4575
+ }
4576
+
4123
4577
  export { formatRead };
4124
4578
 
4125
4579
  /**
@@ -4354,9 +4808,6 @@ export declare type Guard = v.InferOutput<typeof GuardSchema>;
4354
4808
  */
4355
4809
  export declare const GUARD_DOC_TYPE = "temp.system.guard";
4356
4810
 
4357
- /** Retracted predicate — unconditionally allows, lifting the guard. */
4358
- export declare const GUARD_LIFTED_PREDICATE = "true";
4359
-
4360
4811
  export declare const GUARD_OWNER = "robot:workflow-engine";
4361
4812
 
4362
4813
  /**
@@ -4955,6 +5406,67 @@ export declare interface HydratedSnapshot {
4955
5406
  */
4956
5407
  export declare function inFlightFilter(): string;
4957
5408
 
5409
+ /** Why one caller-supplied initial-field row cannot be consumed. */
5410
+ export declare type InitialFieldIssue = {
5411
+ index: number;
5412
+ name: string;
5413
+ type: FieldKind;
5414
+ } & (
5415
+ | {
5416
+ reason: "duplicate";
5417
+ duplicateIndexes: number[];
5418
+ }
5419
+ | {
5420
+ reason: "undeclared";
5421
+ }
5422
+ | {
5423
+ reason: "wrong-kind";
5424
+ expectedTypes: FieldKind[];
5425
+ }
5426
+ | {
5427
+ reason: "not-input";
5428
+ source:
5429
+ | "working-memory"
5430
+ | Exclude<NonNullable<FieldEntry["initialValue"]>["type"], "input">;
5431
+ }
5432
+ | ({
5433
+ reason: "invalid-scope";
5434
+ stage: string;
5435
+ declaredType: FieldKind;
5436
+ } & (
5437
+ | {
5438
+ scope: "stage";
5439
+ }
5440
+ | {
5441
+ scope: "activity";
5442
+ activity: string;
5443
+ }
5444
+ ))
5445
+ );
5446
+
5447
+ /**
5448
+ * Explain every structural reason caller-supplied initial-field rows cannot
5449
+ * be consumed. Value-shape validation remains in the resolver because it
5450
+ * needs the matched declaration's complete schema.
5451
+ */
5452
+ export declare function initialFieldIssues(
5453
+ args: ScopedInitialFieldDeclarations & {
5454
+ initialFields: readonly InitialFieldValue[];
5455
+ },
5456
+ ): InitialFieldIssue[];
5457
+
5458
+ /**
5459
+ * Thrown before start writes when one or more caller-supplied `initialFields`
5460
+ * rows cannot be consumed by workflow-scope, input-sourced declarations.
5461
+ * `issues` is stable machine-readable remediation context; the message renders
5462
+ * the same complete set for logs and command-line callers.
5463
+ */
5464
+ export declare class InitialFieldsInvalidError extends WorkflowError<"initial-fields-invalid"> {
5465
+ readonly definition?: string;
5466
+ readonly issues: InitialFieldIssue[];
5467
+ constructor(args: { definition?: string; issues: InitialFieldIssue[] });
5468
+ }
5469
+
4958
5470
  /**
4959
5471
  * Initial value for an `input`-sourced entry — what a caller supplies at
4960
5472
  * `startInstance` (or `setStage`). Same discriminator shape as
@@ -5020,8 +5532,8 @@ export declare function instanceDocId(tag: string): string;
5020
5532
  * ({@link verdictGuardsForInstance}) fetches it once against the engine
5021
5533
  * datasource; the reactive adapters feed the same query/params to their
5022
5534
  * stores as a live subscription; {@link guardsForInstance} unions it across
5023
- * datasources for housekeeping. Matches lifted guards too (predicate
5024
- * `"true"`) the consumer decides how to render a lifted guard.
5535
+ * datasources for housekeeping. Ordinary stage retraction deletes guards, so
5536
+ * results represent active persisted guard documents.
5025
5537
  */
5026
5538
  export declare function instanceGuardQuery(instanceId: string): CompiledQuery;
5027
5539
 
@@ -5265,13 +5777,14 @@ export declare function isFilterScopedOut(entry: {
5265
5777
  export declare function isGdr(value: unknown): value is GlobalDocumentReference;
5266
5778
 
5267
5779
  /**
5268
- * Whether a guard has been lifted (retracted to the unconditional-allow
5269
- * predicate). A lift patches the predicate and keeps the doc, so lifted
5270
- * guards still appear in guard queries and streams — this is the
5271
- * discriminator a consumer filters or renders by.
5780
+ * Whether an entry is caller-filled at start/spawn the only source that
5781
+ * reads `initialFields`. Every other source (query/literal/fieldRead, or
5782
+ * working memory) resolves itself at materialisation, so a `$fields.<name>`
5783
+ * read of it can never bind on any read surface that evaluates a
5784
+ * `start.filter`. The deploy read-check keys on this.
5272
5785
  */
5273
- export declare function isGuardLifted(
5274
- guard: Pick<MutationGuardDoc, "predicate">,
5786
+ export declare function isInputSourced(
5787
+ entry: Pick<FieldEntry, "initialValue">,
5275
5788
  ): boolean;
5276
5789
 
5277
5790
  /**
@@ -5295,6 +5808,32 @@ export declare function isNotesEntry(
5295
5808
  }
5296
5809
  >;
5297
5810
 
5811
+ /** Whether a project-user API failure explicitly means the user is absent. */
5812
+ export declare function isProjectUserNotFoundError(error: unknown): boolean;
5813
+
5814
+ /** Entry-level {@link isSingleDocRefKind}: narrows a resolved entry to the
5815
+ * single-GDR arms (`doc.ref` / `subject`) — the value is one GDR (or null)
5816
+ * and the entry may carry the accepted-target `types`. */
5817
+ export declare function isSingleDocRefEntry(
5818
+ entry: ResolvedFieldEntry,
5819
+ ): entry is Extract<
5820
+ ResolvedFieldEntry,
5821
+ {
5822
+ _type: "doc.ref" | "subject";
5823
+ }
5824
+ >;
5825
+
5826
+ /**
5827
+ * Kinds whose value is a single content-document GDR — `doc.ref` and its
5828
+ * elevated alias `subject`. The one predicate behind every "this entry is one
5829
+ * document reference" branch (deref reads, query/spawn ref coercion, input
5830
+ * shape checks, watch-set collection), so the alias can't drift out of a
5831
+ * site.
5832
+ */
5833
+ export declare function isSingleDocRefKind(
5834
+ kind: string,
5835
+ ): kind is "doc.ref" | "subject";
5836
+
5298
5837
  /**
5299
5838
  * Whether a human may start this definition standalone (the default). A
5300
5839
  * `lifecycle: 'child'` definition is spawn-only — instantiated by a parent via
@@ -5308,15 +5847,16 @@ export declare function isStartableDefinition(definition: {
5308
5847
  }): boolean;
5309
5848
 
5310
5849
  /**
5311
- * The SUBJECT-ENTRY RULE: a required `doc.ref` / `doc.refs` input entry is
5312
- * what makes a definition "about" a subject document. One predicate shared by
5313
- * applicability's type matching (`acceptsDocumentType`), the autonomous-start
5314
- * deploy invariant, and the root-read deploy check (a root-reading
5315
- * `start.filter` needs a subject entry to bind a candidate root) so
5316
- * "counts as a subject" can't drift between them.
5850
+ * The SUBJECT-ENTRY RULE: the `subject`-kind entry is what makes a definition
5851
+ * "about" a subject document the kind is the discriminator, never a
5852
+ * heuristic over required refs. One predicate shared by applicability's type
5853
+ * matching (`acceptsDocumentType`), the autonomous-start deploy invariant,
5854
+ * and the root-read deploy check (a root-reading `start.filter` needs a
5855
+ * subject entry to bind a candidate root) — so "counts as a subject" can't
5856
+ * drift between them.
5317
5857
  */
5318
5858
  export declare function isSubjectEntry(
5319
- entry: Pick<FieldEntry, "required" | "type">,
5859
+ entry: Pick<FieldEntry, "type">,
5320
5860
  ): boolean;
5321
5861
 
5322
5862
  /**
@@ -5445,6 +5985,15 @@ export declare interface LoadedDoc {
5445
5985
 
5446
5986
  export declare type LoggerFactory = (name: string) => EngineLogger;
5447
5987
 
5988
+ /** A by-name reference to another workflow definition (an
5989
+ * `action.spawn.definition`). No `version` (or `'latest'`) means "the
5990
+ * highest deployed version at spawn time"; a numeric version pins one
5991
+ * deployed version permanently. */
5992
+ export declare interface LogicalRef {
5993
+ name: string;
5994
+ version?: number | "latest";
5995
+ }
5996
+
5448
5997
  export declare type ManualTarget = v.InferOutput<
5449
5998
  typeof StoredManualTargetSchema
5450
5999
  >;
@@ -5471,7 +6020,7 @@ export { MAX_COUNTERFACTUAL_INDEX };
5471
6020
 
5472
6021
  /**
5473
6022
  * The oldest engine model that can safely read a persisted engine document.
5474
- * The engine always writes the {@link MODEL_STAMP} pair, so a `modelVersion`
6023
+ * The engine always writes the stamp pair, so a `modelVersion`
5475
6024
  * with no `minReaderModel` is malformed foreign data — read conservatively:
5476
6025
  * the stamp itself is the floor. A doc with neither is model 0 (floor 0).
5477
6026
  */
@@ -5818,12 +6367,7 @@ export declare function parseDefinitionInput(
5818
6367
  caller: string,
5819
6368
  ): WorkflowDefinition;
5820
6369
 
5821
- /**
5822
- * The ONE way to read an instance's frozen {@link WorkflowInstance.definitionSnapshot}
5823
- * back into a {@link WorkflowDefinition} — wraps the parse so a corrupt
5824
- * snapshot fails with the instance id attached instead of a bare
5825
- * `SyntaxError`.
5826
- */
6370
+ /** Parse the frozen definition from a complete persisted instance. */
5827
6371
  export declare function parseDefinitionSnapshot(
5828
6372
  instance: WorkflowInstance,
5829
6373
  ): WorkflowDefinition;
@@ -5840,6 +6384,11 @@ export declare interface ParsedGdr {
5840
6384
  documentId: string;
5841
6385
  }
5842
6386
 
6387
+ declare type ParsedWorkflowConfig = v.InferOutput<typeof WorkflowConfigSchema>;
6388
+
6389
+ declare type ParsedWorkflowDeployment =
6390
+ ParsedWorkflowConfig["deployments"][number];
6391
+
5843
6392
  /**
5844
6393
  * Parse a GDR URI into its scheme + addressing parts. Throws on
5845
6394
  * unknown scheme or malformed shape.
@@ -5949,6 +6498,16 @@ export declare interface PendingEffectClaim {
5949
6498
  * live claim), and a field would drift from that trail across releases.
5950
6499
  */
5951
6500
  leaseExpiresAt?: string;
6501
+ /**
6502
+ * The exact-claim identity a mid-dispatch state report must present.
6503
+ * `effectKey` cannot serve: a lease takeover keeps the same key, so a
6504
+ * superseded handler holding only the key could still write. The token is
6505
+ * minted fresh on every claim and takeover; `commitEffectOps` rejects a
6506
+ * report whose token no longer matches before writing anything. Absent
6507
+ * only on claims persisted before tokens existed — those never match, so
6508
+ * their dispatches simply cannot report mid-flight.
6509
+ */
6510
+ claimToken?: string;
5952
6511
  }
5953
6512
 
5954
6513
  /**
@@ -5971,6 +6530,10 @@ export declare class PersistedDocShapeError extends WorkflowError<"persisted-doc
5971
6530
  });
5972
6531
  }
5973
6532
 
6533
+ export declare type PersonActor = Omit<Actor, "kind"> & {
6534
+ readonly kind: "person";
6535
+ };
6536
+
5974
6537
  /**
5975
6538
  * One row of the instance's idempotency ledger — a caller-supplied
5976
6539
  * `idempotencyKey` a state-changing verb already committed under. Recorded in
@@ -6010,6 +6573,15 @@ export declare function processShellUserProperties<
6010
6573
  runtimeVersion: string;
6011
6574
  };
6012
6575
 
6576
+ /** `setProgress`'s field addressing: a bare name targets the workflow scope;
6577
+ * pass `{scope: 'stage', field}` for a stage-scope progress field. */
6578
+ export declare type ProgressTarget =
6579
+ | string
6580
+ | {
6581
+ scope: "workflow" | "stage";
6582
+ field: string;
6583
+ };
6584
+
6013
6585
  /**
6014
6586
  * Project a store-resolved doc onto its watch ref's identity, the way the
6015
6587
  * lake's perspective reads do: the published-form id becomes `_id` (the form
@@ -6030,6 +6602,26 @@ export declare function projectToWatchRef(args: {
6030
6602
  perspective: WorkflowPerspective | undefined;
6031
6603
  }): SanityDocument;
6032
6604
 
6605
+ /** Host integration for current project-user data. */
6606
+ export declare interface ProjectUserDirectory<User> {
6607
+ /** Return `inaccessible` for lookup failures; directory methods must not reject. */
6608
+ readonly findById: (id: string) => Promise<ProjectUserLookup<User>>;
6609
+ readonly findByEmail?: (email: string) => Promise<ProjectUserLookup<User>>;
6610
+ }
6611
+
6612
+ export declare type ProjectUserLookup<User> =
6613
+ | {
6614
+ readonly status: "resolved";
6615
+ readonly user: User;
6616
+ }
6617
+ | {
6618
+ readonly status: "missing";
6619
+ }
6620
+ | {
6621
+ readonly status: "inaccessible";
6622
+ readonly cause?: unknown;
6623
+ };
6624
+
6033
6625
  export declare interface QueryArgs {
6034
6626
  groq: string;
6035
6627
  params?: Record<string, unknown>;
@@ -6039,6 +6631,20 @@ export declare interface QueryInScopeArgs extends InstanceRefArgs, QueryArgs {}
6039
6631
 
6040
6632
  export { quoted };
6041
6633
 
6634
+ export declare const READER_MODEL_ROLLOUT_URL =
6635
+ "https://github.com/sanity-io/workflows/blob/main/docs/reader-model-rollout.md";
6636
+
6637
+ /** A producer has not explicitly acknowledged this engine's writer capability. */
6638
+ export declare class ReaderModelAcknowledgementError extends WorkflowError<"reader-model-acknowledgement"> {
6639
+ readonly code = "WORKFLOW_READER_MODEL_ACKNOWLEDGEMENT_MISMATCH";
6640
+ readonly expectedMinReaderModel: unknown;
6641
+ readonly engineMinReaderModel = 2;
6642
+ readonly engineModelVersion = 3;
6643
+ readonly documentationUrl =
6644
+ "https://github.com/sanity-io/workflows/blob/main/docs/reader-model-rollout.md";
6645
+ constructor(expectedMinReaderModel: unknown, context?: string);
6646
+ }
6647
+
6042
6648
  /**
6043
6649
  * The one spelling of the instance read discipline — model gate
6044
6650
  * ({@link assertReadableModel}) first, shape parse
@@ -6097,6 +6703,15 @@ export declare function refDataset<TType extends string = string>({
6097
6703
  type: TType;
6098
6704
  }): GlobalDocumentReference<TType>;
6099
6705
 
6706
+ /**
6707
+ * Kinds whose entries carry the accepted-target `types` facet — the
6708
+ * content-document reference kinds. `release.ref` is excluded: it points at a
6709
+ * release system doc whose type is fixed.
6710
+ */
6711
+ export declare function refKindAcceptsTypes(
6712
+ kind: string,
6713
+ ): kind is "doc.ref" | "doc.refs" | "subject";
6714
+
6100
6715
  /** Make a GDR pointer to a Media-Library-resource doc. */
6101
6716
  export declare function refMediaLibrary<TType extends string = string>({
6102
6717
  resourceId,
@@ -6117,15 +6732,24 @@ export declare class RefResourceUndeclaredError extends WorkflowError<"ref-resou
6117
6732
  }
6118
6733
 
6119
6734
  /**
6120
- * The GDR `type`s in a `doc.ref` / `doc.refs` value that the entry's declared
6121
- * accepted `types` rejectempty when the value conforms, the entry declares
6122
- * no `types`, or the kind isn't a ref. A GDR's `type` names the target
6123
- * document's schema type, so this is the declared-subject-type contract.
6124
- * Skips anything that isn't GDR-shaped the shape schemas scream about
6125
- * those. Boundaries that need their own error framing (the spawn `with`
6126
- * projection gates its remediation hint on the generic `"document"` type
6127
- * being among the rejects) read this; everything else goes through
6128
- * {@link refTypeIssues} / {@link checkFieldValue}.
6735
+ * Every spawn reference a definition carries, as logical
6736
+ * {@link LogicalRef} entriesthe definition's outgoing edges in the
6737
+ * spawn-dependency graph. The one walk deploy ordering, delete's
6738
+ * referrer check, and external dependency tooling all share, so what
6739
+ * counts as a reference can never drift between them.
6740
+ */
6741
+ export declare function refsOf(def: WorkflowDefinition): LogicalRef[];
6742
+
6743
+ /**
6744
+ * The GDR `type`s in a reference-kind ({@link refKindAcceptsTypes}) value
6745
+ * that the entry's declared accepted `types` reject — empty when the value
6746
+ * conforms, the entry declares no `types`, or the kind isn't a ref. A GDR's
6747
+ * `type` names the target document's schema type, so this is the
6748
+ * declared-target-type contract. Skips anything that isn't GDR-shaped — the
6749
+ * shape schemas scream about those. Boundaries that need their own error
6750
+ * framing (the spawn `with` projection gates its remediation hint on the
6751
+ * generic `"document"` type being among the rejects) read this; everything
6752
+ * else goes through {@link refTypeIssues} / {@link checkFieldValue}.
6129
6753
  */
6130
6754
  export declare function rejectedRefTypes(args: {
6131
6755
  entryType: string;
@@ -6213,12 +6837,18 @@ export declare class RequiredFieldNotProvidedError extends WorkflowError<"requir
6213
6837
  });
6214
6838
  }
6215
6839
 
6216
- /**
6217
- * Names an author's predicate may not use — engine-owned and author names
6218
- * share one namespace, so a predicate redefining a binding would silently
6219
- * shadow engine behaviour. Rejected at deploy; derived from
6220
- * {@link CONDITION_VARS}.
6221
- */
6840
+ /** The known persisted-model requirements applicable to one canonical stored tree. */
6841
+ export declare function requiredModelFeatures(
6842
+ documentType: DataModelDocumentType,
6843
+ document: unknown,
6844
+ ): readonly DataModelChange[];
6845
+
6846
+ /** The oldest engine model that can safely interpret one canonical stored tree. */
6847
+ export declare function requiredReaderModel(
6848
+ documentType: DataModelDocumentType,
6849
+ document: unknown,
6850
+ ): number;
6851
+
6222
6852
  export declare const RESERVED_CONDITION_VARS: readonly string[];
6223
6853
 
6224
6854
  /**
@@ -6242,6 +6872,23 @@ export declare interface ResolveAccessArgs {
6242
6872
  grantsFromPath?: string;
6243
6873
  }
6244
6874
 
6875
+ /** Resolves person provenance without treating agent or system ids as user ids. */
6876
+ export declare function resolveActor<User>(
6877
+ directory: ProjectUserDirectory<User>,
6878
+ actor: Actor,
6879
+ ): Promise<ActorResolution<User>>;
6880
+
6881
+ /** Resolve an actor through a plain engine client, without a UI adapter. */
6882
+ export declare function resolveClientActor(
6883
+ client: WorkflowClient,
6884
+ args: ResolveClientActorArgs,
6885
+ ): Promise<ActorResolution<ClientProjectUser>>;
6886
+
6887
+ export declare interface ResolveClientActorArgs {
6888
+ readonly actor: Actor;
6889
+ readonly projectId: string;
6890
+ }
6891
+
6245
6892
  /**
6246
6893
  * A resolved field entry as the engine persists it on an instance.
6247
6894
  * Discriminated by `_type` (bare — unique within this union); the `value`
@@ -6249,9 +6896,9 @@ export declare interface ResolveAccessArgs {
6249
6896
  * `initialValue` is `{type:'query'}`, of any kind) additionally carries
6250
6897
  * `resolvedAt` — the lake-read time — so `resolvedAt` is provenance-driven,
6251
6898
  * not kind-specific. `object` / `array` entries carry their declared
6252
- * sub-field shape (`fields` / `of`) — and `doc.ref` / `doc.refs` entries
6253
- * their declared accepted `types` — so the instance is self-describing for
6254
- * op-time validation and rendering.
6899
+ * sub-field shape (`fields` / `of`) — and the reference kinds
6900
+ * ({@link refKindAcceptsTypes}) their declared accepted `types` — so the
6901
+ * instance is self-describing for op-time validation and rendering.
6255
6902
  */
6256
6903
  export declare type ResolvedFieldEntry = {
6257
6904
  [K in FieldKind]: {
@@ -6263,6 +6910,8 @@ export declare type ResolvedFieldEntry = {
6263
6910
  value: FieldValueMap[K];
6264
6911
  /** Lake-read time, present only on `query`-sourced entries. */
6265
6912
  resolvedAt?: string;
6913
+ options?: ChoiceOptions;
6914
+ validation?: ScalarValidation;
6266
6915
  } & (K extends "object"
6267
6916
  ? {
6268
6917
  fields: FieldShape[];
@@ -6273,7 +6922,7 @@ export declare type ResolvedFieldEntry = {
6273
6922
  of: FieldShape[];
6274
6923
  }
6275
6924
  : Record<never, never>) &
6276
- (K extends "doc.ref" | "doc.refs"
6925
+ (K extends "doc.ref" | "doc.refs" | "subject"
6277
6926
  ? {
6278
6927
  types?: string[];
6279
6928
  }
@@ -6327,10 +6976,9 @@ export declare function resourceAliasesToMap(
6327
6976
  * boundaries probe this resolver per ref, so narrowing a resolver rejects
6328
6977
  * refs to the resources it stops serving.
6329
6978
  *
6330
- * Resolved clients ride the engine's API version like every other engine
6331
- * client: the verb scope rebinds them onto `ENGINE_API_VERSION` when they
6332
- * carry {@link WorkflowClient.withConfig} (one without it is used as
6333
- * returned and must be built to serve that version).
6979
+ * Engine-owned verb scopes rebind resolved clients onto
6980
+ * `ENGINE_API_VERSION`. Effect handlers receive resolver clients unchanged
6981
+ * because handler traffic belongs to the host.
6334
6982
  */
6335
6983
  export declare type ResourceClientResolver = (
6336
6984
  parsed: ParsedGdr,
@@ -6369,10 +7017,10 @@ export declare interface ResourceSurface {
6369
7017
  }
6370
7018
 
6371
7019
  /**
6372
- * Retract every guard for a stage being exited (lift predicate to allow), but
7020
+ * Retract every guard for a stage being exited by deleting it, but
6373
7021
  * only once the instance has genuinely moved off that stage — or was aborted
6374
7022
  * on it: an aborted instance keeps its `currentStage` (no stage move), so the
6375
- * `abortedAt` stamp is what licenses lifting the stage it still occupies. The
7023
+ * `abortedAt` stamp is what licenses retracting the stage it still occupies. The
6376
7024
  * gate is `abortedAt`, not `completedAt` — normal completion parks the
6377
7025
  * instance on a structurally terminal stage whose guards must stay live.
6378
7026
  * Skip if it is still live on the stage (a concurrent loop-back re-entered
@@ -6445,6 +7093,19 @@ export declare function sameResource(
6445
7093
  b: WorkflowResource,
6446
7094
  ): boolean;
6447
7095
 
7096
+ /** Inclusive scalar bounds. String/text bounds measure character length;
7097
+ * number bounds measure the numeric value. */
7098
+ export declare interface ScalarValidation {
7099
+ min?: number | undefined;
7100
+ max?: number | undefined;
7101
+ }
7102
+
7103
+ export declare function scalarValidationIssues(args: {
7104
+ entryType: string;
7105
+ validation: ScalarValidation | undefined;
7106
+ value: unknown;
7107
+ }): string[] | undefined;
7108
+
6448
7109
  /**
6449
7110
  * The DECLARED field tree of a runtime schema — every entry key (optional
6450
7111
  * keys marked `key?`), every enum vocabulary, every variant arm — walked out
@@ -6458,6 +7119,20 @@ export declare function schemaTreeShape(schema: v.GenericSchema): unknown;
6458
7119
 
6459
7120
  export { ScopeAssignment };
6460
7121
 
7122
+ export declare interface ScopedInitialFieldDeclarations {
7123
+ workflowFields: readonly FieldEntry[];
7124
+ stages?: readonly {
7125
+ name: string;
7126
+ fields?: readonly FieldEntry[] | undefined;
7127
+ activities?:
7128
+ | readonly {
7129
+ name: string;
7130
+ fields?: readonly FieldEntry[] | undefined;
7131
+ }[]
7132
+ | undefined;
7133
+ }[];
7134
+ }
7135
+
6461
7136
  export { sentenceCase };
6462
7137
 
6463
7138
  export declare interface SessionArgs {
@@ -6492,6 +7167,27 @@ export declare interface SiteConsequence {
6492
7167
  after: ConditionOutcome;
6493
7168
  }
6494
7169
 
7170
+ /** One statically invalid parent-to-child spawn contract found at deploy. */
7171
+ export declare type SpawnContractIssue =
7172
+ | {
7173
+ reason: "unresolved-definition";
7174
+ from: string;
7175
+ ref: string;
7176
+ }
7177
+ | {
7178
+ reason: "unconsumable-field";
7179
+ from: string;
7180
+ child: string;
7181
+ field: string;
7182
+ detail: string;
7183
+ };
7184
+
7185
+ /** Deploy refused one or more invalid static `spawn` contracts. */
7186
+ export declare class SpawnContractsInvalidError extends WorkflowError<"spawn-contracts-invalid"> {
7187
+ readonly issues: SpawnContractIssue[];
7188
+ constructor(args: { issues: SpawnContractIssue[]; message: string });
7189
+ }
7190
+
6495
7191
  export declare type Stage = StageFields<
6496
7192
  FieldEntry,
6497
7193
  Activity,
@@ -6565,17 +7261,44 @@ declare interface StageGuardArgs {
6565
7261
 
6566
7262
  export declare type StageName = string;
6567
7263
 
7264
+ /** Why a mid-dispatch report's claim no longer authorises it — see
7265
+ * {@link StaleEffectClaimError}. */
7266
+ export declare type StaleClaimReason =
7267
+ | "unclaimed"
7268
+ | "claim-superseded"
7269
+ | "lease-expired";
7270
+
7271
+ /**
7272
+ * Thrown when a mid-dispatch state report (`commitEffectOps`) presents a
7273
+ * claim token that no longer authorises writing: the entry's claim was
7274
+ * released, taken over by another dispatch (`claim-superseded`), or its
7275
+ * lease lapsed. Nothing was written — the gate runs before any mutation.
7276
+ * The handler should stop reporting; its completion still follows the
7277
+ * normal first-writer-wins completion semantics.
7278
+ */
7279
+ export declare class StaleEffectClaimError extends WorkflowError<"stale-effect-claim"> {
7280
+ readonly instanceId: string;
7281
+ readonly effectKey: string;
7282
+ readonly reason: StaleClaimReason;
7283
+ constructor(args: {
7284
+ instanceId: string;
7285
+ effectKey: string;
7286
+ reason: StaleClaimReason;
7287
+ });
7288
+ }
7289
+
6568
7290
  /**
6569
7291
  * The vars a definition's `start.allowed` reads — the start-time permission
6570
7292
  * dialect: everything the filter context binds ({@link START_FILTER_VARS})
6571
7293
  * plus `$fields`, which start time always has. No candidate root ever binds
6572
7294
  * here (the subject rides `$fields.<entry>.id`; a root read is
6573
- * deploy-rejected), so a false/GROQ-null verdict is genuinely fail-closed —
6574
- * there is no unbound-binding ambiguity to caveat. Bound in one place:
6575
- * `startContextParams` in the applicability evaluator.
7295
+ * deploy-rejected). Pre-flights can omit not-yet-collected input bindings and
7296
+ * report those reads as provisional. Bound in one place: `startContextParams`
7297
+ * in the applicability evaluator.
6576
7298
  */
6577
7299
  export declare const START_ALLOWED_VARS: readonly {
6578
7300
  name: string;
7301
+ label: string;
6579
7302
  description: string;
6580
7303
  }[];
6581
7304
 
@@ -6584,17 +7307,15 @@ export declare const START_ALLOWED_VARS: readonly {
6584
7307
  * not the rendered condition scope (no {@link ConditionVarBinding}: these
6585
7308
  * bind only while the filter is evaluated on the READ side — the
6586
7309
  * `definitionsForDocument` derivation and the Studio start control).
6587
- * `startInstance` never evaluates the filter. BROWSE-TIME-PURE: every var is
6588
- * knowable before any inputs exist, so `$fields` is deliberately absent a
6589
- * `$fields` read in a filter is deploy-rejected with a pointer to
6590
- * `start.allowed`, the context that binds it. An absent binding evaluates to
6591
- * GROQ null; the VERDICT-level coercion (null result not applicable) is
6592
- * what fails closed — what a null read does inside the expression depends on
6593
- * its shape. Bound in one place: `startContextParams` in the applicability
6594
- * evaluator.
7310
+ * `startInstance` never evaluates the filter. BROWSE-TIME-PURE: `$fields` is
7311
+ * deliberately absent a `$fields` read is deploy-rejected with a pointer
7312
+ * to `start.allowed`. The synthetic subject variable requires a prospective
7313
+ * subject; evaluation throws when the caller omits that required scope.
7314
+ * Bound in one place: `startContextParams` in the applicability evaluator.
6595
7315
  */
6596
7316
  export declare const START_FILTER_VARS: readonly {
6597
7317
  name: string;
7318
+ label: string;
6598
7319
  description: string;
6599
7320
  }[];
6600
7321
 
@@ -6623,8 +7344,10 @@ export declare type StartContext = Record<string, unknown>;
6623
7344
  * `RequiredFieldNotProvidedError` for it), never a `start.allowed` verdict.
6624
7345
  */
6625
7346
  export declare interface StartEvaluation {
6626
- /** The `start.allowed` verdict `outcome === 'satisfied'`. Vacuously true
6627
- * when the definition declares no `allowed`, exactly like the verb. */
7347
+ /** Overall preflight startability: every supplied initial-field row is
7348
+ * valid and the `start.allowed` outcome is satisfied. `outcome` describes
7349
+ * only the condition; structurally invalid rows can therefore produce
7350
+ * `allowed: false` with `outcome: 'satisfied'`. */
6628
7351
  allowed: boolean;
6629
7352
  /**
6630
7353
  * Three-valued, BINDABILITY-AWARE verdict: `'unsatisfied'` is a definitive
@@ -6653,6 +7376,10 @@ export declare interface StartEvaluation {
6653
7376
  name: string;
6654
7377
  type: FieldEntry["type"];
6655
7378
  }[];
7379
+ /** Supplied rows `startInstance` would reject before writing. Empty means
7380
+ * every row targets a workflow-scope, input-sourced declaration exactly
7381
+ * once. Render these as corrections, not an authorization verdict. */
7382
+ invalidInitialFields: InitialFieldIssue[];
6656
7383
  }
6657
7384
 
6658
7385
  /** Type-mirror of {@link startFields}: how standalone runs of this workflow
@@ -6691,10 +7418,11 @@ export declare interface StartInstanceArgs {
6691
7418
  * `initialValue` resolution for query/working-memory entries).
6692
7419
  *
6693
7420
  * To start an instance "about" a specific document, declare a
6694
- * `{ type: "doc.ref", name: "subject", initialValue: { type: "input" } }`
7421
+ * `{ type: "subject", name: "subject", initialValue: { type: "input" } }`
6695
7422
  * entry on the workflow and pass
6696
- * `{ type: "doc.ref", name: "subject", value: { id, type } }` here.
6697
- * Conditions then read it as `$fields.subject`.
7423
+ * `{ type: "subject", name: "subject", value: { id, type } }` here.
7424
+ * Conditions then read it as `$fields.subject`, and document pickers key
7425
+ * on the `subject` kind.
6698
7426
  */
6699
7427
  initialFields?: InitialFieldValue[];
6700
7428
  ancestors?: GlobalDocumentReference[];
@@ -6834,6 +7562,7 @@ export declare function startRefusal(definition: {
6834
7562
  * The caller-side half of the start contexts — everything the evaluating
6835
7563
  * surface knows that the definition doesn't. Every member is optional
6836
7564
  * because the surfaces genuinely differ (a pure consumer may hold no clock):
7565
+ * except for the subject identity required by `$subjectHasInFlightInstance`,
6837
7566
  * an absent binding evaluates each read of it to GROQ null, and where that
6838
7567
  * null lands decides the verdict — a predicate that can't decide without
6839
7568
  * the binding fails closed, while a count-of-matches clause over values
@@ -6848,9 +7577,13 @@ export declare interface StartScope {
6848
7577
  tag?: string | undefined;
6849
7578
  /** ISO clock reading — binds `$now`. */
6850
7579
  now?: string | undefined;
7580
+ /** Resource-qualified identity of the prospective subject. Required when
7581
+ * `start.filter` reads `$subjectHasInFlightInstance`; unlike a loaded
7582
+ * document's bare `_id`, this stays collision-free across resources. */
7583
+ subject?: GdrUri | undefined;
6851
7584
  /**
6852
7585
  * The WORKFLOW resource's dataset, for predicates that read it (`*[...]` or
6853
- * a deref) — invoked lazily, only when `analyzeCondition` says the
7586
+ * a deref) or `$subjectHasInFlightInstance` — invoked lazily only when the
6854
7587
  * predicate needs it. A slice is fine as long as it covers what predicates
6855
7588
  * scan; the engine verbs supply EVERY instance of the tag, completed
6856
7589
  * included — `*` carries no hidden predicate, so authors qualify in-flight
@@ -7843,7 +8576,7 @@ export declare const wallClock: Clock;
7843
8576
  export declare interface WatchSet {
7844
8577
  /**
7845
8578
  * Docs to subscribe to — instance + ancestors + the docs named by
7846
- * `doc.ref`/`doc.refs`/`release.ref` field entries — deduped by
8579
+ * `doc.ref`/`subject`/`doc.refs`/`release.ref` field entries — deduped by
7847
8580
  * `globalDocumentId`. Refs that aren't resource-qualified GDR URIs are
7848
8581
  * skipped (without a resource there's nothing to subscribe against).
7849
8582
  */
@@ -8002,6 +8735,23 @@ export declare const workflow: {
8002
8735
  completeEffect: (
8003
8736
  rawArgs: Clocked<Telemetered<CompleteEffectArgs & EngineScopeArgs>>,
8004
8737
  ) => Promise<OperationResult>;
8738
+ /**
8739
+ * Commit mid-dispatch field state from a running effect handler — the
8740
+ * engine verb behind `ctx.commitOps`. Gates on the dispatch's exact claim
8741
+ * (token match + unexpired lease; a stale report throws
8742
+ * `StaleEffectClaimError` and writes nothing), validates and applies the
8743
+ * `field.*` ops through the shared op applier, records history and the
8744
+ * mandatory idempotency key, renews the claim's lease in the same
8745
+ * compare-and-swap commit, refreshes the stage's guards, then cascades —
8746
+ * a report that satisfies a transition moves the instance, by design.
8747
+ *
8748
+ * Completion (`completeEffect`) remains the authoritative final result
8749
+ * and stays claim-blind; this verb only protects the mid-dispatch write
8750
+ * channel from superseded handlers.
8751
+ */
8752
+ commitEffectOps: (
8753
+ rawArgs: Clocked<Telemetered<CommitEffectOpsArgs & EngineScopeArgs>>,
8754
+ ) => Promise<OperationResult>;
8005
8755
  /**
8006
8756
  * Run the cascade until stable — triggered actions fire, transitions move.
8007
8757
  *
@@ -8067,7 +8817,7 @@ export declare const workflow: {
8067
8817
  * filters see for a given instance.
8068
8818
  *
8069
8819
  * Hydrates the instance's snapshot (instance + ancestors + every doc
8070
- * declared by a `doc.ref` / `doc.refs` entry in scope), then
8820
+ * declared by a `doc.ref` / `subject` / `doc.refs` entry in scope), then
8071
8821
  * evaluates the supplied GROQ in groq-js against that dataset. The
8072
8822
  * caller-free rendered scope cascade gates evaluate in is auto-bound —
8073
8823
  * the instance-derived vars ({@link FILTER_SCOPE_VARS}) with the open
@@ -8153,7 +8903,8 @@ export declare const workflow: {
8153
8903
  * Inngest/durable worker, any server) that holds no instances in memory: a
8154
8904
  * document changed; which instances should it `tick`? The watch-set covers
8155
8905
  * the instance itself, its ancestors, and the docs named by
8156
- * `doc.ref` / `doc.refs` / `release.ref` field entries on the workflow scope
8906
+ * `doc.ref` / `subject` / `doc.refs` / `release.ref` field entries on the
8907
+ * workflow scope
8157
8908
  * **and the current stage** — so a hand-rolled GROQ over `fields[]` gets it
8158
8909
  * subtly wrong (misses stage-scope refs, `release.ref`, ancestors).
8159
8910
  *
@@ -8182,7 +8933,7 @@ export declare const workflow: {
8182
8933
  * deployed definition that APPLIES to `document` — what a start picker for
8183
8934
  * it should offer. Loads the latest deployed version of each definition
8184
8935
  * visible to the engine's tag and filters it through the derivation
8185
- * ({@link applicableDefinitions}): startable ∧ a required subject entry
8936
+ * ({@link applicableDefinitions}): startable ∧ the `subject`-kind entry
8186
8937
  * accepts the doc's `_type` ∧ `start.filter` passes — evaluated in the
8187
8938
  * browse-time-pure start-filter context with `$tag`/`$definition`/`$now`
8188
8939
  * bound and the tag's instance slice (completed included) backing dataset
@@ -8190,9 +8941,12 @@ export declare const workflow: {
8190
8941
  * question; pre-flight it with {@link workflow.evaluateStart}.
8191
8942
  *
8192
8943
  * Takes the LOADED candidate document, not a ref — applicability evaluates
8193
- * its content, under whatever perspective the caller read it with. Surfaces
8194
- * ALL matches (name ascending), no engine ranking — presenting a picker or
8195
- * auto-picking is consumer policy. Advisory like every engine-side check.
8944
+ * its content, under whatever perspective the caller read it with. A
8945
+ * resource-qualified `subject` accompanies it when a filter reads
8946
+ * `$subjectHasInFlightInstance`; a bare document id cannot identify a
8947
+ * cross-resource subject. Surfaces ALL matches (name ascending), no engine
8948
+ * ranking — presenting a picker or auto-picking is consumer policy.
8949
+ * Advisory like every engine-side check.
8196
8950
  */
8197
8951
  definitionsForDocument: (
8198
8952
  rawArgs: Clocked<DefinitionsForDocumentArgs & EngineScopeArgs>,
@@ -8433,7 +9187,12 @@ export declare interface WorkflowCommitOptions {
8433
9187
  tag?: string;
8434
9188
  }
8435
9189
 
8436
- export declare type WorkflowConfig = v.InferOutput<typeof WorkflowConfigSchema>;
9190
+ export declare type WorkflowConfig = Omit<
9191
+ ParsedWorkflowConfig,
9192
+ "deployments"
9193
+ > & {
9194
+ deployments: WorkflowDeployment[];
9195
+ };
8437
9196
 
8438
9197
  declare const WorkflowConfigSchema: v.ObjectSchema<
8439
9198
  {
@@ -8445,16 +9204,24 @@ declare const WorkflowConfigSchema: v.ObjectSchema<
8445
9204
  readonly name: v.SchemaWithPipe<
8446
9205
  readonly [
8447
9206
  v.StringSchema<undefined>,
8448
- v.NonEmptyAction<string, "must not be empty">,
9207
+ v.NonEmptyAction<string, undefined>,
9208
+ v.CheckAction<
9209
+ string,
9210
+ `invalid ${string} \u2014 ASCII lowercase + digits + dashes, no leading dash, no dots`
9211
+ >,
8449
9212
  ]
8450
9213
  >;
9214
+ readonly expectedMinReaderModel: v.OptionalSchema<
9215
+ v.CustomSchema<2, undefined>,
9216
+ undefined
9217
+ >;
8451
9218
  readonly tag: v.SchemaWithPipe<
8452
9219
  readonly [
8453
9220
  v.StringSchema<undefined>,
8454
9221
  v.NonEmptyAction<string, undefined>,
8455
9222
  v.CheckAction<
8456
9223
  string,
8457
- "invalid tag lowercase letters, digits and dashes only, no leading dash, no dots"
9224
+ `invalid ${string} \u2014 ASCII lowercase + digits + dashes, no leading dash, no dots`
8458
9225
  >,
8459
9226
  ]
8460
9227
  >;
@@ -8655,7 +9422,30 @@ declare const WorkflowConfigSchema: v.ObjectSchema<
8655
9422
  id: string;
8656
9423
  };
8657
9424
  }[],
8658
- "duplicate resource handle name — each binding name must be unique within a deployment"
9425
+ (
9426
+ issue: v.CheckIssue<
9427
+ {
9428
+ name: string;
9429
+ resource:
9430
+ | {
9431
+ type: "dataset";
9432
+ id: string;
9433
+ }
9434
+ | {
9435
+ type: "canvas";
9436
+ id: string;
9437
+ }
9438
+ | {
9439
+ type: "media-library";
9440
+ id: string;
9441
+ }
9442
+ | {
9443
+ type: "dashboard";
9444
+ id: string;
9445
+ };
9446
+ }[]
9447
+ >,
9448
+ ) => string
8659
9449
  >,
8660
9450
  ]
8661
9451
  >,
@@ -8709,6 +9499,7 @@ declare const WorkflowConfigSchema: v.ObjectSchema<
8709
9499
  v.MinLengthAction<
8710
9500
  {
8711
9501
  name: string;
9502
+ expectedMinReaderModel?: 2 | undefined;
8712
9503
  tag: string;
8713
9504
  workflowResource:
8714
9505
  | {
@@ -8769,6 +9560,127 @@ declare const WorkflowConfigSchema: v.ObjectSchema<
8769
9560
  v.CheckAction<
8770
9561
  {
8771
9562
  name: string;
9563
+ expectedMinReaderModel?: 2 | undefined;
9564
+ tag: string;
9565
+ workflowResource:
9566
+ | {
9567
+ type: "dataset";
9568
+ id: string;
9569
+ }
9570
+ | {
9571
+ type: "canvas";
9572
+ id: string;
9573
+ }
9574
+ | {
9575
+ type: "media-library";
9576
+ id: string;
9577
+ }
9578
+ | {
9579
+ type: "dashboard";
9580
+ id: string;
9581
+ };
9582
+ resourceAliases?:
9583
+ | {
9584
+ name: string;
9585
+ resource:
9586
+ | {
9587
+ type: "dataset";
9588
+ id: string;
9589
+ }
9590
+ | {
9591
+ type: "canvas";
9592
+ id: string;
9593
+ }
9594
+ | {
9595
+ type: "media-library";
9596
+ id: string;
9597
+ }
9598
+ | {
9599
+ type: "dashboard";
9600
+ id: string;
9601
+ };
9602
+ }[]
9603
+ | undefined;
9604
+ definitions: {
9605
+ name: string;
9606
+ title: string;
9607
+ description?: string | undefined;
9608
+ groups?: Group[] | undefined;
9609
+ lifecycle?: WorkflowLifecycle | undefined;
9610
+ start?: StartBlock | undefined;
9611
+ initialStage: string;
9612
+ fields?: FieldEntry[] | undefined;
9613
+ stages: Stage[];
9614
+ predicates?: Record<string, string> | undefined;
9615
+ roleAliases?: RoleAliases | undefined;
9616
+ }[];
9617
+ }[],
9618
+ (
9619
+ issue: v.CheckIssue<
9620
+ {
9621
+ name: string;
9622
+ expectedMinReaderModel?: 2 | undefined;
9623
+ tag: string;
9624
+ workflowResource:
9625
+ | {
9626
+ type: "dataset";
9627
+ id: string;
9628
+ }
9629
+ | {
9630
+ type: "canvas";
9631
+ id: string;
9632
+ }
9633
+ | {
9634
+ type: "media-library";
9635
+ id: string;
9636
+ }
9637
+ | {
9638
+ type: "dashboard";
9639
+ id: string;
9640
+ };
9641
+ resourceAliases?:
9642
+ | {
9643
+ name: string;
9644
+ resource:
9645
+ | {
9646
+ type: "dataset";
9647
+ id: string;
9648
+ }
9649
+ | {
9650
+ type: "canvas";
9651
+ id: string;
9652
+ }
9653
+ | {
9654
+ type: "media-library";
9655
+ id: string;
9656
+ }
9657
+ | {
9658
+ type: "dashboard";
9659
+ id: string;
9660
+ };
9661
+ }[]
9662
+ | undefined;
9663
+ definitions: {
9664
+ name: string;
9665
+ title: string;
9666
+ description?: string | undefined;
9667
+ groups?: Group[] | undefined;
9668
+ lifecycle?: WorkflowLifecycle | undefined;
9669
+ start?: StartBlock | undefined;
9670
+ initialStage: string;
9671
+ fields?: FieldEntry[] | undefined;
9672
+ stages: Stage[];
9673
+ predicates?: Record<string, string> | undefined;
9674
+ roleAliases?: RoleAliases | undefined;
9675
+ }[];
9676
+ }[]
9677
+ >,
9678
+ ) => string
9679
+ >,
9680
+ v.CheckAction<
9681
+ {
9682
+ name: string;
9683
+ expectedMinReaderModel?: 2 | undefined;
8772
9684
  tag: string;
8773
9685
  workflowResource:
8774
9686
  | {
@@ -8823,7 +9735,67 @@ declare const WorkflowConfigSchema: v.ObjectSchema<
8823
9735
  roleAliases?: RoleAliases | undefined;
8824
9736
  }[];
8825
9737
  }[],
8826
- "duplicate deployment tag — each deployment must use a unique tag"
9738
+ (
9739
+ issue: v.CheckIssue<
9740
+ {
9741
+ name: string;
9742
+ expectedMinReaderModel?: 2 | undefined;
9743
+ tag: string;
9744
+ workflowResource:
9745
+ | {
9746
+ type: "dataset";
9747
+ id: string;
9748
+ }
9749
+ | {
9750
+ type: "canvas";
9751
+ id: string;
9752
+ }
9753
+ | {
9754
+ type: "media-library";
9755
+ id: string;
9756
+ }
9757
+ | {
9758
+ type: "dashboard";
9759
+ id: string;
9760
+ };
9761
+ resourceAliases?:
9762
+ | {
9763
+ name: string;
9764
+ resource:
9765
+ | {
9766
+ type: "dataset";
9767
+ id: string;
9768
+ }
9769
+ | {
9770
+ type: "canvas";
9771
+ id: string;
9772
+ }
9773
+ | {
9774
+ type: "media-library";
9775
+ id: string;
9776
+ }
9777
+ | {
9778
+ type: "dashboard";
9779
+ id: string;
9780
+ };
9781
+ }[]
9782
+ | undefined;
9783
+ definitions: {
9784
+ name: string;
9785
+ title: string;
9786
+ description?: string | undefined;
9787
+ groups?: Group[] | undefined;
9788
+ lifecycle?: WorkflowLifecycle | undefined;
9789
+ start?: StartBlock | undefined;
9790
+ initialStage: string;
9791
+ fields?: FieldEntry[] | undefined;
9792
+ stages: Stage[];
9793
+ predicates?: Record<string, string> | undefined;
9794
+ roleAliases?: RoleAliases | undefined;
9795
+ }[];
9796
+ }[]
9797
+ >,
9798
+ ) => string
8827
9799
  >,
8828
9800
  ]
8829
9801
  >;
@@ -8930,7 +9902,12 @@ declare const WorkflowDefinitionSchema: v.GenericSchema<
8930
9902
  WorkflowFields<FieldEntry, Stage, StartBlock>
8931
9903
  >;
8932
9904
 
8933
- export declare type WorkflowDeployment = WorkflowConfig["deployments"][number];
9905
+ export declare type WorkflowDeployment = Omit<
9906
+ ParsedWorkflowDeployment,
9907
+ "expectedMinReaderModel"
9908
+ > & {
9909
+ expectedMinReaderModel: typeof DATA_MODEL_MIN_READER;
9910
+ };
8934
9911
 
8935
9912
  export declare const WorkflowEffectCompleted: WorkflowTelemetryEvent<WorkflowEffectCompletedData>;
8936
9913
 
@@ -8961,6 +9938,17 @@ export declare interface WorkflowEffectsDrainedData extends InstanceScopedEventD
8961
9938
  drainedEffects: EffectName[];
8962
9939
  }
8963
9940
 
9941
+ export declare const WorkflowEffectStateReported: WorkflowTelemetryEvent<WorkflowEffectStateReportedData>;
9942
+
9943
+ export declare interface WorkflowEffectStateReportedData extends InstanceScopedEventData {
9944
+ /** The reporting effect's author-chosen name — one of the payload policy's
9945
+ * two deliberate customer-string exceptions (module doc). */
9946
+ effect: EffectName;
9947
+ /** Auto-transitions fired during the post-report cascade — a report that
9948
+ * satisfies a transition moves the instance. */
9949
+ cascaded: number;
9950
+ }
9951
+
8964
9952
  /**
8965
9953
  * Base class of the engine's structured errors. `kind` is the stable
8966
9954
  * discriminant — render on it; `name` mirrors the concrete class for logs.
@@ -8985,6 +9973,7 @@ export declare type WorkflowErrorKind =
8985
9973
  | "effect-ops-invalid"
8986
9974
  | "effect-outputs-invalid"
8987
9975
  | "required-field-not-provided"
9976
+ | "initial-fields-invalid"
8988
9977
  | "workflow-state-diverged"
8989
9978
  | "partial-guard-deploy"
8990
9979
  | "start-not-primed"
@@ -8992,14 +9981,19 @@ export declare type WorkflowErrorKind =
8992
9981
  | "concurrent-fire-action"
8993
9982
  | "concurrent-edit-field"
8994
9983
  | "concurrent-complete-effect"
9984
+ | "concurrent-commit-effect-ops"
9985
+ | "stale-effect-claim"
9986
+ | "effect-commit-queue-overflow"
8995
9987
  | "cascade-limit"
8996
9988
  | "field-value-shape"
8997
9989
  | "ref-resource-undeclared"
8998
9990
  | "model-version-ahead"
9991
+ | "reader-model-acknowledgement"
8999
9992
  | "persisted-doc-shape"
9000
9993
  | "instance-not-found"
9001
9994
  | "definition-not-found"
9002
9995
  | "definition-in-use"
9996
+ | "spawn-contracts-invalid"
9003
9997
  | "effect-not-found"
9004
9998
  | "missing-effect-handler"
9005
9999
  | "contract-violation";
@@ -9095,9 +10089,9 @@ export declare interface WorkflowInstance extends SanityDocument {
9095
10089
  modelVersion?: number;
9096
10090
  /**
9097
10091
  * Reader floor — the oldest engine data model that can safely interpret
9098
- * this document (see {@link DATA_MODEL_MIN_READER}). Written alongside
9099
- * {@link WorkflowInstance.modelVersion}; additive model changes leave it,
9100
- * only breaking ones raise it.
10092
+ * this document. Derived from features actually present, bounded by
10093
+ * {@link DATA_MODEL_MIN_READER}, and written alongside
10094
+ * {@link WorkflowInstance.modelVersion}. Full persists never lower it.
9101
10095
  */
9102
10096
  minReaderModel?: number;
9103
10097
  /**
@@ -9405,11 +10399,11 @@ export declare interface WorkflowTransaction {
9405
10399
  /**
9406
10400
  * Queue a document delete. Deliberately a transaction-only capability —
9407
10401
  * the top-level client surface stays delete-free so no engine code path
9408
- * can casually remove documents; engine-side the sole consumer is
9409
- * `deleteDefinition` housekeeping (definition docs + orphaned guard docs),
9410
- * and outside the engine the CLI's `nuke` reset deletes raw engine-owned
9411
- * docs through it. Both the real `@sanity/client` Transaction and the test
9412
- * fake's TransactionHandle carry this shape.
10402
+ * can casually remove documents. Engine-side consumers are guard retraction
10403
+ * and `deleteDefinition` housekeeping; outside the engine the CLI's `nuke`
10404
+ * reset deletes raw engine-owned docs through it. Both the real
10405
+ * `@sanity/client` Transaction and the test fake's TransactionHandle carry
10406
+ * this shape.
9413
10407
  */
9414
10408
  delete: (id: string) => WorkflowTransaction;
9415
10409
  /**