@sanity/workflow-engine 0.19.0 → 0.21.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.d.ts CHANGED
@@ -203,7 +203,7 @@ declare const ActionParamSchema: v.SchemaWithPipe<
203
203
  "doc.refs",
204
204
  "json",
205
205
  ],
206
- `Invalid option: expected one of ${string}`
206
+ string
207
207
  >;
208
208
  readonly name: v.SchemaWithPipe<
209
209
  readonly [
@@ -508,15 +508,15 @@ export declare interface ActivityEvaluation {
508
508
  */
509
509
  scopedOut: boolean;
510
510
  /**
511
- * The activity's unmet {@link Activity.requirements}, by name — present iff at least
511
+ * The activity's unmet {@link Activity.requirements}, with authored display copy — present iff at least
512
512
  * one is unmet. The activity's own readiness summary: a consumer can explain why
513
513
  * the whole activity is gated without inspecting each action (every action also
514
514
  * carries the matching `requirements-unmet` `disabledReason`).
515
515
  */
516
- unmetRequirements?: string[];
516
+ unmetRequirements?: RequirementDescriptor[];
517
517
  /** Derived state per declared requirement, keyed by requirement name.
518
518
  * Present iff the activity declares requirements; `unmetRequirements`
519
- * is exactly the keys whose insight isn't satisfied. */
519
+ * contains descriptors for exactly the requirements whose insight isn't satisfied. */
520
520
  requirementInsights?: Record<string, ConditionInsight>;
521
521
  /** Derived state of the activity's `filter` existence gate. Present iff
522
522
  * declared. Advisory read: the engine's stage entry owns the gate itself. */
@@ -533,7 +533,7 @@ declare type ActivityFields<TField, TAction, TTarget, TGroup> = {
533
533
  group?: TGroup | undefined;
534
534
  target?: TTarget | undefined;
535
535
  filter?: string | undefined;
536
- requirements?: Record<string, string> | undefined;
536
+ requirements?: GroqRequirement[] | undefined;
537
537
  actions?: TAction[] | undefined;
538
538
  fields?: TField[] | undefined;
539
539
  };
@@ -546,20 +546,31 @@ export declare type ActivityStatus = (typeof ACTIVITY_STATUSES)[number];
546
546
 
547
547
  /**
548
548
  * Who is acting — advisory provenance, not an authenticated principal. The
549
- * engine always resolves it from the client's token (`/users/me`); there is
550
- * no way to pass or synthesize one. The stamp is still advisory: nothing
551
- * re-verifies it at read time, and only the lake's own token identity is
552
- * authenticated — hard enforcement lives there.
549
+ * engine always resolves it from the client's token; there is no way to pass
550
+ * or synthesize one. The stamp is still advisory: nothing re-verifies it at
551
+ * read time, and only the lake's own token identity is authenticated — hard
552
+ * enforcement lives there.
553
+ *
554
+ * `id` is the account-global user id (the global API host's `/users/me`) —
555
+ * the one identity namespace that is stable across projects and org-level
556
+ * resources. Robot tokens carry a single universal id, so for them `id`
557
+ * equals what every host returns. Instances written before ids were
558
+ * namespace-classified carry the workflow resource's local principal id in
559
+ * `id` instead; readers interpret those through the prefix classifier in
560
+ * `core/identity.ts` with the document's home resource as the implied
561
+ * scope.
553
562
  */
554
563
  export declare interface Actor {
555
564
  kind: ActorKind;
556
565
  id: string;
557
566
  /**
558
567
  * Free-form role names — typically a copy of Sanity's `user.roles[].name`
559
- * for the token behind the call. The engine treats these as opaque
560
- * strings, matched by literal membership: `Action.roles` and `assignees`
561
- * roles OR-match against this list. There is no actor-side wildcard — a
562
- * `"*"` here is just a literal string and matches nothing on its own.
568
+ * for the token behind the call, as the workflow resource's host reports
569
+ * them (project roles for dataset resources). The engine treats these as
570
+ * opaque strings, matched by literal membership: `Action.roles` and
571
+ * `assignees` roles OR-match against this list. There is no actor-side
572
+ * wildcard — a `"*"` here is just a literal string and matches nothing on
573
+ * its own.
563
574
  *
564
575
  * To let one role satisfy a gate it doesn't literally name — e.g. an
565
576
  * `administrator` satisfying a narrower gate, or one deployment's role
@@ -597,6 +608,9 @@ export declare type ActorResolution<User> =
597
608
 
598
609
  export { analyzeCondition };
599
610
 
611
+ /** Lake `identity()` sentinel for unauthenticated callers. */
612
+ export declare const ANONYMOUS_IDENTITY = "<anonymous>";
613
+
600
614
  /** The definition surface the start contexts read — structural, so authored,
601
615
  * stored, and deployed definition shapes all fit. `name` binds
602
616
  * `$definition` and names the definition in a broken-predicate error. */
@@ -608,7 +622,7 @@ export declare interface ApplicabilitySource {
608
622
  | {
609
623
  kind?: StartKind | undefined;
610
624
  filter?: string | undefined;
611
- allowed?: string | undefined;
625
+ requirements?: StartRequirement[] | undefined;
612
626
  }
613
627
  | undefined;
614
628
  }
@@ -747,10 +761,7 @@ declare type AuthoringFieldRef = v.InferOutput<typeof AuthoringFieldRefSchema>;
747
761
  declare const AuthoringFieldRefSchema: v.StrictObjectSchema<
748
762
  {
749
763
  readonly scope: v.OptionalSchema<
750
- v.PicklistSchema<
751
- readonly ["workflow", "stage", "activity"],
752
- `Invalid option: expected one of ${string}`
753
- >,
764
+ v.PicklistSchema<readonly ["workflow", "stage", "activity"], string>,
754
765
  undefined
755
766
  >;
756
767
  readonly field: v.SchemaWithPipe<
@@ -916,7 +927,7 @@ declare const AuthoringGuardSchema: v.StrictObjectSchema<
916
927
  v.ArraySchema<
917
928
  v.PicklistSchema<
918
929
  readonly ["create", "update", "delete", "publish", "unpublish"],
919
- `Invalid option: expected one of ${string}`
930
+ string
920
931
  >,
921
932
  undefined
922
933
  >,
@@ -1091,7 +1102,7 @@ declare const AuthoringManualTargetSchema: v.VariantSchema<
1091
1102
  readonly scope: v.OptionalSchema<
1092
1103
  v.PicklistSchema<
1093
1104
  readonly ["workflow", "stage", "activity"],
1094
- `Invalid option: expected one of ${string}`
1105
+ string
1095
1106
  >,
1096
1107
  undefined
1097
1108
  >;
@@ -1127,7 +1138,7 @@ declare const AuthoringOpSchema: v.VariantSchema<
1127
1138
  readonly scope: v.OptionalSchema<
1128
1139
  v.PicklistSchema<
1129
1140
  readonly ["workflow", "stage", "activity"],
1130
- `Invalid option: expected one of ${string}`
1141
+ string
1131
1142
  >,
1132
1143
  undefined
1133
1144
  >;
@@ -1152,7 +1163,7 @@ declare const AuthoringOpSchema: v.VariantSchema<
1152
1163
  readonly scope: v.OptionalSchema<
1153
1164
  v.PicklistSchema<
1154
1165
  readonly ["workflow", "stage", "activity"],
1155
- `Invalid option: expected one of ${string}`
1166
+ string
1156
1167
  >,
1157
1168
  undefined
1158
1169
  >;
@@ -1176,7 +1187,7 @@ declare const AuthoringOpSchema: v.VariantSchema<
1176
1187
  readonly scope: v.OptionalSchema<
1177
1188
  v.PicklistSchema<
1178
1189
  readonly ["workflow", "stage", "activity"],
1179
- `Invalid option: expected one of ${string}`
1190
+ string
1180
1191
  >,
1181
1192
  undefined
1182
1193
  >;
@@ -1201,7 +1212,7 @@ declare const AuthoringOpSchema: v.VariantSchema<
1201
1212
  readonly scope: v.OptionalSchema<
1202
1213
  v.PicklistSchema<
1203
1214
  readonly ["workflow", "stage", "activity"],
1204
- `Invalid option: expected one of ${string}`
1215
+ string
1205
1216
  >,
1206
1217
  undefined
1207
1218
  >;
@@ -1232,7 +1243,7 @@ declare const AuthoringOpSchema: v.VariantSchema<
1232
1243
  readonly scope: v.OptionalSchema<
1233
1244
  v.PicklistSchema<
1234
1245
  readonly ["workflow", "stage", "activity"],
1235
- `Invalid option: expected one of ${string}`
1246
+ string
1236
1247
  >,
1237
1248
  undefined
1238
1249
  >;
@@ -1268,7 +1279,7 @@ declare const AuthoringOpSchema: v.VariantSchema<
1268
1279
  >;
1269
1280
  readonly status: v.PicklistSchema<
1270
1281
  readonly ["active", "done", "skipped", "failed"],
1271
- `Invalid option: expected one of ${string}`
1282
+ string
1272
1283
  >;
1273
1284
  },
1274
1285
  undefined
@@ -1281,7 +1292,7 @@ declare const AuthoringOpSchema: v.VariantSchema<
1281
1292
  readonly scope: v.OptionalSchema<
1282
1293
  v.PicklistSchema<
1283
1294
  readonly ["workflow", "stage", "activity"],
1284
- `Invalid option: expected one of ${string}`
1295
+ string
1285
1296
  >,
1286
1297
  undefined
1287
1298
  >;
@@ -1609,6 +1620,25 @@ declare type ClaimField = {
1609
1620
  group?: GroupMembership | undefined;
1610
1621
  };
1611
1622
 
1623
+ export declare interface ClassifiedPrincipal {
1624
+ namespace: PrincipalNamespace;
1625
+ /**
1626
+ * The account-global id when the string itself carries it: the id verbatim
1627
+ * for `global` and `robot` (a robot's single id IS its universal identity),
1628
+ * the embedded global id for `e-` project ids. Absent for plain `project`
1629
+ * ids (resolving those needs the project-users directory), sentinels, and
1630
+ * unknowns.
1631
+ */
1632
+ globalId?: string;
1633
+ }
1634
+
1635
+ /**
1636
+ * Classify a bare principal-id string by its namespace. Total — never
1637
+ * throws; ids that fit no known form come back `unknown` so the caller
1638
+ * decides how loud to be.
1639
+ */
1640
+ export declare function classifyPrincipalId(id: string): ClassifiedPrincipal;
1641
+
1612
1642
  /**
1613
1643
  * The `@sanity/client`-config fragment that addresses a {@link WorkflowResource}
1614
1644
  * — the one home for the dataset-vs-resource branch every client-building host
@@ -1637,6 +1667,13 @@ declare type ClientForGdr = (parsed: ParsedGdr) => WorkflowClient;
1637
1667
  /** Native project-user response returned by Sanity's project API. */
1638
1668
  export declare interface ClientProjectUser {
1639
1669
  readonly id: string;
1670
+ /**
1671
+ * The person's account-global user id — the canonical identity every
1672
+ * workflow value stores. This is the sanctioned bridge between a
1673
+ * project's local principal namespace and the global one; surfaces use
1674
+ * it to emit assignment values from project-member displays.
1675
+ */
1676
+ readonly sanityUserId?: string;
1640
1677
  readonly displayName?: string;
1641
1678
  readonly email?: string;
1642
1679
  readonly imageUrl?: string | null;
@@ -1969,14 +2006,15 @@ export declare interface ConditionVar {
1969
2006
  * the rest evaluate to `undefined` — and deploy rejects them at these
1970
2007
  * sites; a cascade-fired action's per-token gate is `roles`, never its
1971
2008
  * conditions.
1972
- * 3. **The start contexts** — a definition's `start.filter` and
1973
- * `start.allowed` evaluate against a CANDIDATE (no instance exists yet):
1974
- * `*[...]` reads the WORKFLOW resource's dataset and none of the rendered
2009
+ * 3. **The start contexts** — a definition's `start.filter` and start GROQ
2010
+ * requirements evaluate against a CANDIDATE (no instance exists yet):
2011
+ * `*[...]` reads the engine-owned `{definition, subject, completedAt}`
2012
+ * projection of the tag's instances and none of the rendered
1975
2013
  * condition vars exist. The two split on what a surface can know:
1976
2014
  * `filter` is browse-time-pure (candidate document as root,
1977
2015
  * {@link START_FILTER_VARS} — no `$fields`, which cannot exist before
1978
- * inputs do), `allowed` is the start-time permission predicate
1979
- * ({@link START_ALLOWED_VARS} — `$fields` bound, never a root).
2016
+ * inputs do), a `groq` requirement is the start-time readiness predicate
2017
+ * ({@link START_REQUIREMENT_VARS} — `$fields` bound, never a root).
1980
2018
  * 4. **Guard predicates** — NOT conditions. A lake mutation guard's
1981
2019
  * `predicate` is groq-js **delta-mode** GROQ over a document mutation:
1982
2020
  * `before()`/`after()`/`identity()` are dialect natives, and the wire
@@ -1997,10 +2035,9 @@ export declare type ConditionVarBinding = "always" | "caller" | "spawn";
1997
2035
 
1998
2036
  /**
1999
2037
  * The one-doc read a reactive adapter subscribes with to observe a content doc
2000
- * under a perspective stack the same GROQ as the engine's own hydration read
2001
- * ({@link hydrateSnapshot}), so the adapter and the engine resolve identical
2002
- * content: draft/version content projected onto the published id, a doc that
2003
- * exists only as a draft (or only inside a release) still visible.
2038
+ * under a perspective stack. It uses the same perspective semantics as
2039
+ * {@link hydrateSnapshot}: draft/version content is projected onto the published
2040
+ * id, and a doc that exists only as a draft or release version remains visible.
2004
2041
  */
2005
2042
  export declare function contentDocQuery(documentId: string): CompiledQuery;
2006
2043
 
@@ -2302,6 +2339,24 @@ export declare const DATA_MODEL_CHANGES: readonly [
2302
2339
  applicability: "detectable";
2303
2340
  summary: "Pending-effect claims carry an exact-claim token gating mid-dispatch state reports.";
2304
2341
  }>,
2342
+ Readonly<{
2343
+ id: "classified-principal-ids";
2344
+ introducedInModel: 4;
2345
+ minReaderModel: 4;
2346
+ documentTypes: readonly ["instance"];
2347
+ compatibility: "reader-floor";
2348
+ applicability: "unconditional";
2349
+ summary: string;
2350
+ }>,
2351
+ Readonly<{
2352
+ id: "readiness-requirements";
2353
+ introducedInModel: 4;
2354
+ minReaderModel: 4;
2355
+ documentTypes: readonly ["definition"];
2356
+ compatibility: "reader-floor";
2357
+ applicability: "detectable";
2358
+ summary: "Start and activity readiness use named polymorphic requirement arrays.";
2359
+ }>,
2305
2360
  ];
2306
2361
 
2307
2362
  /**
@@ -2311,7 +2366,7 @@ export declare const DATA_MODEL_CHANGES: readonly [
2311
2366
  * carry a lower floor. Raising this maximum is a declared, DATAMODEL.md-logged
2312
2367
  * decision that requires readers-first fleet sequencing.
2313
2368
  */
2314
- export declare const DATA_MODEL_MIN_READER = 2;
2369
+ export declare const DATA_MODEL_MIN_READER = 4;
2315
2370
 
2316
2371
  /**
2317
2372
  * The engine's persisted data-model version — the provenance half of
@@ -2326,7 +2381,7 @@ export declare const DATA_MODEL_MIN_READER = 2;
2326
2381
  * job. Declare every bump in `DATAMODEL.md`; the model-surface snapshot test
2327
2382
  * keeps undeclared drift red.
2328
2383
  */
2329
- export declare const DATA_MODEL_VERSION = 3;
2384
+ export declare const DATA_MODEL_VERSION = 4;
2330
2385
 
2331
2386
  export declare interface DataModelChange {
2332
2387
  readonly id: string;
@@ -2515,10 +2570,6 @@ export declare interface DefinitionsForDocumentArgs {
2515
2570
  * perspective the caller loaded the document with.
2516
2571
  */
2517
2572
  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;
2522
2573
  }
2523
2574
 
2524
2575
  /** A definition-level site address: every runtime {@link InsightSite}, plus
@@ -2539,9 +2590,8 @@ export declare type DefinitionSiteAddress =
2539
2590
 
2540
2591
  /**
2541
2592
  * GROQ listing EVERY deployed {@link WORKFLOW_DEFINITION_TYPE} visible to the
2542
- * caller's tag, grouped by name. `versionOrder` picks the in-group direction:
2543
- * `'desc'` puts each name's latest first (discovery keeps the head per name),
2544
- * `'asc'` walks history oldest-first (handler verification reads them all).
2593
+ * caller's tag, grouped by name. `versionOrder` picks the in-group direction;
2594
+ * handler verification uses oldest-first order while inspecting every version.
2545
2595
  *
2546
2596
  * Params: `$tag`.
2547
2597
  */
@@ -3045,13 +3095,13 @@ export declare type DisabledReason =
3045
3095
  /**
3046
3096
  * The activity's declared {@link Activity.requirements} aren't all satisfied —
3047
3097
  * the readiness axis. The activity is visible and the actor authorized, but
3048
- * its own preconditions don't hold yet. `unmetRequirements` names the
3049
- * failing keys so a consumer can disable the affirmative control and say
3098
+ * its own preconditions don't hold yet. `unmetRequirements` carries the
3099
+ * authored descriptors so a consumer can disable the affirmative control and say
3050
3100
  * which precondition is outstanding. Distinct from `filter-failed`
3051
3101
  * (visibility/authorization) and `mutation-guard-denied` (content-write).
3052
3102
  */
3053
3103
  kind: "requirements-unmet";
3054
- unmetRequirements: string[];
3104
+ unmetRequirements: RequirementDescriptor[];
3055
3105
  }
3056
3106
  | {
3057
3107
  /**
@@ -3136,7 +3186,8 @@ export declare interface DocumentActionDenialsArgs {
3136
3186
  };
3137
3187
  action: MutationGuardAction;
3138
3188
  guards: readonly MutationGuardDoc[];
3139
- /** Actor id, resolved as `identity()` in predicates. */
3189
+ /** The caller's principal id in the guarded resource's own namespace,
3190
+ * resolved as `identity()` in predicates. */
3140
3191
  identity?: string;
3141
3192
  }
3142
3193
 
@@ -3151,10 +3202,8 @@ declare type DocumentEnvelopeKey =
3151
3202
  | "minReaderModel";
3152
3203
 
3153
3204
  /**
3154
- * The document-prefilter GROQ arm — matches instances that MAY reference any
3155
- * of `documents`. A deliberate lake-side SUPERSET (it also matches
3156
- * exited-stage refs); narrow fetched rows to the exact watch-set with
3157
- * {@link instanceWatchesDocument}. Binds `$documents` + `$bareIds` into
3205
+ * The document GROQ arm — matches instances whose reactive watch-set
3206
+ * references any of `documents`. Binds `$documents` + `$bareIds` into
3158
3207
  * `params`. Exposed for list builders that compose their own conditions
3159
3208
  * (e.g. the CLI's cross-partition list); {@link instancesQuery} consumers get
3160
3209
  * it via the `document`/`documents` filter fields instead.
@@ -3457,11 +3506,13 @@ export declare type EffectHandler<
3457
3506
  */
3458
3507
  declare type EffectHandlerContext<Client extends WorkflowClient> = {
3459
3508
  /**
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.
3509
+ * A concrete sibling of the client supplied to `createEngine`, bound to the
3510
+ * workflow resource with the same namespaces and credentials. Untagged
3511
+ * handler requests on its workflow-client surface carry the `workflow.effect`
3512
+ * request tag by default. A concrete client's explicit tags compose beneath
3513
+ * that prefix. On the structural fallback for minimal clients, pass-through
3514
+ * namespaces are not stamped and core builders expose the engine's minimal
3515
+ * workflow-client surface.
3465
3516
  */
3466
3517
  client: Client;
3467
3518
  /**
@@ -3477,8 +3528,8 @@ declare type EffectHandlerContext<Client extends WorkflowClient> = {
3477
3528
  * {@link GlobalDocumentReference}. Returns the `resourceClients` client
3478
3529
  * for that resource when one is mapped, {@link client} for the workflow
3479
3530
  * 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.
3531
+ * credentials otherwise. Returned clients preserve their concrete APIs and
3532
+ * apply the same default effect request tag.
3482
3533
  * Throws if `ref` isn't a GDR — a bare id can't
3483
3534
  * be routed, so failing loud beats silently patching the wrong dataset.
3484
3535
  */
@@ -3733,6 +3784,9 @@ export declare interface Engine {
3733
3784
  setStage: (args: SetStageArgs) => Promise<OperationResult>;
3734
3785
  /** Admin override — hard-stop an in-flight instance where it stands. */
3735
3786
  abortInstance: (args: AbortInstanceArgs) => Promise<OperationResult>;
3787
+ /** Admin override — reset a failed/terminal activity in the current stage
3788
+ * back to `active` (re-run) or `skipped` (bypass), then cascade. */
3789
+ resetActivity: (args: ResetActivityArgs) => Promise<OperationResult>;
3736
3790
  /** Admin override — remove a deployed definition (instances are only ever aborted, never deleted). */
3737
3791
  deleteDefinition: (
3738
3792
  args: DeleteDefinitionArgs,
@@ -3792,12 +3846,13 @@ export declare interface Engine {
3792
3846
  args: DefinitionsForDocumentArgs,
3793
3847
  ) => Promise<DeployedDefinition[]>;
3794
3848
  /** Pre-flight `startInstance`'s gates for a definition + the
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
3799
- * predicate reading a not-yet-supplied entry reports `'unevaluable'`
3800
- * with the entries named in `unboundReads`, never a collapsed verdict.
3849
+ * `initialFields` gathered so far: structurally invalid rows, every
3850
+ * requirement's ordered descriptor/outcome/insight, and still-missing
3851
+ * required inputs. `allowed` is the overall startability signal; `outcome`
3852
+ * aggregates the requirements. Bindability-aware — a requirement reading
3853
+ * a not-yet-supplied entry (including `singleSubject`'s implicit subject
3854
+ * read) reports `'unevaluable'` with the entries named
3855
+ * in `unboundReads`, never a collapsed verdict.
3801
3856
  * Pure read; the enforcement moment is `startInstance` itself. */
3802
3857
  evaluateStart: (args: EvaluateStartArgs) => Promise<StartEvaluation>;
3803
3858
  /** GROQ query against the engine's workflow resource. `$tag`
@@ -3845,10 +3900,10 @@ export declare interface Engine {
3845
3900
  * {@link WorkflowClient.withConfig}, and `resourceClients`-resolved clients
3846
3901
  * are rebound the same way. A caller's configured `apiVersion` therefore
3847
3902
  * 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
3850
- * cannot be rebound — it must be built to serve this version; see
3851
- * {@link WorkflowClient.withConfig}.
3903
+ * untouched). Effect handlers keep the caller's `apiVersion`; their derived
3904
+ * clients change only the request-tag prefix. The other exception is a client
3905
+ * that lacks `withConfig` and so cannot be rebound — it must be built to serve
3906
+ * this version; see {@link WorkflowClient.withConfig}.
3852
3907
  */
3853
3908
  export declare const ENGINE_API_VERSION = "2026-04-29";
3854
3909
 
@@ -3969,6 +4024,13 @@ export declare interface EvaluateFromSnapshotArgs {
3969
4024
  instance: WorkflowInstance;
3970
4025
  definition: WorkflowDefinition;
3971
4026
  actor: Actor;
4027
+ /**
4028
+ * The actor's principal id in the workflow resource's own identity
4029
+ * namespace — the comparand for everything the resource's lake evaluates
4030
+ * (`identity()` in guard predicates, the anchor ACL's grant filters).
4031
+ * Omitted when it equals {@link Actor.id} (org-level resources, robots).
4032
+ */
4033
+ localPrincipalId?: string;
3972
4034
  /**
3973
4035
  * Resolved grants for the actor. Omit to leave the rendered `$can`
3974
4036
  * undefined (conditions referencing it fail closed — the real lake
@@ -3998,14 +4060,16 @@ export declare interface EvaluateFromSnapshotArgs {
3998
4060
  */
3999
4061
  guards?: readonly MutationGuardDoc[];
4000
4062
  /**
4001
- * The actor's ACL grants per FOREIGN subject resource, keyed by
4002
- * resource-shaped GDR (`<type>:<id>`) feeds the subject-write forecast on
4003
- * effects-bearing actions ({@link SubjectPermissionDenial}). Omit, or omit a
4004
- * resource, to skip that resource's forecast (degrade open the subject's
4005
- * lake still enforces). {@link evaluateInstance} resolves this through each
4063
+ * Per-FOREIGN-subject-resource access — the actor's ACL grants PLUS the
4064
+ * actor's principal id in that resource's own namespace — keyed by
4065
+ * resource-shaped GDR (`<type>:<id>`); feeds the subject-write forecast on
4066
+ * effects-bearing actions ({@link SubjectPermissionDenial}). A resource
4067
+ * appears only when both halves resolved; omit it (or the whole map) to
4068
+ * skip that resource's forecast (degrade open — the subject's lake still
4069
+ * enforces). {@link evaluateInstance} resolves this through each
4006
4070
  * resource's own client via {@link subjectResourceGrants}.
4007
4071
  */
4008
- resourceGrants?: ReadonlyMap<string, Grant[]>;
4072
+ resourceGrants?: ReadonlyMap<string, SubjectResourceAccess>;
4009
4073
  }
4010
4074
 
4011
4075
  /**
@@ -4042,15 +4106,13 @@ export declare interface EvaluateStartArgs {
4042
4106
  * be absent — a root read is then GROQ null, fail-closed or vacuous-pass by
4043
4107
  * shape) as the GROQ root, the {@link StartScope} bindings plus
4044
4108
  * `$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
4109
+ * dataset the scope's fetched slice as `*`. Cheap pure evaluation otherwise: no I/O rides a
4047
4110
  * filter that needs neither. GROQ null ("can't decide") is `false` — every consumer of
4048
4111
  * this verdict fails closed; a parse/evaluation THROW is a malformed
4049
4112
  * predicate, not an unevaluable one — rethrown loud, naming the definition,
4050
4113
  * 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
4053
- * propagates as itself: transport trouble, never definition blame.
4114
+ * A failed slice FETCH propagates as itself: transport trouble, never
4115
+ * definition blame.
4054
4116
  */
4055
4117
  export declare function evaluateStartFilter(args: {
4056
4118
  filter: string;
@@ -4167,7 +4229,7 @@ export { explainCondition };
4167
4229
  export { ExplainConditionArgs };
4168
4230
 
4169
4231
  /**
4170
- * Explain one `start.allowed` in the start-allowed context: no root (the
4232
+ * Explain one start GROQ requirement in the start-requirement context: no root (the
4171
4233
  * subject rides `$fields.<entry>.id` — deploy rejects a root read), the
4172
4234
  * {@link StartScope} bindings plus `$definition` and the caller's `$fields`
4173
4235
  * map, and the scope's fetched slice as `*` when the predicate reads the
@@ -4185,8 +4247,8 @@ export { ExplainConditionArgs };
4185
4247
  * bug as an author verdict. Parse/evaluation throws rethrow naming the
4186
4248
  * definition, like the filter's; a failed slice FETCH propagates as itself.
4187
4249
  */
4188
- export declare function explainStartAllowed(args: {
4189
- allowed: string;
4250
+ export declare function explainStartRequirement(args: {
4251
+ query: string;
4190
4252
  definition: Pick<ApplicabilitySource, "name" | "fields">;
4191
4253
  /** The caller's input entries as a `$fields` map — the engine verbs build
4192
4254
  * it with `startFieldsParam` (field resolution's projection), so the
@@ -4713,6 +4775,11 @@ declare function grantsPermissionOn(args: {
4713
4775
  userId?: string;
4714
4776
  }): Promise<boolean>;
4715
4777
 
4778
+ export declare type GroqRequirement = RequirementBase & {
4779
+ type: "groq";
4780
+ query: string;
4781
+ };
4782
+
4716
4783
  /** Type-mirror of {@link GroupSchema} — one declared group. */
4717
4784
  export declare type Group = {
4718
4785
  name: string;
@@ -4826,7 +4893,7 @@ export declare type GuardAction = v.InferOutput<typeof GuardActionSchema>;
4826
4893
 
4827
4894
  declare const GuardActionSchema: v.PicklistSchema<
4828
4895
  readonly ["create", "update", "delete", "publish", "unpublish"],
4829
- `Invalid option: expected one of ${string}`
4896
+ string
4830
4897
  >;
4831
4898
 
4832
4899
  export declare type GuardMatch = Guard["match"];
@@ -4991,7 +5058,7 @@ declare const GuardSchema: v.StrictObjectSchema<
4991
5058
  v.ArraySchema<
4992
5059
  v.PicklistSchema<
4993
5060
  readonly ["create", "update", "delete", "publish", "unpublish"],
4994
- `Invalid option: expected one of ${string}`
5061
+ string
4995
5062
  >,
4996
5063
  undefined
4997
5064
  >,
@@ -5098,6 +5165,11 @@ export { guillemets };
5098
5165
  */
5099
5166
  export declare function hashDefinitionContent(def: WorkflowDefinition): string;
5100
5167
 
5168
+ /** Whether the definition declares a `singleSubject` start requirement. */
5169
+ export declare function hasSingleSubjectRequirement(
5170
+ definition: Pick<ApplicabilitySource, "start">,
5171
+ ): boolean;
5172
+
5101
5173
  /**
5102
5174
  * History-entry `_type` discriminators. Order roughly matches the
5103
5175
  * order a typical run produces them in a single fire-action commit.
@@ -5527,13 +5599,14 @@ export declare type InsightSite =
5527
5599
  export declare function instanceDocId(tag: string): string;
5528
5600
 
5529
5601
  /**
5530
- * The per-instance guard filter — the single definition of "this instance's
5531
- * guards in one datasource". The engine's verdict load
5532
- * ({@link verdictGuardsForInstance}) fetches it once against the engine
5533
- * datasource; the reactive adapters feed the same query/params to their
5534
- * stores as a live subscription; {@link guardsForInstance} unions it across
5535
- * datasources for housekeeping. Ordinary stage retraction deletes guards, so
5536
- * results represent active persisted guard documents.
5602
+ * The per-instance guard filter — "this instance's guards in one datasource".
5603
+ * The engine's verdict load ({@link verdictGuardsForInstance}) fetches it once
5604
+ * against the engine datasource, and {@link guardsForInstance} unions it
5605
+ * across datasources for housekeeping; the reactive adapters subscribe the
5606
+ * set-shaped {@link instancesGuardQuery} this delegates to (one shared
5607
+ * live query per resource, sliced per `sourceInstanceId`), so every path
5608
+ * reads through one filter definition. Ordinary stage retraction deletes
5609
+ * guards, so results represent active persisted guard documents.
5537
5610
  */
5538
5611
  export declare function instanceGuardQuery(instanceId: string): CompiledQuery;
5539
5612
 
@@ -5586,6 +5659,12 @@ export declare interface InstanceSession {
5586
5659
  * docs are processed), never from the commit itself — the commit's
5587
5660
  * outcome is never masked by a store echo's failure. */
5588
5661
  update(docs: LoadedDoc[]): void;
5662
+ /** Replace one held document without rebuilding the rest of the overlay.
5663
+ * Consumers with per-document streams use this after the initial
5664
+ * {@link InstanceSession.update} snapshot. Self-doc recency, commit-time
5665
+ * buffering, and deferred buffered-validation errors follow the same
5666
+ * contract as {@link InstanceSession.update}. */
5667
+ updateDocument(doc: LoadedDoc): void;
5589
5668
  /** Replace the held live guards (the consumer's guard stream,
5590
5669
  * last-write-wins). Guards are a separate stream from the watch-set:
5591
5670
  * {@link InstanceSession.evaluate} pre-flights the instance write against
@@ -5647,6 +5726,18 @@ export declare interface InstancesForDocumentArgs {
5647
5726
  document: GdrUri;
5648
5727
  }
5649
5728
 
5729
+ /**
5730
+ * The guard filter for a SET of instances in one datasource — the single
5731
+ * definition every per-instance read delegates to ({@link instanceGuardQuery}).
5732
+ * Reactive adapters subscribe it as ONE shared live query per resource for
5733
+ * every co-mounted session, fanning results back out per `sourceInstanceId`,
5734
+ * so a document's guard subscription count doesn't grow with its instance
5735
+ * count. Deterministically ordered, matching {@link guardsForResource}.
5736
+ */
5737
+ export declare function instancesGuardQuery(
5738
+ instanceIds: readonly string[],
5739
+ ): CompiledQuery;
5740
+
5650
5741
  /**
5651
5742
  * The instance-list GROQ for a {@link InstancesQueryFilter}, ordered by
5652
5743
  * `startedAt` ascending (descending + sliced under
@@ -5666,17 +5757,16 @@ export declare function instancesQuery(args: {
5666
5757
  export declare interface InstancesQueryFilter {
5667
5758
  /**
5668
5759
  * Only instances that may reference this document (resource-qualified GDR
5669
- * URI). This is a lake-side PREFILTER a deliberate superset that also
5670
- * matches exited-stage refs; narrow the fetched rows to the exact reactive
5671
- * watch-set with {@link instanceWatchesDocument}.
5760
+ * URI). The lake-side predicate matches the reactive watch-set's
5761
+ * workflow, open-stage, activity, ancestor, live-child, and own-id references.
5672
5762
  */
5673
5763
  document?: GdrUri;
5674
5764
  /**
5675
5765
  * The multi-document form of {@link InstancesQueryFilter.document}: one
5676
- * prefilter matching instances that may reference ANY of the given docs,
5766
+ * predicate matching instances that reference ANY of the given docs,
5677
5767
  * for consumers discovering instances across many open documents at once.
5678
- * Merged with `document` when both are set; per-document narrowing is the
5679
- * caller's ({@link instanceWatchesDocument} again). A DEFINED-but-EMPTY
5768
+ * Merged with `document` when both are set. Callers may defensively recheck
5769
+ * with {@link instanceWatchesDocument}. A DEFINED-but-EMPTY
5680
5770
  * array matches nothing (the GROQ-natural reading of membership in an
5681
5771
  * empty set) — omit the field for the unconstrained every-in-flight read.
5682
5772
  */
@@ -5740,6 +5830,10 @@ export declare function isClaimExpired(
5740
5830
  now: string,
5741
5831
  ): boolean;
5742
5832
 
5833
+ export declare function isClientProjectUser(
5834
+ value: unknown,
5835
+ ): value is ClientProjectUser;
5836
+
5743
5837
  export { isComparisonOp };
5744
5838
 
5745
5839
  /**
@@ -5931,12 +6025,35 @@ export declare function lakeGuardId(args: {
5931
6025
  }): string;
5932
6026
 
5933
6027
  /**
5934
- * The latest deployed version of each definition name the reduction every
5935
- * "what would a start load?" consumer applies over a
5936
- * {@link definitionsListGroq} read (GROQ has no group-by, so it happens
5937
- * client-side). Order-independent: the highest version per name wins under
5938
- * either `versionOrder`; names keep first-appearance order, so a
5939
- * name-ascending read stays name-ascending.
6028
+ * The id a lake-facing check binds for an actor: the resource-local
6029
+ * principal id when the namespaces diverge, otherwise the actor's own
6030
+ * (account-global) id. Every advisory that must agree with the lake's
6031
+ * `identity()` guard previews and pre-flights, the anchor ACL's `$can`
6032
+ * grant filters resolves through this one rule; binding `actor.id`
6033
+ * directly at a lake edge reintroduces the divergent-identity mismatch.
6034
+ */
6035
+ export declare function lakePrincipalId(args: {
6036
+ actor: {
6037
+ id: string;
6038
+ };
6039
+ localPrincipalId?: string | undefined;
6040
+ }): string;
6041
+
6042
+ /**
6043
+ * GROQ listing only the latest deployed version of each definition name.
6044
+ * The correlated inner query keeps the reduction in the lake, so discovery
6045
+ * reads do not transfer every historical definition body.
6046
+ *
6047
+ * Params: `$tag`.
6048
+ */
6049
+ export declare function latestDefinitionsGroq(): string;
6050
+
6051
+ /**
6052
+ * The latest deployed version of each definition name from any supplied row
6053
+ * set. Useful at boundaries that may already hold multiple versions; callers
6054
+ * starting from the lake can use {@link latestDefinitionsGroq}. The highest
6055
+ * version wins regardless of input order, while names keep first-appearance
6056
+ * order.
5940
6057
  */
5941
6058
  export declare function latestDeployedDefinitions<
5942
6059
  T extends {
@@ -6134,9 +6251,10 @@ export declare interface MutationContext {
6134
6251
  | null;
6135
6252
  action: MutationGuardAction;
6136
6253
  /**
6137
- * Caller-asserted actor id, resolved as `identity()` in the predicate.
6138
- * Advisory the engine takes the caller's word for who is acting; only
6139
- * the lake's own token identity is authenticated.
6254
+ * The caller's principal id in the guarded resource's own namespace
6255
+ * (what that lake's `identity()` returns), resolved as `identity()` in
6256
+ * the predicate. Advisory — the engine takes the caller's word for who
6257
+ * is acting; only the lake's own token identity is authenticated.
6140
6258
  */
6141
6259
  identity?: string;
6142
6260
  }
@@ -6534,6 +6652,24 @@ export declare type PersonActor = Omit<Actor, "kind"> & {
6534
6652
  readonly kind: "person";
6535
6653
  };
6536
6654
 
6655
+ /**
6656
+ * The namespace a bare principal-id string belongs to.
6657
+ *
6658
+ * - `global` — account-global (comparable across every org-level context)
6659
+ * - `project` — scoped to ONE project; which project is not in the string,
6660
+ * it comes from context (for stored engine values: the anchor resource
6661
+ * the document lives in)
6662
+ * - `robot` — a token principal with one universal id (never needs mapping)
6663
+ * - `sentinel` — `<anonymous>` / `<system>`, never a person
6664
+ * - `unknown` — unclassifiable; treat as unresolvable and surface it
6665
+ */
6666
+ export declare type PrincipalNamespace =
6667
+ | "global"
6668
+ | "project"
6669
+ | "robot"
6670
+ | "sentinel"
6671
+ | "unknown";
6672
+
6537
6673
  /**
6538
6674
  * One row of the instance's idempotency ledger — a caller-supplied
6539
6675
  * `idempotencyKey` a state-changing verb already committed under. Recorded in
@@ -6582,14 +6718,19 @@ export declare type ProgressTarget =
6582
6718
  field: string;
6583
6719
  };
6584
6720
 
6721
+ /** Project a readable instance into the only row shape start predicates may scan. */
6722
+ export declare function projectStartSliceRow(
6723
+ instance: WorkflowInstance,
6724
+ ): StartSliceRow;
6725
+
6585
6726
  /**
6586
6727
  * Project a store-resolved doc onto its watch ref's identity, the way the
6587
6728
  * lake's perspective reads do: the published-form id becomes `_id` (the form
6588
6729
  * the session keys its overlay and snapshot by), and a draft/version
6589
6730
  * representation's stored id rides along as `_originalId` — session-side
6590
6731
  * conditions (including the `_originalId in path("versions.**")` shape) then
6591
- * read exactly what the engine's own hydration ({@link contentDocQuery})
6592
- * returns. Strict by construction: only the ids in
6732
+ * read the same projected identity as the engine's perspective-aware hydration.
6733
+ * Strict by construction: only the ids in
6593
6734
  * {@link watchRefRepresentations} are accepted — an id that merely *ends* in
6594
6735
  * the watched id (another doc's dotted id under a version prefix), a release
6595
6736
  * the perspective doesn't read, or a draft the perspective makes invisible is
@@ -6638,8 +6779,8 @@ export declare const READER_MODEL_ROLLOUT_URL =
6638
6779
  export declare class ReaderModelAcknowledgementError extends WorkflowError<"reader-model-acknowledgement"> {
6639
6780
  readonly code = "WORKFLOW_READER_MODEL_ACKNOWLEDGEMENT_MISMATCH";
6640
6781
  readonly expectedMinReaderModel: unknown;
6641
- readonly engineMinReaderModel = 2;
6642
- readonly engineModelVersion = 3;
6782
+ readonly engineMinReaderModel = 4;
6783
+ readonly engineModelVersion = 4;
6643
6784
  readonly documentationUrl =
6644
6785
  "https://github.com/sanity-io/workflows/blob/main/docs/reader-model-rollout.md";
6645
6786
  constructor(expectedMinReaderModel: unknown, context?: string);
@@ -6805,8 +6946,8 @@ export declare function remediationsFor(
6805
6946
  /**
6806
6947
  * A verb that would unstick a {@link StuckCause} — the *what to do about it*
6807
6948
  * half of a diagnosis. Surface-neutral identifiers; a consumer maps each to
6808
- * its own command or button. `retry-effect` and `reset-activity` are not yet
6809
- * callable engine operations — see {@link SuggestedRemediation.available}.
6949
+ * its own command or button. `retry-effect` is not yet a callable engine
6950
+ * operation — see {@link SuggestedRemediation.available}.
6810
6951
  */
6811
6952
  export declare type RemediationVerb =
6812
6953
  | "retry-effect"
@@ -6849,8 +6990,65 @@ export declare function requiredReaderModel(
6849
6990
  document: unknown,
6850
6991
  ): number;
6851
6992
 
6993
+ declare type RequirementBase = {
6994
+ name: string;
6995
+ title?: string | undefined;
6996
+ description?: string | undefined;
6997
+ };
6998
+
6999
+ /** Authored identity and display copy for one readiness requirement. */
7000
+ export declare interface RequirementDescriptor {
7001
+ name: string;
7002
+ title?: string | undefined;
7003
+ description?: string | undefined;
7004
+ }
7005
+
7006
+ /**
7007
+ * Names an author's predicate may not use — engine-owned and author names
7008
+ * share one namespace, so a predicate redefining a binding would silently
7009
+ * shadow engine behaviour. Rejected at deploy; derived from the condition
7010
+ * inventory.
7011
+ */
6852
7012
  export declare const RESERVED_CONDITION_VARS: readonly string[];
6853
7013
 
7014
+ /**
7015
+ * What to reset a stuck activity INTO — the two non-`failed` outcomes that
7016
+ * unstick a stage gated on it. `active` re-runs it (back in progress, so a
7017
+ * caller drives it to completion again); `skipped` bypasses it (terminal but
7018
+ * resolved, so `$allActivitiesDone` can satisfy and a gated exit transition
7019
+ * fire). `done` is deliberately absent: a reset is recovery, not a silent
7020
+ * declaration that the work succeeded.
7021
+ */
7022
+ declare const RESET_ACTIVITY_TARGETS: readonly ["active", "skipped"];
7023
+
7024
+ export declare interface ResetActivityArgs extends DedupableOperationArgs {
7025
+ /** Name of the activity to reset, within the instance's current stage. */
7026
+ activity: string;
7027
+ /**
7028
+ * What to reset it into. `active` (the default) re-runs the activity — back
7029
+ * in progress, for a caller to drive to completion again; `skipped` bypasses
7030
+ * it — terminal but resolved, so a `$allActivitiesDone`-gated exit transition
7031
+ * can fire. `done` is intentionally not offered: a reset is recovery, not a
7032
+ * silent success.
7033
+ */
7034
+ to?: ResetActivityTarget;
7035
+ }
7036
+
7037
+ export declare type ResetActivityResult =
7038
+ | {
7039
+ fired: false;
7040
+ }
7041
+ | {
7042
+ fired: true;
7043
+ stage: StageName;
7044
+ activity: ActivityName;
7045
+ from: ActivityStatus;
7046
+ to: ResetActivityTarget;
7047
+ };
7048
+
7049
+ export declare type ResetActivityTarget =
7050
+ (typeof RESET_ACTIVITY_TARGETS)[number];
7051
+
6854
7052
  /**
6855
7053
  * Resolve the engine's `WorkflowAccess` for a client — both halves
6856
7054
  * fetched from its token in parallel and cached. Throws if the client
@@ -6977,8 +7175,8 @@ export declare function resourceAliasesToMap(
6977
7175
  * refs to the resources it stops serving.
6978
7176
  *
6979
7177
  * 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.
7178
+ * `ENGINE_API_VERSION`. Effect handlers derive request-tagged siblings from
7179
+ * resolver clients so their concrete APIs remain available and attributed.
6982
7180
  */
6983
7181
  export declare type ResourceClientResolver = (
6984
7182
  parsed: ParsedGdr,
@@ -7160,6 +7358,34 @@ export declare interface SetStageArgs extends DedupableOperationArgs {
7160
7358
  */
7161
7359
  export declare const silentLogger: EngineLogger;
7162
7360
 
7361
+ export declare type SingleSubjectRequirement = RequirementBase & {
7362
+ type: "singleSubject";
7363
+ };
7364
+
7365
+ /**
7366
+ * Evaluate a declared `singleSubject` requirement — resolves `true` when it
7367
+ * REFUSES the start: an in-flight instance (no `completedAt`) of THIS
7368
+ * definition already holds the prospective subject. The subject resolves from
7369
+ * the `$fields` map's subject entry (a GDR envelope, `.id` the identity),
7370
+ * falling back to `scope.subject`. No subject in hand means nothing to compare — the requirement
7371
+ * passes; a pre-flight surface reports the unbound subject entry as
7372
+ * provisional through {@link unboundRequirementReads}. The rule is
7373
+ * count-shaped, so an absent `scope.fetchDataset` THROWS like a
7374
+ * dataset-reading GROQ requirement — an empty `*` would pass vacuously. One
7375
+ * evaluator serves every moment: the `startInstance` gate enforces it
7376
+ * (`StartNotAllowedError`), the `evaluateStart` verb pre-flights it, and start
7377
+ * surfaces evaluate it directly for their controls — every site gated by
7378
+ * {@link hasSingleSubjectRequirement}, so only a rule this engine knows arrives
7379
+ * here (an absent or unsupported rule is the caller's contract violation).
7380
+ * Advisory under races like every engine-side check.
7381
+ */
7382
+ export declare function singleSubjectRequirementRefused(args: {
7383
+ definition: Pick<ApplicabilitySource, "name" | "fields" | "start">;
7384
+ /** A produced `$fields` map (`startFieldsParam`, or a surface's seed map). */
7385
+ fields?: Record<string, unknown> | undefined;
7386
+ scope?: StartScope | undefined;
7387
+ }): Promise<boolean>;
7388
+
7163
7389
  /** One site whose verdict a proposed assignment flips. */
7164
7390
  export declare interface SiteConsequence {
7165
7391
  site: InsightSite;
@@ -7287,21 +7513,6 @@ export declare class StaleEffectClaimError extends WorkflowError<"stale-effect-c
7287
7513
  });
7288
7514
  }
7289
7515
 
7290
- /**
7291
- * The vars a definition's `start.allowed` reads — the start-time permission
7292
- * dialect: everything the filter context binds ({@link START_FILTER_VARS})
7293
- * plus `$fields`, which start time always has. No candidate root ever binds
7294
- * here (the subject rides `$fields.<entry>.id`; a root read is
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.
7298
- */
7299
- export declare const START_ALLOWED_VARS: readonly {
7300
- name: string;
7301
- label: string;
7302
- description: string;
7303
- }[];
7304
-
7305
7516
  /**
7306
7517
  * The vars a definition's `start.filter` reads — the start-filter dialect,
7307
7518
  * not the rendered condition scope (no {@link ConditionVarBinding}: these
@@ -7309,8 +7520,7 @@ export declare const START_ALLOWED_VARS: readonly {
7309
7520
  * `definitionsForDocument` derivation and the Studio start control).
7310
7521
  * `startInstance` never evaluates the filter. BROWSE-TIME-PURE: `$fields` is
7311
7522
  * 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.
7523
+ * to start GROQ requirements.
7314
7524
  * Bound in one place: `startContextParams` in the applicability evaluator.
7315
7525
  */
7316
7526
  export declare const START_FILTER_VARS: readonly {
@@ -7321,6 +7531,21 @@ export declare const START_FILTER_VARS: readonly {
7321
7531
 
7322
7532
  declare const START_KINDS: readonly ["interactive", "autonomous"];
7323
7533
 
7534
+ /**
7535
+ * The vars a definition's start GROQ requirements read — the start-time readiness
7536
+ * dialect: everything the filter context binds ({@link START_FILTER_VARS})
7537
+ * plus `$fields`, which start time always has. No candidate root ever binds
7538
+ * here (the subject rides `$fields.<entry>.id`; a root read is
7539
+ * deploy-rejected). Pre-flights can omit not-yet-collected input bindings and
7540
+ * report those reads as provisional. Bound in one place: `startContextParams`
7541
+ * in the applicability evaluator.
7542
+ */
7543
+ export declare const START_REQUIREMENT_VARS: readonly {
7544
+ name: string;
7545
+ label: string;
7546
+ description: string;
7547
+ }[];
7548
+
7324
7549
  export declare type StartBlock = StartFields & {
7325
7550
  kind: StartKind;
7326
7551
  };
@@ -7341,34 +7566,34 @@ export declare type StartContext = Record<string, unknown>;
7341
7566
  * What `evaluateStart` projects — the same gates `startInstance` enforces,
7342
7567
  * as renderable state. `allowed` and `missingRequired` are deliberately
7343
7568
  * orthogonal: a missing required input is a caller mistake (the verb throws
7344
- * `RequiredFieldNotProvidedError` for it), never a `start.allowed` verdict.
7569
+ * `RequiredFieldNotProvidedError` for it), never a readiness verdict.
7345
7570
  */
7346
7571
  export declare interface StartEvaluation {
7347
7572
  /** 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
7573
+ * valid and every declared start requirement is satisfied. `outcome` describes only the
7574
+ * predicates; structurally invalid rows can therefore produce
7350
7575
  * `allowed: false` with `outcome: 'satisfied'`. */
7351
7576
  allowed: boolean;
7352
7577
  /**
7353
- * Three-valued, BINDABILITY-AWARE verdict: `'unsatisfied'` is a definitive
7354
- * no for these inputs (disable and explain), `'unevaluable'` means the
7355
- * predicate can't be decided yet — either a null operand reached an
7356
- * ordered comparison, or the predicate reads an entry `initialFields`
7357
- * doesn't supply ({@link StartEvaluation.unboundReads} non-empty). Keep
7358
- * the affordance enabled on `'unevaluable'`; `startInstance` still
7359
- * enforces the final verdict, where absence is final rather than
7360
- * provisional.
7578
+ * Three-valued, BINDABILITY-AWARE verdict over the start predicates:
7579
+ * `'unsatisfied'` is a definitive no for these inputs (disable and
7580
+ * explain), `'unevaluable'` means the verdict can't be decided yet —
7581
+ * either a null operand reached an ordered comparison, or a predicate
7582
+ * reads an entry `initialFields` doesn't supply
7583
+ * ({@link StartEvaluation.unboundReads} non-empty). One exception outranks
7584
+ * the provisional rule: any definitive requirement refusal keeps the
7585
+ * aggregate `'unsatisfied'` even while other reads are unbound. Keep the
7586
+ * affordance enabled on `'unevaluable'`; `startInstance` still enforces
7587
+ * the final verdict, where absence is final rather than provisional.
7361
7588
  */
7362
7589
  outcome: ConditionOutcome;
7363
- /** The `start.allowed` atom breakdown over the SUPPLIED inputs what to
7364
- * render next to a disabled start affordance. Present iff the definition
7365
- * declares `allowed`. With `unboundReads` non-empty its own `outcome` may
7366
- * be a collapsed provisional answer the top-level `outcome` is the
7367
- * trustworthy one. */
7368
- insight?: ConditionInsight;
7369
- /** The `$fields` entries the predicate reads that `initialFields` doesn't
7370
- * supply — "fill these to decide". Non-empty forces `outcome:
7371
- * 'unevaluable'`. Empty when the definition declares no `allowed`. */
7590
+ /** One result per declared readiness node, in author order. */
7591
+ requirements: StartRequirementEvaluation[];
7592
+ /** The `$fields` entries the predicates read that `initialFields` doesn't
7593
+ * supply "fill these to decide", including a `singleSubject` node's
7594
+ * implicit subject read. Non-empty makes undecided requirements
7595
+ * `'unevaluable'`; a separate definitive refusal still keeps the aggregate
7596
+ * outcome `'unsatisfied'`. Empty when the definition declares no requirements. */
7372
7597
  unboundReads: string[];
7373
7598
  /** Required input entries `initialFields` doesn't fill yet — the rows a
7374
7599
  * `startInstance` now would throw `RequiredFieldNotProvidedError` about. */
@@ -7387,12 +7612,12 @@ export declare interface StartEvaluation {
7387
7612
  * authoring may omit it — so each variant declares it. */
7388
7613
  declare type StartFields = {
7389
7614
  filter?: string | undefined;
7390
- allowed?: string | undefined;
7615
+ requirements?: StartRequirement[] | undefined;
7391
7616
  };
7392
7617
 
7393
7618
  /**
7394
7619
  * Project caller-supplied `initialFields` into the `$fields` map the
7395
- * start-allowed context binds: one key per declared `input`-sourced entry,
7620
+ * start-requirement context binds: one key per declared `input`-sourced entry,
7396
7621
  * resolved through {@link suppliedFieldFor} — the predicate can only ever see
7397
7622
  * a value the input resolution would persist, and an undeclared supplied name
7398
7623
  * never leaks in. Unsupplied (or null-supplied) entries stay unbound, so a
@@ -7500,19 +7725,21 @@ export declare function startKindOf(definition: {
7500
7725
  }): StartKind;
7501
7726
 
7502
7727
  /**
7503
- * Thrown by `startInstance` when the definition's `start.allowed` predicate
7504
- * is not satisfied for the supplied `initialFields` evaluated false, or
7505
- * GROQ null ("can't decide"; fail-closed, `insight.outcome` tells the two
7506
- * apart). Carries the full {@link ConditionInsight} so a consumer renders
7507
- * the same explanation the `evaluateStart` pre-flight would have shown.
7728
+ * Thrown by `startInstance` when one or more declared start requirements are
7729
+ * not satisfied for the supplied `initialFields`. Carries every unmet node's
7730
+ * authored descriptor in declaration order; `evaluateStart` provides the
7731
+ * corresponding per-node outcomes and GROQ insights.
7508
7732
  * There is no override arg — like `fireAction`, you don't bypass a verdict,
7509
7733
  * you change what produces it. Advisory under races like every engine-side
7510
7734
  * check.
7511
7735
  */
7512
7736
  export declare class StartNotAllowedError extends WorkflowError<"start-not-allowed"> {
7513
7737
  readonly definition: string;
7514
- readonly insight: ConditionInsight;
7515
- constructor(args: { definition: string; insight: ConditionInsight });
7738
+ readonly unmetRequirements: RequirementDescriptor[];
7739
+ constructor(args: {
7740
+ definition: string;
7741
+ unmetRequirements: RequirementDescriptor[];
7742
+ });
7516
7743
  }
7517
7744
 
7518
7745
  /**
@@ -7558,43 +7785,57 @@ export declare function startRefusal(definition: {
7558
7785
  lifecycle?: WorkflowLifecycle | undefined;
7559
7786
  }): string | undefined;
7560
7787
 
7788
+ export declare type StartRequirement =
7789
+ | GroqRequirement
7790
+ | SingleSubjectRequirement;
7791
+
7792
+ export declare interface StartRequirementEvaluation extends RequirementDescriptor {
7793
+ /** Whether this requirement is satisfied, unsatisfied, or not yet decidable. */
7794
+ outcome: ConditionOutcome;
7795
+ /** GROQ explanation; absent for non-GROQ requirement kinds. */
7796
+ insight?: ConditionInsight | undefined;
7797
+ }
7798
+
7561
7799
  /**
7562
7800
  * The caller-side half of the start contexts — everything the evaluating
7563
7801
  * surface knows that the definition doesn't. Every member is optional
7564
7802
  * because the surfaces genuinely differ (a pure consumer may hold no clock):
7565
- * except for the subject identity required by `$subjectHasInFlightInstance`,
7566
- * an absent binding evaluates each read of it to GROQ null, and where that
7803
+ * An absent binding evaluates each read of it to GROQ null, and where that
7567
7804
  * null lands decides the verdict — a predicate that can't decide without
7568
7805
  * the binding fails closed, while a count-of-matches clause over values
7569
7806
  * every row stores passes vacuously (in GROQ null equals only null, so the
7570
7807
  * unbound read matches no stored value). The vars themselves are
7571
- * inventoried in `START_FILTER_VARS` / `START_ALLOWED_VARS`; the caller's
7808
+ * inventoried in `START_FILTER_VARS` / `START_REQUIREMENT_VARS`; the caller's
7572
7809
  * `$fields` map is NOT scope — `start.filter` never binds it, and
7573
- * `explainStartAllowed` takes it as its own argument.
7810
+ * `explainStartRequirement` takes it as its own argument.
7574
7811
  */
7575
7812
  export declare interface StartScope {
7576
7813
  /** The engine's tag partition — binds `$tag`. */
7577
7814
  tag?: string | undefined;
7578
7815
  /** ISO clock reading — binds `$now`. */
7579
7816
  now?: string | undefined;
7580
- /** Resource-qualified identity of the prospective subject. Required when
7581
- * `start.filter` reads `$subjectHasInFlightInstance`; unlike a loaded
7817
+ /** Resource-qualified identity of the prospective subject. Unlike a loaded
7582
7818
  * document's bare `_id`, this stays collision-free across resources. */
7583
7819
  subject?: GdrUri | undefined;
7584
7820
  /**
7585
- * The WORKFLOW resource's dataset, for predicates that read it (`*[...]` or
7586
- * a deref) or `$subjectHasInFlightInstance` — invoked lazily only when the
7587
- * predicate needs it. A slice is fine as long as it covers what predicates
7588
- * scan; the engine verbs supply EVERY instance of the tag, completed
7589
- * included — `*` carries no hidden predicate, so authors qualify in-flight
7821
+ * The engine-owned start slice, for predicates that read `*[...]` or for a
7822
+ * `singleSubject` requirement — invoked lazily only when evaluation needs it.
7823
+ * Each row exposes exactly `{definition, subject, completedAt}`; completed
7824
+ * rows are included, so authors qualify in-flight
7590
7825
  * themselves (`!defined(completedAt)`). Absent ⇒ a dataset-reading filter
7591
7826
  * fails closed (this surface cannot see the dataset, so it cannot decide),
7592
- * while a dataset-reading `allowed` THROWS — see
7593
- * {@link explainStartAllowed}.
7827
+ * while a dataset-reading requirement THROWS — see
7828
+ * {@link explainStartRequirement}.
7594
7829
  */
7595
7830
  fetchDataset?: (() => Promise<unknown[]>) | undefined;
7596
7831
  }
7597
7832
 
7833
+ export declare interface StartSliceRow {
7834
+ definition: string;
7835
+ subject: GdrUri | null;
7836
+ completedAt: string | null;
7837
+ }
7838
+
7598
7839
  /**
7599
7840
  * Declared editability of a field — the generic edit seam's gate. Default
7600
7841
  * (absent) is NOT editable: a field is op-only engine working memory unless the
@@ -7636,7 +7877,7 @@ declare const StoredFieldOpSchema: v.VariantSchema<
7636
7877
  {
7637
7878
  readonly scope: v.PicklistSchema<
7638
7879
  readonly ["workflow", "stage", "activity"],
7639
- `Invalid option: expected one of ${string}`
7880
+ string
7640
7881
  >;
7641
7882
  readonly field: v.SchemaWithPipe<
7642
7883
  readonly [
@@ -7658,7 +7899,7 @@ declare const StoredFieldOpSchema: v.VariantSchema<
7658
7899
  {
7659
7900
  readonly scope: v.PicklistSchema<
7660
7901
  readonly ["workflow", "stage", "activity"],
7661
- `Invalid option: expected one of ${string}`
7902
+ string
7662
7903
  >;
7663
7904
  readonly field: v.SchemaWithPipe<
7664
7905
  readonly [
@@ -7679,7 +7920,7 @@ declare const StoredFieldOpSchema: v.VariantSchema<
7679
7920
  {
7680
7921
  readonly scope: v.PicklistSchema<
7681
7922
  readonly ["workflow", "stage", "activity"],
7682
- `Invalid option: expected one of ${string}`
7923
+ string
7683
7924
  >;
7684
7925
  readonly field: v.SchemaWithPipe<
7685
7926
  readonly [
@@ -7701,7 +7942,7 @@ declare const StoredFieldOpSchema: v.VariantSchema<
7701
7942
  {
7702
7943
  readonly scope: v.PicklistSchema<
7703
7944
  readonly ["workflow", "stage", "activity"],
7704
- `Invalid option: expected one of ${string}`
7945
+ string
7705
7946
  >;
7706
7947
  readonly field: v.SchemaWithPipe<
7707
7948
  readonly [
@@ -7729,7 +7970,7 @@ declare const StoredFieldOpSchema: v.VariantSchema<
7729
7970
  {
7730
7971
  readonly scope: v.PicklistSchema<
7731
7972
  readonly ["workflow", "stage", "activity"],
7732
- `Invalid option: expected one of ${string}`
7973
+ string
7733
7974
  >;
7734
7975
  readonly field: v.SchemaWithPipe<
7735
7976
  readonly [
@@ -7759,7 +8000,7 @@ declare const StoredFieldRefSchema: v.StrictObjectSchema<
7759
8000
  {
7760
8001
  readonly scope: v.PicklistSchema<
7761
8002
  readonly ["workflow", "stage", "activity"],
7762
- `Invalid option: expected one of ${string}`
8003
+ string
7763
8004
  >;
7764
8005
  readonly field: v.SchemaWithPipe<
7765
8006
  readonly [
@@ -7794,7 +8035,7 @@ declare const StoredManualTargetSchema: v.VariantSchema<
7794
8035
  {
7795
8036
  readonly scope: v.PicklistSchema<
7796
8037
  readonly ["workflow", "stage", "activity"],
7797
- `Invalid option: expected one of ${string}`
8038
+ string
7798
8039
  >;
7799
8040
  readonly field: v.SchemaWithPipe<
7800
8041
  readonly [
@@ -7822,7 +8063,7 @@ declare const StoredOpSchema: v.VariantSchema<
7822
8063
  {
7823
8064
  readonly scope: v.PicklistSchema<
7824
8065
  readonly ["workflow", "stage", "activity"],
7825
- `Invalid option: expected one of ${string}`
8066
+ string
7826
8067
  >;
7827
8068
  readonly field: v.SchemaWithPipe<
7828
8069
  readonly [
@@ -7844,7 +8085,7 @@ declare const StoredOpSchema: v.VariantSchema<
7844
8085
  {
7845
8086
  readonly scope: v.PicklistSchema<
7846
8087
  readonly ["workflow", "stage", "activity"],
7847
- `Invalid option: expected one of ${string}`
8088
+ string
7848
8089
  >;
7849
8090
  readonly field: v.SchemaWithPipe<
7850
8091
  readonly [
@@ -7865,7 +8106,7 @@ declare const StoredOpSchema: v.VariantSchema<
7865
8106
  {
7866
8107
  readonly scope: v.PicklistSchema<
7867
8108
  readonly ["workflow", "stage", "activity"],
7868
- `Invalid option: expected one of ${string}`
8109
+ string
7869
8110
  >;
7870
8111
  readonly field: v.SchemaWithPipe<
7871
8112
  readonly [
@@ -7887,7 +8128,7 @@ declare const StoredOpSchema: v.VariantSchema<
7887
8128
  {
7888
8129
  readonly scope: v.PicklistSchema<
7889
8130
  readonly ["workflow", "stage", "activity"],
7890
- `Invalid option: expected one of ${string}`
8131
+ string
7891
8132
  >;
7892
8133
  readonly field: v.SchemaWithPipe<
7893
8134
  readonly [
@@ -7915,7 +8156,7 @@ declare const StoredOpSchema: v.VariantSchema<
7915
8156
  {
7916
8157
  readonly scope: v.PicklistSchema<
7917
8158
  readonly ["workflow", "stage", "activity"],
7918
- `Invalid option: expected one of ${string}`
8159
+ string
7919
8160
  >;
7920
8161
  readonly field: v.SchemaWithPipe<
7921
8162
  readonly [
@@ -7946,7 +8187,7 @@ declare const StoredOpSchema: v.VariantSchema<
7946
8187
  >;
7947
8188
  readonly status: v.PicklistSchema<
7948
8189
  readonly ["active", "done", "skipped", "failed"],
7949
- `Invalid option: expected one of ${string}`
8190
+ string
7950
8191
  >;
7951
8192
  },
7952
8193
  undefined
@@ -8019,6 +8260,17 @@ export declare interface SubjectPermissionDenial {
8019
8260
  permission: DocumentValuePermission;
8020
8261
  }
8021
8262
 
8263
+ /** One foreign resource's forecast inputs: the actor's grants there, and the
8264
+ * actor's principal id in THAT resource's own identity namespace. */
8265
+ declare interface SubjectResourceAccess {
8266
+ grants: Grant[];
8267
+ /** What that resource's lake `identity()` returns for the acting token —
8268
+ * resolved through the resource's own routed client, so a dataset
8269
+ * resource contributes the actor's per-project user id and an org-level
8270
+ * resource the account-global id. */
8271
+ actorId: string;
8272
+ }
8273
+
8022
8274
  /**
8023
8275
  * A document the reactive layer should subscribe to, with its GDR
8024
8276
  * exploded so consumers never re-parse: the resource-addressing parts
@@ -8220,10 +8472,7 @@ declare const SubworkflowsSchema: v.StrictObjectSchema<
8220
8472
  * `$subworkflows`) decide.
8221
8473
  */
8222
8474
  readonly onExit: v.OptionalSchema<
8223
- v.PicklistSchema<
8224
- readonly ["detach", "abort"],
8225
- `Invalid option: expected one of ${string}`
8226
- >,
8475
+ v.PicklistSchema<readonly ["detach", "abort"], string>,
8227
8476
  undefined
8228
8477
  >;
8229
8478
  },
@@ -8268,6 +8517,9 @@ export declare interface SweepStaleClaimsResult {
8268
8517
  released: PendingEffect[];
8269
8518
  }
8270
8519
 
8520
+ /** Lake `identity()` sentinel for system-initiated actions. */
8521
+ export declare const SYSTEM_IDENTITY = "<system>";
8522
+
8271
8523
  /**
8272
8524
  * The engine's read-partition invariant as a GROQ predicate: a document is
8273
8525
  * visible when its `tag` equals the caller's `$tag` param. The single
@@ -8438,7 +8690,7 @@ declare type TransitionFields = {
8438
8690
  export declare function tryParseGdr(uri: string): ParsedGdr | undefined;
8439
8691
 
8440
8692
  /**
8441
- * The `$fields` entries a `start.allowed` predicate reads that `fields` does
8693
+ * The `$fields` entries a start GROQ requirement reads that `fields` does
8442
8694
  * not bind — the BINDABILITY rule every pre-flight surface applies before
8443
8695
  * trusting a verdict over possibly-incomplete inputs. GROQ equality against
8444
8696
  * a missing operand collapses to a definitive-looking answer (`null == x` is
@@ -8455,8 +8707,8 @@ export declare function tryParseGdr(uri: string): ParsedGdr | undefined;
8455
8707
  * seed map) — producers bind only own keys with real values, so key presence
8456
8708
  * IS the supplied-ness rule.
8457
8709
  */
8458
- export declare function unboundAllowedReads(
8459
- allowed: string,
8710
+ export declare function unboundRequirementReads(
8711
+ query: string,
8460
8712
  fields: Record<string, unknown>,
8461
8713
  ): string[];
8462
8714
 
@@ -8541,9 +8793,10 @@ declare type ValueExprInternal =
8541
8793
  * physically scoped: a guard doc in a watched content dataset that
8542
8794
  * self-declares the engine's resource id must never reach a verdict. This
8543
8795
  * keeps the advisory layer consistent (verdicts are UX, not enforcement);
8544
- * it is not itself a security boundary. Runs the same query the reactive
8545
- * adapters subscribe with ({@link instanceGuardQuery}), so the stateless and
8546
- * reactive paths agree.
8796
+ * it is not itself a security boundary. Reads through the same filter
8797
+ * definition the reactive adapters subscribe with
8798
+ * ({@link instanceGuardQuery}, the one-id form of the set-shaped
8799
+ * {@link instancesGuardQuery}), so the stateless and reactive paths agree.
8547
8800
  */
8548
8801
  export declare function verdictGuardsForInstance(
8549
8802
  client: WorkflowClient,
@@ -8651,12 +8904,12 @@ export declare const workflow: {
8651
8904
  /**
8652
8905
  * Spawn a new workflow instance from a deployed definition.
8653
8906
  *
8654
- * Two gates run before anything is written, in order: the required-input
8655
- * check a missing `required` input is a CALLER mistake
8656
- * ({@link RequiredFieldNotProvidedError}) then the definition's
8657
- * `start.allowed` permission predicate, whose false/GROQ-null VERDICT
8658
- * throws {@link StartNotAllowedError} (declaring the expression is the
8659
- * opt-in; there is no override arg — pre-flight with `evaluateStart`).
8907
+ * The gates run before anything is written, in order: supplied rows must be
8908
+ * structurally consumable, required inputs must be present
8909
+ * ({@link RequiredFieldNotProvidedError}), then every declared start
8910
+ * requirement is evaluated in author order. All unmet `groq` and
8911
+ * `singleSubject` nodes are reported by one {@link StartNotAllowedError}
8912
+ * (there is no override arg — pre-flight with `evaluateStart`).
8660
8913
  * Per-value SHAPE validation fires during field resolution, after the
8661
8914
  * verdict but still before any write. It does NOT evaluate `start.filter`:
8662
8915
  * that is a read-side visibility rule (see `definitionsForDocument`).
@@ -8788,6 +9041,18 @@ export declare const workflow: {
8788
9041
  abortInstance: (
8789
9042
  rawArgs: Clocked<Telemetered<AbortInstanceArgs & EngineScopeArgs>>,
8790
9043
  ) => Promise<OperationResult>;
9044
+ /**
9045
+ * Admin override — reset a failed (or otherwise terminal) activity in the
9046
+ * instance's current stage: `to: 'active'` re-runs it, `to: 'skipped'`
9047
+ * (the bypass) resolves it so a `$allActivitiesDone`-gated exit can fire.
9048
+ * Defaults to `active`. Cascades after the reset, so an unblocked
9049
+ * transition fires in the same call. ACL gating should be enforced
9050
+ * upstream. `changed: false` means the reset was a no-op (instance
9051
+ * terminal, or the activity already at the target status).
9052
+ */
9053
+ resetActivity: (
9054
+ rawArgs: Clocked<Telemetered<ResetActivityArgs & EngineScopeArgs>>,
9055
+ ) => Promise<OperationResult>;
8791
9056
  /**
8792
9057
  * Fetch a workflow instance by id, scoped to the engine's tag.
8793
9058
  * Throws when the instance doesn't exist or isn't visible to this
@@ -8902,17 +9167,16 @@ export declare const workflow: {
8902
9167
  * For a non-reactive, content-change-driven runtime (a Sanity Function, an
8903
9168
  * Inngest/durable worker, any server) that holds no instances in memory: a
8904
9169
  * document changed; which instances should it `tick`? The watch-set covers
8905
- * the instance itself, its ancestors, and the docs named by
9170
+ * the instance itself, its ancestors, live spawned children, and the docs named by
8906
9171
  * `doc.ref` / `subject` / `doc.refs` / `release.ref` field entries on the
8907
9172
  * workflow scope
8908
9173
  * **and the current stage** — so a hand-rolled GROQ over `fields[]` gets it
8909
- * subtly wrong (misses stage-scope refs, `release.ref`, ancestors).
9174
+ * subtly wrong (misses stage-scope refs, `release.ref`, ancestors, and children).
8910
9175
  *
8911
- * A coarse GROQ prefilter narrows candidates server-side (in-flight,
8912
- * tag-scoped, mentioning the doc anywhere in state); the authoritative match
8913
- * is {@link instanceWatchesDocument}, derived from `collectWatchRefs`, so the
8914
- * reverse stays in lockstep with the forward set and honours the
8915
- * open-stage-only rule the prefilter deliberately over-approximates.
9176
+ * The GROQ filter narrows candidates server-side (in-flight, tag-scoped,
9177
+ * matching workflow/open-stage refs); {@link instanceWatchesDocument},
9178
+ * derived from `collectWatchRefs`, rechecks the result so the reverse stays
9179
+ * in lockstep with the forward set.
8916
9180
  *
8917
9181
  * Single-resource: instances always live in the engine's own resource, so
8918
9182
  * this reads one client (unlike {@link guardsForInstance}, whose guard docs
@@ -8936,15 +9200,13 @@ export declare const workflow: {
8936
9200
  * ({@link applicableDefinitions}): startable ∧ the `subject`-kind entry
8937
9201
  * accepts the doc's `_type` ∧ `start.filter` passes — evaluated in the
8938
9202
  * browse-time-pure start-filter context with `$tag`/`$definition`/`$now`
8939
- * bound and the tag's instance slice (completed included) backing dataset
8940
- * reads. `start.allowed` never participatespermission is a start-time
9203
+ * bound and the tag's projected start slice (completed included) backing dataset
9204
+ * reads. Start requirements never participatereadiness is a start-time
8941
9205
  * question; pre-flight it with {@link workflow.evaluateStart}.
8942
9206
  *
8943
9207
  * Takes the LOADED candidate document, not a ref — applicability evaluates
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
9208
+ * its content under whatever perspective the caller read it with. Surfaces
9209
+ * ALL matches (name ascending), no engine
8948
9210
  * ranking — presenting a picker or auto-picking is consumer policy.
8949
9211
  * Advisory like every engine-side check.
8950
9212
  */
@@ -8955,18 +9217,20 @@ export declare const workflow: {
8955
9217
  * Pre-flight the start gates for a definition + candidate `initialFields` —
8956
9218
  * the read `startInstance` enforces, as a {@link StartEvaluation} a surface
8957
9219
  * can render: `missingRequired` mirrors the input contract
8958
- * ({@link RequiredFieldNotProvidedError}'s rows), and `allowed` /
8959
- * `outcome` / `insight` carry the `start.allowed` verdict with its atom
8960
- * breakdown disable the start affordance on a definitive `false` and say
8961
- * why. BINDABILITY-AWARE for partial mid-form inputs: when the predicate
8962
- * reads an entry `initialFields` doesn't supply, `outcome` is
9220
+ * ({@link RequiredFieldNotProvidedError}'s rows), while `requirements`
9221
+ * preserves every declared node's authored descriptor, outcome, and GROQ
9222
+ * insight when applicable. `allowed` / `outcome` aggregate those ordered
9223
+ * results. BINDABILITY-AWARE for partial mid-form inputs: when a predicate
9224
+ * reads an entry `initialFields` doesn't supply including a
9225
+ * `singleSubject` node's implicit subject read — `outcome` is
8963
9226
  * `'unevaluable'` and `unboundReads` names the entries ("fill these to
8964
9227
  * decide") instead of the collapsed answer GROQ equality would give —
8965
9228
  * this is the ONE deliberate divergence from the gate, where absence is
8966
9229
  * final, not provisional (a rule like `!defined($fields.rush)` genuinely
8967
- * passes there when `rush` is absent). A definition with no
8968
- * `start.allowed` is vacuously allowed, exactly like the verb. Pure read;
8969
- * advisory under races — the enforcement moment is `startInstance` itself.
9230
+ * passes there when `rush` is absent). A definition declaring no start
9231
+ * requirements is vacuously allowed, exactly like
9232
+ * the verb. Pure read; advisory under races — the enforcement moment is
9233
+ * `startInstance` itself.
8970
9234
  */
8971
9235
  evaluateStart: (
8972
9236
  rawArgs: Clocked<EvaluateStartArgs & EngineScopeArgs>,
@@ -9013,6 +9277,16 @@ declare const WORKFLOW_LIFECYCLES: readonly ["standalone", "child"];
9013
9277
  */
9014
9278
  export declare interface WorkflowAccess {
9015
9279
  actor: Actor;
9280
+ /**
9281
+ * The actor's principal id in the workflow resource's OWN identity
9282
+ * namespace — what that resource's lake `identity()` returns for the same
9283
+ * token (the per-project user id for dataset resources; equal to
9284
+ * {@link Actor.id} for org-level resources and robots). In-memory only,
9285
+ * never persisted: it exists for the lake-facing edge — binding
9286
+ * `identity()` in guard previews and grant-filter evaluation so the
9287
+ * advisory verdicts agree with what the lake itself would decide.
9288
+ */
9289
+ localPrincipalId?: string;
9016
9290
  grants?: Grant[];
9017
9291
  }
9018
9292
 
@@ -9026,6 +9300,8 @@ export declare interface WorkflowActionFiredData extends InstanceScopedEventData
9026
9300
  cascaded: number;
9027
9301
  }
9028
9302
 
9303
+ export declare const WorkflowActivityReset: WorkflowTelemetryEvent<WorkflowAdminOverrideData>;
9304
+
9029
9305
  /** Outcome flag for the admin-override events — the attempt emits either way. */
9030
9306
  export declare interface WorkflowAdminOverrideData extends InstanceScopedEventData {
9031
9307
  /** `false` = the override was a no-op (already at the target / already terminal). */
@@ -9107,7 +9383,7 @@ export declare interface WorkflowClient {
9107
9383
  * Optional — present on the real `@sanity/client` and the in-memory test
9108
9384
  * fake. Returns a sibling client with the given config overrides,
9109
9385
  * inheriting everything else from the source (token, apiHost). The engine
9110
- * derives two things from it:
9386
+ * derives three things from it:
9111
9387
  *
9112
9388
  * - **Cross-resource routing** (`resource` + the dataset pair): a sibling
9113
9389
  * for a foreign GDR when `resourceClients` doesn't map it. A client
@@ -9121,6 +9397,10 @@ export declare interface WorkflowClient {
9121
9397
  * rebound and is used as-is — it must be built to serve
9122
9398
  * {@link ENGINE_API_VERSION} already; older dated versions fail
9123
9399
  * silently incomplete, not loud.
9400
+ * - **Effect request attribution** (`requestTagPrefix`): handlers receive a
9401
+ * derived client whose untagged traffic carries the effect tag while the
9402
+ * caller's own client remains untouched. A client without `withConfig`
9403
+ * uses the structural request wrapper instead.
9124
9404
  *
9125
9405
  * Dataset resources carry the `{projectId, dataset}` pair alongside
9126
9406
  * `resource`: the real client routes by `resource` (it takes precedence in
@@ -9129,7 +9409,7 @@ export declare interface WorkflowClient {
9129
9409
  * only — a canvas/media-library derivation on the fake aliases the current
9130
9410
  * store until the fake learns `resource` upstream.
9131
9411
  */
9132
- withConfig?: (config: WorkflowClientConfig) => WorkflowClient;
9412
+ withConfig?: (config: WorkflowClientConfig) => this;
9133
9413
  /**
9134
9414
  * Optional — present on the real `@sanity/client`, absent on the
9135
9415
  * in-memory test client. The engine probes for it when auto-resolving
@@ -9155,14 +9435,22 @@ export declare interface WorkflowClient {
9155
9435
  /**
9156
9436
  * The config bag {@link WorkflowClient.withConfig} accepts — all optional: a
9157
9437
  * resource rebind (`resource`, plus the dataset pair for dataset targets), an
9158
- * `apiVersion` rebind, or both. Everything omitted is inherited from the
9159
- * source client.
9438
+ * `apiVersion` rebind, a request-tag prefix, or any combination. Everything
9439
+ * omitted is inherited from the source client.
9160
9440
  */
9161
9441
  export declare interface WorkflowClientConfig {
9162
9442
  resource?: WorkflowResource;
9163
9443
  projectId?: string;
9164
9444
  dataset?: string;
9165
9445
  apiVersion?: string;
9446
+ requestTagPrefix?: string;
9447
+ /**
9448
+ * Host selection, mirroring `@sanity/client`: `false` derives a sibling
9449
+ * addressing the global API host instead of the project host. The engine
9450
+ * uses this for exactly one read — resolving the acting token's
9451
+ * account-global identity from the global `/users/me`.
9452
+ */
9453
+ useProjectHostname?: boolean;
9166
9454
  }
9167
9455
 
9168
9456
  export declare interface WorkflowCommitOptions {
@@ -9212,7 +9500,7 @@ declare const WorkflowConfigSchema: v.ObjectSchema<
9212
9500
  ]
9213
9501
  >;
9214
9502
  readonly expectedMinReaderModel: v.OptionalSchema<
9215
- v.CustomSchema<2, undefined>,
9503
+ v.CustomSchema<4, undefined>,
9216
9504
  undefined
9217
9505
  >;
9218
9506
  readonly tag: v.SchemaWithPipe<
@@ -9499,7 +9787,7 @@ declare const WorkflowConfigSchema: v.ObjectSchema<
9499
9787
  v.MinLengthAction<
9500
9788
  {
9501
9789
  name: string;
9502
- expectedMinReaderModel?: 2 | undefined;
9790
+ expectedMinReaderModel?: 4 | undefined;
9503
9791
  tag: string;
9504
9792
  workflowResource:
9505
9793
  | {
@@ -9560,7 +9848,7 @@ declare const WorkflowConfigSchema: v.ObjectSchema<
9560
9848
  v.CheckAction<
9561
9849
  {
9562
9850
  name: string;
9563
- expectedMinReaderModel?: 2 | undefined;
9851
+ expectedMinReaderModel?: 4 | undefined;
9564
9852
  tag: string;
9565
9853
  workflowResource:
9566
9854
  | {
@@ -9619,7 +9907,7 @@ declare const WorkflowConfigSchema: v.ObjectSchema<
9619
9907
  issue: v.CheckIssue<
9620
9908
  {
9621
9909
  name: string;
9622
- expectedMinReaderModel?: 2 | undefined;
9910
+ expectedMinReaderModel?: 4 | undefined;
9623
9911
  tag: string;
9624
9912
  workflowResource:
9625
9913
  | {
@@ -9680,7 +9968,7 @@ declare const WorkflowConfigSchema: v.ObjectSchema<
9680
9968
  v.CheckAction<
9681
9969
  {
9682
9970
  name: string;
9683
- expectedMinReaderModel?: 2 | undefined;
9971
+ expectedMinReaderModel?: 4 | undefined;
9684
9972
  tag: string;
9685
9973
  workflowResource:
9686
9974
  | {
@@ -9739,7 +10027,7 @@ declare const WorkflowConfigSchema: v.ObjectSchema<
9739
10027
  issue: v.CheckIssue<
9740
10028
  {
9741
10029
  name: string;
9742
- expectedMinReaderModel?: 2 | undefined;
10030
+ expectedMinReaderModel?: 4 | undefined;
9743
10031
  tag: string;
9744
10032
  workflowResource:
9745
10033
  | {
@@ -10089,7 +10377,7 @@ export declare interface WorkflowInstance extends SanityDocument {
10089
10377
  modelVersion?: number;
10090
10378
  /**
10091
10379
  * Reader floor — the oldest engine data model that can safely interpret
10092
- * this document. Derived from features actually present, bounded by
10380
+ * this document. No lower than the writer's unconditional
10093
10381
  * {@link DATA_MODEL_MIN_READER}, and written alongside
10094
10382
  * {@link WorkflowInstance.modelVersion}. Full persists never lower it.
10095
10383
  */