@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.
@@ -20,6 +20,317 @@ function _interopNamespaceCompat(e) {
20
20
 
21
21
  var v__namespace = /* @__PURE__ */ _interopNamespaceCompat(v);
22
22
 
23
+ class WorkflowError extends Error {
24
+ kind;
25
+ constructor(kind, message, options) {
26
+ super(message, options), this.kind = kind;
27
+ }
28
+ }
29
+
30
+ class ContractViolationError extends WorkflowError {
31
+ constructor(message) {
32
+ super("contract-violation", message), this.name = "ContractViolationError";
33
+ }
34
+ }
35
+
36
+ class InstanceNotFoundError extends WorkflowError {
37
+ instanceId;
38
+ constructor(args) {
39
+ super("instance-not-found", `Workflow instance ${args.instanceId} not found${args.detail ? ` (${args.detail})` : ""}`),
40
+ this.name = "InstanceNotFoundError", this.instanceId = args.instanceId;
41
+ }
42
+ }
43
+
44
+ class DefinitionNotFoundError extends WorkflowError {
45
+ definition;
46
+ version;
47
+ constructor(args) {
48
+ super("definition-not-found", args.version !== void 0 ? `Workflow definition ${args.definition} v${args.version} not deployed` : `Workflow definition ${args.definition} has no deployed versions`),
49
+ this.name = "DefinitionNotFoundError", this.definition = args.definition, args.version !== void 0 && (this.version = args.version);
50
+ }
51
+ }
52
+
53
+ class SpawnContractsInvalidError extends WorkflowError {
54
+ issues;
55
+ constructor(args) {
56
+ super("spawn-contracts-invalid", args.message), this.name = "SpawnContractsInvalidError",
57
+ this.issues = args.issues;
58
+ }
59
+ }
60
+
61
+ class DefinitionInUseError extends WorkflowError {
62
+ definition;
63
+ blockedBy;
64
+ constructor(args) {
65
+ super("definition-in-use", definitionInUseMessage(args.definition, args.blockedBy)),
66
+ this.name = "DefinitionInUseError", this.definition = args.definition, this.blockedBy = args.blockedBy;
67
+ }
68
+ }
69
+
70
+ function definitionInUseMessage(definition, blockedBy) {
71
+ if (blockedBy.reason === "non-terminal-instances") {
72
+ const head = blockedBy.instanceIds.slice(0, 3).join(", "), preview = blockedBy.instanceIds.length > 3 ? `${head}, …` : head;
73
+ return `Cannot delete ${definition}: ${blockedBy.instanceIds.length} non-terminal instance(s) exist (${preview}). Pass cascade to abort them first — instances are aborted in place, never deleted.`;
74
+ }
75
+ const names = blockedBy.referrers.map(r => `${r.definition} v${r.version}`).join(", ");
76
+ return `Cannot delete ${definition}: still spawn-referenced by deployed definition(s) ${names}. Delete or redeploy the referrer(s) first.`;
77
+ }
78
+
79
+ class EffectNotFoundError extends WorkflowError {
80
+ instanceId;
81
+ effectKey;
82
+ settled;
83
+ constructor(args) {
84
+ super("effect-not-found", effectNotFoundMessage(args)), this.name = "EffectNotFoundError",
85
+ this.instanceId = args.instanceId, this.effectKey = args.effectKey, args.settled !== void 0 && (this.settled = args.settled);
86
+ }
87
+ }
88
+
89
+ function effectNotFoundMessage(args) {
90
+ const base = `Pending effect "${args.effectKey}" not found on instance ${args.instanceId}`;
91
+ if (args.settled === void 0) return base;
92
+ const cause = args.settled.detail !== void 0 ? ` (${args.settled.detail})` : "";
93
+ return args.settled.status === "cancelled" ? `${base} — it was cancelled at ${args.settled.ranAt}${cause}` : `${base} — it already settled "${args.settled.status}" at ${args.settled.ranAt}${cause}`;
94
+ }
95
+
96
+ function errorMessage(err) {
97
+ return (err instanceof Error ? err.message : String(err)).replace(/[^\P{Cc}\n\t]/gu, "");
98
+ }
99
+
100
+ function rethrowWithContext(err, context) {
101
+ throw new Error(`${context}: ${errorMessage(err)}`, {
102
+ cause: err
103
+ });
104
+ }
105
+
106
+ const WORKFLOW_INSTANCE_TYPE = "sanity.workflow.instance";
107
+
108
+ function terminalState(instance) {
109
+ return instance.abortedAt !== void 0 ? "aborted" : instance.completedAt !== void 0 ? "completed" : "in-flight";
110
+ }
111
+
112
+ function isUnprimed(instance) {
113
+ return instance.stages.length === 0 && terminalState(instance) === "in-flight";
114
+ }
115
+
116
+ function parseDefinitionSnapshotValue(instance) {
117
+ try {
118
+ return JSON.parse(instance.definitionSnapshot);
119
+ } catch (err) {
120
+ rethrowWithContext(err, `Failed to parse definitionSnapshot on instance "${instance._id}"`);
121
+ }
122
+ }
123
+
124
+ function parseDefinitionSnapshot(instance) {
125
+ return parseDefinitionSnapshotValue(instance);
126
+ }
127
+
128
+ function parentRef(instance) {
129
+ return instance.ancestors.at(-1);
130
+ }
131
+
132
+ const DATA_MODEL_VERSION = 3, DATA_MODEL_MIN_READER = 2, READER_MODEL_ROLLOUT_URL = "https://github.com/sanity-io/workflows/blob/main/docs/reader-model-rollout.md";
133
+
134
+ class ReaderModelAcknowledgementError extends WorkflowError {
135
+ code="WORKFLOW_READER_MODEL_ACKNOWLEDGEMENT_MISMATCH";
136
+ expectedMinReaderModel;
137
+ engineMinReaderModel=DATA_MODEL_MIN_READER;
138
+ engineModelVersion=DATA_MODEL_VERSION;
139
+ documentationUrl=READER_MODEL_ROLLOUT_URL;
140
+ constructor(expectedMinReaderModel, context = "Deployment") {
141
+ const expected = expectedMinReaderModel === void 0 ? "missing" : String(expectedMinReaderModel);
142
+ super("reader-model-acknowledgement", `${context} expected reader floor ${expected}; the installed engine requires acknowledgement ${DATA_MODEL_MIN_READER}. Dependency upgrades can change writer compatibility. Upgrade all readers and Functions before accepting a higher floor; after verifying the rollout, change the literal in deployment configuration. ${READER_MODEL_ROLLOUT_URL}`),
143
+ this.name = "ReaderModelAcknowledgementError", this.expectedMinReaderModel = expectedMinReaderModel;
144
+ }
145
+ }
146
+
147
+ function assertReaderModelAcknowledgement(expectedMinReaderModel, context) {
148
+ if (typeof expectedMinReaderModel != "number" || !Number.isFinite(expectedMinReaderModel) || !Number.isInteger(expectedMinReaderModel) || expectedMinReaderModel < 0 || expectedMinReaderModel !== DATA_MODEL_MIN_READER) throw new ReaderModelAcknowledgementError(expectedMinReaderModel, context);
149
+ }
150
+
151
+ const DATA_MODEL_CHANGES = Object.freeze([ Object.freeze({
152
+ id: "governed-model-stamps",
153
+ introducedInModel: 1,
154
+ minReaderModel: 0,
155
+ documentTypes: Object.freeze([ "definition", "instance" ]),
156
+ compatibility: "additive",
157
+ applicability: "unconditional",
158
+ summary: "Definition and instance documents carry model provenance and reader-floor stamps."
159
+ }), Object.freeze({
160
+ id: "subject-field-kind",
161
+ introducedInModel: 2,
162
+ minReaderModel: 0,
163
+ documentTypes: Object.freeze([ "definition", "instance" ]),
164
+ compatibility: "additive",
165
+ applicability: "detectable",
166
+ summary: "A workflow-level subject field identifies the document a workflow is about."
167
+ }), Object.freeze({
168
+ id: "typed-scalar-choice-lists",
169
+ introducedInModel: 2,
170
+ minReaderModel: 2,
171
+ documentTypes: Object.freeze([ "definition", "instance" ]),
172
+ compatibility: "reader-floor",
173
+ applicability: "detectable",
174
+ summary: "Scalar fields may constrain writes to a persisted typed choice list."
175
+ }), Object.freeze({
176
+ id: "action-semantics",
177
+ introducedInModel: 2,
178
+ minReaderModel: 0,
179
+ documentTypes: Object.freeze([ "definition" ]),
180
+ compatibility: "additive",
181
+ applicability: "detectable",
182
+ summary: "Ordinary actions may carry a closed bag of advisory workflow semantics."
183
+ }), Object.freeze({
184
+ id: "inclusive-scalar-bounds",
185
+ introducedInModel: 2,
186
+ minReaderModel: 2,
187
+ documentTypes: Object.freeze([ "definition", "instance" ]),
188
+ compatibility: "reader-floor",
189
+ applicability: "detectable",
190
+ summary: "String, text, and number values may carry persisted inclusive bounds."
191
+ }), Object.freeze({
192
+ id: "progress-field-kind",
193
+ introducedInModel: 3,
194
+ minReaderModel: 0,
195
+ documentTypes: Object.freeze([ "definition", "instance" ]),
196
+ compatibility: "additive",
197
+ applicability: "detectable",
198
+ summary: "A progress field kind carries application-defined 0–100 completion."
199
+ }), Object.freeze({
200
+ id: "effect-claim-tokens",
201
+ introducedInModel: 3,
202
+ minReaderModel: 0,
203
+ documentTypes: Object.freeze([ "instance" ]),
204
+ compatibility: "additive",
205
+ applicability: "detectable",
206
+ summary: "Pending-effect claims carry an exact-claim token gating mid-dispatch state reports."
207
+ }) ]);
208
+
209
+ function recordOf(value) {
210
+ return value !== null && typeof value == "object" && !Array.isArray(value) ? value : void 0;
211
+ }
212
+
213
+ function recordsAt(record, key) {
214
+ const value = record[key];
215
+ return Array.isArray(value) ? value.map(recordOf).filter(item => item !== void 0) : [];
216
+ }
217
+
218
+ function nestedFieldEntries(entries) {
219
+ return entries.flatMap(entry => [ entry, ...nestedFieldEntries(recordsAt(entry, "fields")), ...nestedFieldEntries(recordsAt(entry, "of")) ]);
220
+ }
221
+
222
+ function parsedDefinitionSnapshot(root) {
223
+ if (typeof root.definitionSnapshot == "string") return recordOf(parseDefinitionSnapshotValue({
224
+ _id: typeof root._id == "string" ? root._id : "<unknown instance>",
225
+ definitionSnapshot: root.definitionSnapshot
226
+ }));
227
+ }
228
+
229
+ function persistedFieldEntries(document) {
230
+ const root = recordOf(document);
231
+ if (root === void 0) return [];
232
+ const snapshot = parsedDefinitionSnapshot(root), roots = snapshot === void 0 ? [ root ] : [ root, snapshot ], stages = roots.flatMap(candidate => recordsAt(candidate, "stages")), activities = stages.flatMap(stage => recordsAt(stage, "activities")), actions = activities.flatMap(activity => recordsAt(activity, "actions")), effects = actions.flatMap(action => recordsAt(action, "effects"));
233
+ return nestedFieldEntries([ ...roots.flatMap(candidate => recordsAt(candidate, "fields")), ...stages.flatMap(stage => recordsAt(stage, "fields")), ...activities.flatMap(activity => recordsAt(activity, "fields")), ...actions.flatMap(action => recordsAt(action, "params")), ...effects.flatMap(effect => recordsAt(effect, "outputs")) ]);
234
+ }
235
+
236
+ function hasChoiceList(document) {
237
+ return persistedFieldEntries(document).some(entry => {
238
+ const options = recordOf(entry.options);
239
+ return options !== void 0 && Array.isArray(options.list);
240
+ });
241
+ }
242
+
243
+ function hasFieldKind(document, kind) {
244
+ return persistedFieldEntries(document).some(entry => entry.type === kind || entry._type === kind);
245
+ }
246
+
247
+ function hasActionSemantics(document) {
248
+ const root = recordOf(document);
249
+ return root === void 0 ? !1 : recordsAt(root, "stages").flatMap(stage => recordsAt(stage, "activities")).flatMap(activity => recordsAt(activity, "actions")).some(action => Array.isArray(action.semantics));
250
+ }
251
+
252
+ function hasScalarValidation(document) {
253
+ return persistedFieldEntries(document).some(entry => {
254
+ const validation = recordOf(entry.validation);
255
+ return typeof validation?.min == "number" || typeof validation?.max == "number";
256
+ });
257
+ }
258
+
259
+ function hasClaimTokens(document) {
260
+ const root = recordOf(document);
261
+ return root === void 0 ? !1 : recordsAt(root, "pendingEffects").some(entry => {
262
+ const claim = recordOf(entry.claim);
263
+ return claim !== void 0 && typeof claim.claimToken == "string";
264
+ });
265
+ }
266
+
267
+ const featureDetectors = {
268
+ "governed-model-stamps": () => !0,
269
+ "subject-field-kind": document => hasFieldKind(document, "subject"),
270
+ "typed-scalar-choice-lists": hasChoiceList,
271
+ "action-semantics": hasActionSemantics,
272
+ "inclusive-scalar-bounds": hasScalarValidation,
273
+ "progress-field-kind": document => hasFieldKind(document, "progress"),
274
+ "effect-claim-tokens": hasClaimTokens
275
+ };
276
+
277
+ function requiredModelFeatures(documentType, document) {
278
+ return DATA_MODEL_CHANGES.filter(change => change.documentTypes.some(candidate => candidate === documentType) && featureDetectors[change.id](document));
279
+ }
280
+
281
+ function requiredReaderModel(documentType, document) {
282
+ return Math.max(0, ...requiredModelFeatures(documentType, document).map(change => change.minReaderModel));
283
+ }
284
+
285
+ function modelStampFor(args) {
286
+ return {
287
+ modelVersion: DATA_MODEL_VERSION,
288
+ minReaderModel: Math.max(args.storedMinReaderModel ?? 0, requiredReaderModel(args.documentType, args.document))
289
+ };
290
+ }
291
+
292
+ function fieldTreeShape(value) {
293
+ if (Array.isArray(value)) return value.map(fieldTreeShape);
294
+ if (value === null) return "null";
295
+ if (typeof value == "object") {
296
+ const record = value;
297
+ return Object.fromEntries(Object.keys(record).toSorted().map(key => [ key, fieldTreeShape(record[key]) ]));
298
+ }
299
+ return typeof value;
300
+ }
301
+
302
+ function modelVersionOf(doc) {
303
+ const stamp = doc.modelVersion;
304
+ return typeof stamp == "number" ? stamp : 0;
305
+ }
306
+
307
+ function minReaderModelOf(doc) {
308
+ const floor = doc.minReaderModel;
309
+ return typeof floor == "number" ? floor : modelVersionOf(doc);
310
+ }
311
+
312
+ class ModelVersionAheadError extends WorkflowError {
313
+ documentId;
314
+ documentModelVersion;
315
+ requiredReaderModel;
316
+ engineModelVersion;
317
+ constructor(args) {
318
+ super("model-version-ahead", `Document "${args.documentId}" was written by engine data model ${args.documentModelVersion} and requires a reader at model ${args.requiredReaderModel} or newer; this engine reads up to model ${DATA_MODEL_VERSION}. Upgrade @sanity/workflow-engine to a version that understands it.`),
319
+ this.name = "ModelVersionAheadError", this.documentId = args.documentId, this.documentModelVersion = args.documentModelVersion,
320
+ this.requiredReaderModel = args.requiredReaderModel, this.engineModelVersion = DATA_MODEL_VERSION;
321
+ }
322
+ }
323
+
324
+ function assertReadableModel(doc) {
325
+ const documentReaderModel = minReaderModelOf(doc);
326
+ if (documentReaderModel > DATA_MODEL_VERSION) throw new ModelVersionAheadError({
327
+ documentId: doc._id,
328
+ documentModelVersion: modelVersionOf(doc),
329
+ requiredReaderModel: documentReaderModel
330
+ });
331
+ return doc;
332
+ }
333
+
23
334
  function isCascadeFired(action) {
24
335
  return action.when !== void 0;
25
336
  }
@@ -40,16 +351,6 @@ function driverKind(actor) {
40
351
  return actor.kind === "person" || actor.kind === "agent" ? actor.kind : "service";
41
352
  }
42
353
 
43
- function errorMessage(err) {
44
- return (err instanceof Error ? err.message : String(err)).replace(/[^\P{Cc}\n\t]/gu, "");
45
- }
46
-
47
- function rethrowWithContext(err, context) {
48
- throw new Error(`${context}: ${errorMessage(err)}`, {
49
- cause: err
50
- });
51
- }
52
-
53
354
  function andConditions(parts) {
54
355
  const present = parts.filter(p => p !== void 0);
55
356
  if (present.length !== 0) return present.length === 1 ? present[0] : present.map(p => `(${p})`).join(" && ");
@@ -250,71 +551,6 @@ function isGdr(value) {
250
551
  return typeof value == "object" && value !== null && typeof value.id == "string" && typeof value.type == "string";
251
552
  }
252
553
 
253
- class WorkflowError extends Error {
254
- kind;
255
- constructor(kind, message, options) {
256
- super(message, options), this.kind = kind;
257
- }
258
- }
259
-
260
- class ContractViolationError extends WorkflowError {
261
- constructor(message) {
262
- super("contract-violation", message), this.name = "ContractViolationError";
263
- }
264
- }
265
-
266
- class InstanceNotFoundError extends WorkflowError {
267
- instanceId;
268
- constructor(args) {
269
- super("instance-not-found", `Workflow instance ${args.instanceId} not found${args.detail ? ` (${args.detail})` : ""}`),
270
- this.name = "InstanceNotFoundError", this.instanceId = args.instanceId;
271
- }
272
- }
273
-
274
- class DefinitionNotFoundError extends WorkflowError {
275
- definition;
276
- version;
277
- constructor(args) {
278
- super("definition-not-found", args.version !== void 0 ? `Workflow definition ${args.definition} v${args.version} not deployed` : `Workflow definition ${args.definition} has no deployed versions`),
279
- this.name = "DefinitionNotFoundError", this.definition = args.definition, args.version !== void 0 && (this.version = args.version);
280
- }
281
- }
282
-
283
- class DefinitionInUseError extends WorkflowError {
284
- definition;
285
- blockedBy;
286
- constructor(args) {
287
- super("definition-in-use", definitionInUseMessage(args.definition, args.blockedBy)),
288
- this.name = "DefinitionInUseError", this.definition = args.definition, this.blockedBy = args.blockedBy;
289
- }
290
- }
291
-
292
- function definitionInUseMessage(definition, blockedBy) {
293
- if (blockedBy.reason === "non-terminal-instances") {
294
- const head = blockedBy.instanceIds.slice(0, 3).join(", "), preview = blockedBy.instanceIds.length > 3 ? `${head}, …` : head;
295
- return `Cannot delete ${definition}: ${blockedBy.instanceIds.length} non-terminal instance(s) exist (${preview}). Pass cascade to abort them first — instances are aborted in place, never deleted.`;
296
- }
297
- const names = blockedBy.referrers.map(r => `${r.definition} v${r.version}`).join(", ");
298
- return `Cannot delete ${definition}: still spawn-referenced by deployed definition(s) ${names}. Delete or redeploy the referrer(s) first.`;
299
- }
300
-
301
- class EffectNotFoundError extends WorkflowError {
302
- instanceId;
303
- effectKey;
304
- settled;
305
- constructor(args) {
306
- super("effect-not-found", effectNotFoundMessage(args)), this.name = "EffectNotFoundError",
307
- this.instanceId = args.instanceId, this.effectKey = args.effectKey, args.settled !== void 0 && (this.settled = args.settled);
308
- }
309
- }
310
-
311
- function effectNotFoundMessage(args) {
312
- const base = `Pending effect "${args.effectKey}" not found on instance ${args.instanceId}`;
313
- if (args.settled === void 0) return base;
314
- const cause = args.settled.detail !== void 0 ? ` (${args.settled.detail})` : "";
315
- return args.settled.status === "cancelled" ? `${base} — it was cancelled at ${args.settled.ranAt}${cause}` : `${base} — it already settled "${args.settled.status}" at ${args.settled.ranAt}${cause}`;
316
- }
317
-
318
554
  const LAKE_ID_SEGMENT_RE = /^[a-z0-9][a-z0-9-]*$/, LAKE_ID_SEGMENT_GLOSS = "ASCII lowercase + digits + dashes, no leading dash, no dots";
319
555
 
320
556
  function validateTag(tag) {
@@ -337,7 +573,13 @@ function asPredicate(validate) {
337
573
  };
338
574
  }
339
575
 
340
- const isValidTag = asPredicate(validateTag), isValidAliasName = asPredicate(validateResourceAliasName), isValidDatasetId = asPredicate(datasetResourceParts), WorkflowResourceSchema = v__namespace.variant("type", [ v__namespace.object({
576
+ const isValidTag = asPredicate(validateTag), isValidAliasName = asPredicate(validateResourceAliasName), isValidDatasetId = asPredicate(datasetResourceParts);
577
+
578
+ function lakeSegment(label) {
579
+ return v__namespace.pipe(v__namespace.string(), v__namespace.nonEmpty(), v__namespace.check(isValidTag, `invalid ${label} — ${LAKE_ID_SEGMENT_GLOSS}`));
580
+ }
581
+
582
+ const WorkflowResourceSchema = v__namespace.variant("type", [ v__namespace.object({
341
583
  type: v__namespace.literal("dataset"),
342
584
  id: v__namespace.pipe(NonEmptyString$1, v__namespace.check(isValidDatasetId, 'invalid dataset resource id — expected "<projectId>.<dataset>"'))
343
585
  }), v__namespace.object({
@@ -353,13 +595,46 @@ const isValidTag = asPredicate(validateTag), isValidAliasName = asPredicate(vali
353
595
  name: v__namespace.pipe(NonEmptyString$1, v__namespace.check(isValidAliasName, "invalid resource handle name — lowercase letters, digits and dashes only, no leading dash")),
354
596
  resource: WorkflowResourceSchema
355
597
  }), DefinitionSchema = v__namespace.custom(input => typeof input == "object" && input !== null && typeof input.name == "string", "expected a workflow definition (an object with a string `name`)"), DeploymentSchema = v__namespace.object({
356
- name: NonEmptyString$1,
357
- tag: v__namespace.pipe(v__namespace.string(), v__namespace.nonEmpty(), v__namespace.check(isValidTag, "invalid tag — lowercase letters, digits and dashes only, no leading dash, no dots")),
598
+ name: lakeSegment("name"),
599
+ expectedMinReaderModel: v__namespace.optional(v__namespace.custom(() => !0), void 0),
600
+ tag: lakeSegment("tag"),
358
601
  workflowResource: WorkflowResourceSchema,
359
- resourceAliases: v__namespace.optional(v__namespace.pipe(v__namespace.array(ResourceBindingSchema), v__namespace.check(bindings => new Set(bindings.map(binding => binding.name)).size === bindings.length, "duplicate resource handle name — each binding name must be unique within a deployment"))),
602
+ resourceAliases: v__namespace.optional(v__namespace.pipe(v__namespace.array(ResourceBindingSchema), v__namespace.check(bindings => duplicateHandleMessage(bindings) === void 0, issue => duplicateHandleMessage(issue.input) ?? "duplicate resource handle name"))),
360
603
  definitions: v__namespace.pipe(v__namespace.array(DefinitionSchema), v__namespace.minLength(1, "a deployment needs at least one definition"))
361
- }), TelemetryLoggerSchema = v__namespace.custom(input => typeof input == "object" && input !== null && typeof input.log == "function", "expected a telemetry logger (an object with a `log` function)"), WorkflowConfigSchema = v__namespace.object({
362
- deployments: v__namespace.pipe(v__namespace.array(DeploymentSchema), v__namespace.minLength(1, "a config needs at least one deployment"), v__namespace.check(deployments => new Set(deployments.map(deployment => deployment.tag)).size === deployments.length, "duplicate deployment tag — each deployment must use a unique tag")),
604
+ });
605
+
606
+ function firstDuplicatePair(items, keyOf) {
607
+ const seen = /* @__PURE__ */ new Map;
608
+ for (const item of items) {
609
+ const key = keyOf(item), earlier = seen.get(key);
610
+ if (earlier !== void 0) return [ earlier, item ];
611
+ seen.set(key, item);
612
+ }
613
+ }
614
+
615
+ function duplicateHandleMessage(bindings) {
616
+ const pair = firstDuplicatePair(bindings, binding => binding.name);
617
+ if (pair !== void 0) return `duplicate resource handle name "${pair[1].name}" — each binding name must be unique within a deployment`;
618
+ }
619
+
620
+ function duplicateNameMessage(deployments) {
621
+ const pair = firstDuplicatePair(deployments, deployment => deployment.name);
622
+ if (pair !== void 0) return `duplicate deployment name "${pair[1].name}" — each deployment must use a unique name`;
623
+ }
624
+
625
+ function partitionKey(deployment) {
626
+ return `${resourceGdr(deployment.workflowResource)} ${deployment.tag}`;
627
+ }
628
+
629
+ function partitionCollisionMessage(deployments) {
630
+ const pair = firstDuplicatePair(deployments, partitionKey);
631
+ if (pair === void 0) return;
632
+ const [first, second] = pair;
633
+ return `deployments "${first.name}" and "${second.name}" share workflow resource + tag "${second.tag}" — both would write into the same partition; change one deployment’s tag or resource`;
634
+ }
635
+
636
+ const TelemetryLoggerSchema = v__namespace.custom(input => typeof input == "object" && input !== null && typeof input.log == "function", "expected a telemetry logger (an object with a `log` function)"), WorkflowConfigSchema = v__namespace.object({
637
+ deployments: v__namespace.pipe(v__namespace.array(DeploymentSchema), v__namespace.minLength(1, "a config needs at least one deployment"), v__namespace.check(deployments => duplicateNameMessage(deployments) === void 0, issue => duplicateNameMessage(issue.input) ?? "duplicate deployment name"), v__namespace.check(deployments => partitionCollisionMessage(deployments) === void 0, issue => partitionCollisionMessage(issue.input) ?? "duplicate deployment partition")),
363
638
  telemetry: v__namespace.optional(TelemetryLoggerSchema)
364
639
  });
365
640
 
@@ -596,6 +871,8 @@ function desugarFieldEntry({entry: entry, path: path, ctx: ctx}) {
596
871
  required: entry.required,
597
872
  initialValue: entry.initialValue,
598
873
  editable: editable,
874
+ options: entry.options,
875
+ validation: entry.validation,
599
876
  types: entry.types,
600
877
  fields: entry.fields,
601
878
  of: entry.of
@@ -738,7 +1015,7 @@ function desugarActivity({activity: activity, path: path, stageEnv: stageEnv, ct
738
1015
  };
739
1016
  }
740
1017
 
741
- const TARGET_DOC_KINDS = [ "doc.ref", "doc.refs", "release.ref" ];
1018
+ const TARGET_DOC_KINDS = [ "doc.ref", "doc.refs", "subject", "release.ref" ];
742
1019
 
743
1020
  function desugarTarget({target: target, env: env, path: path, ctx: ctx}) {
744
1021
  if (target === void 0 || target.type === "url") return target;
@@ -759,18 +1036,15 @@ function desugarTarget({target: target, env: env, path: path, ctx: ctx}) {
759
1036
  };
760
1037
  }
761
1038
 
762
- function desugarAction({action: action, path: path, env: env, activityName: activityName, ctx: ctx}) {
763
- if ("type" in action) return desugarClaimAction({
764
- action: action,
765
- path: path,
766
- env: env,
767
- ctx: ctx
768
- });
769
- action.roles !== void 0 && action.roles.length === 0 && ctx.issues.push({
1039
+ function reportEmptyActionRoles({action: action, path: path, ctx: ctx}) {
1040
+ action.roles === void 0 || action.roles.length > 0 || ctx.issues.push({
770
1041
  path: [ ...path, "roles" ],
771
1042
  message: "roles: [] names no roles — omit it to allow any identity, or list at least one role"
772
1043
  });
773
- const cascadeFired = isCascadeFired(action), filter = cascadeFired ? action.filter : andConditions([ rolesCondition(action.roles, ctx.roleAliases), action.filter ]), ops = desugarOps({
1044
+ }
1045
+
1046
+ function desugarActionOps(args) {
1047
+ const {action: action, path: path, env: env, activityName: activityName, ctx: ctx} = args, ops = desugarOps({
774
1048
  ops: action.ops,
775
1049
  path: [ ...path, "ops" ],
776
1050
  env: env,
@@ -781,9 +1055,32 @@ function desugarAction({action: action, path: path, env: env, activityName: acti
781
1055
  type: "status.set",
782
1056
  activity: activityName,
783
1057
  status: action.status
784
- }), {
1058
+ }), ops;
1059
+ }
1060
+
1061
+ function desugarAction({action: action, path: path, env: env, activityName: activityName, ctx: ctx}) {
1062
+ if ("type" in action) return desugarClaimAction({
1063
+ action: action,
1064
+ path: path,
1065
+ env: env,
1066
+ ctx: ctx
1067
+ });
1068
+ reportEmptyActionRoles({
1069
+ action: action,
1070
+ path: path,
1071
+ ctx: ctx
1072
+ });
1073
+ const cascadeFired = isCascadeFired(action), filter = cascadeFired ? action.filter : andConditions([ rolesCondition(action.roles, ctx.roleAliases), action.filter ]), ops = desugarActionOps({
1074
+ action: action,
1075
+ path: path,
1076
+ env: env,
1077
+ activityName: activityName,
1078
+ ctx: ctx
1079
+ });
1080
+ return {
785
1081
  ...stripUndefined({
786
1082
  name: action.name,
1083
+ semantics: action.semantics,
787
1084
  title: action.title,
788
1085
  description: action.description,
789
1086
  group: normalizeGroup(action.group),
@@ -1170,7 +1467,7 @@ function isTerminalActivityStatus(status) {
1170
1467
  return TERMINAL_ACTIVITY_STATUSES.includes(status);
1171
1468
  }
1172
1469
 
1173
- const FIELD_SCOPES = [ "workflow", "stage", "activity" ], DOCUMENT_VALUE_PERMISSIONS = [ "create", "read", "update" ], MUTATION_GUARD_ACTIONS = [ "create", "update", "delete", "publish", "unpublish" ], ACTIVITY_KINDS = [ "user", "service", "script", "manual", "receive" ], EXECUTOR_CLASSIFICATIONS = [ "autonomous", "interactive", "off-system", "hybrid" ], GROUP_KINDS = [ "core", "details" ], DRIVER_KINDS = [ "person", "agent", "service", "engine" ], CONDITION_VARS = [ {
1470
+ const ACTION_SEMANTICS = [ "decision.accept", "decision.decline" ], FIELD_SCOPES = [ "workflow", "stage", "activity" ], DOCUMENT_VALUE_PERMISSIONS = [ "create", "read", "update" ], MUTATION_GUARD_ACTIONS = [ "create", "update", "delete", "publish", "unpublish" ], ACTIVITY_KINDS = [ "user", "service", "script", "manual", "receive" ], EXECUTOR_CLASSIFICATIONS = [ "autonomous", "interactive", "off-system", "hybrid" ], GROUP_KINDS = [ "core", "details" ], DRIVER_KINDS = [ "person", "agent", "service", "engine" ], CONDITION_VARS = [ {
1174
1471
  name: "self",
1175
1472
  binding: "always",
1176
1473
  label: "this workflow instance",
@@ -1179,7 +1476,7 @@ const FIELD_SCOPES = [ "workflow", "stage", "activity" ], DOCUMENT_VALUE_PERMISS
1179
1476
  name: "fields",
1180
1477
  binding: "always",
1181
1478
  label: "the workflow's fields",
1182
- description: "Declared field entries rendered by name (`$fields.<name>` is the value, no wrapper). Stage/activity scopes overlay lexically. What a read puts in your hand follows the declared kind: a singular `doc.ref` DEREFERENCES into the hydrated document (lake `_id`/`_type` plus content fields — which may themselves be named `id`/`type`), while `doc.refs` elements and `release.ref` stay REFERENCES — `{id, type[, releaseName]}` with `id` a GDR URI — because identity reads (membership, counting, joins) must stay total without hydrating every target, and targets may live in resources the evaluation cannot fetch from. Conditions evaluate against the in-memory snapshot only, so a dereferencing plural kind would silently hole wherever hydration lagged."
1479
+ description: "Declared field entries rendered by name (`$fields.<name>` is the value, no wrapper). Stage/activity scopes overlay lexically. What a read puts in your hand follows the declared kind: a singular `doc.ref` (or `subject`) DEREFERENCES into the hydrated document (lake `_id`/`_type` plus content fields — which may themselves be named `id`/`type`), while `doc.refs` elements and `release.ref` stay REFERENCES — `{id, type[, releaseName]}` with `id` a GDR URI — because identity reads (membership, counting, joins) must stay total without hydrating every target, and targets may live in resources the evaluation cannot fetch from. Conditions evaluate against the in-memory snapshot only, so a dereferencing plural kind would silently hole wherever hydration lagged."
1183
1480
  }, {
1184
1481
  name: "parent",
1185
1482
  binding: "always",
@@ -1260,18 +1557,26 @@ const FIELD_SCOPES = [ "workflow", "stage", "activity" ], DOCUMENT_VALUE_PERMISS
1260
1557
  binding: "always",
1261
1558
  label: "the spawned subworkflows",
1262
1559
  description: "Every row of the instance's subworkflow registry, faceted by `activity`/`action`/`definition`/`rowKey`/`status` (`'active'|'done'|'aborted'`) with `current` marking the open stage entry's cohort and `stage` the child's current stage. Usable anywhere — transition `when`s, requirements, any stage's gates; the settled gate is `count($subworkflows[activity == <name> && current && status == 'active']) == 0`."
1263
- } ], RESERVED_CONDITION_VARS = CONDITION_VARS.map(v2 => v2.name), FILTER_SCOPE_VARS = CONDITION_VARS.filter(v2 => v2.binding === "always").map(v2 => v2.name), CALLER_BOUND_VARS = CONDITION_VARS.filter(v2 => v2.binding === "caller").map(v2 => v2.name), START_FILTER_VARS = [ {
1560
+ } ], SUBJECT_HAS_IN_FLIGHT_INSTANCE_VAR = "subjectHasInFlightInstance", RESERVED_CONDITION_VARS = [ ...CONDITION_VARS.map(v2 => v2.name), SUBJECT_HAS_IN_FLIGHT_INSTANCE_VAR ], FILTER_SCOPE_VARS = CONDITION_VARS.filter(v2 => v2.binding === "always").map(v2 => v2.name), CALLER_BOUND_VARS = CONDITION_VARS.filter(v2 => v2.binding === "caller").map(v2 => v2.name), START_FILTER_VARS = [ {
1264
1561
  name: "tag",
1562
+ label: "this engine tag",
1265
1563
  description: "The engine's tag partition — scope `*[...]` instance scans with `tag == $tag`."
1266
1564
  }, {
1267
1565
  name: "definition",
1566
+ label: "this workflow definition",
1268
1567
  description: "The `name` of the definition under evaluation (its own start block binds it)."
1269
1568
  }, {
1270
1569
  name: "now",
1570
+ label: "the current time",
1271
1571
  description: "The ISO clock reading of the evaluating engine."
1572
+ }, {
1573
+ name: SUBJECT_HAS_IN_FLIGHT_INSTANCE_VAR,
1574
+ label: "the subject already has an in-flight workflow",
1575
+ description: "Whether any instance in this engine tag, across all definitions, has the same resource-qualified subject and no `completedAt`. Advisory under concurrent starts."
1272
1576
  } ], START_ALLOWED_VARS = [ ...START_FILTER_VARS, {
1273
1577
  name: "fields",
1274
- description: "The caller's input entries by name (`initialFields` — at `startInstance`, the values the start would seed; at a pre-flight, the values gathered so far, so a read of a not-yet-supplied entry is GROQ null). Document references bind as GDR envelopes — `$fields.<entry>.id` is the GDR URI, never a string authors assemble — a singular `doc.ref` included (nothing hydrates at the gate or the pre-flight). Pathed reads are deploy-checked against these envelope shapes."
1578
+ label: "the start's input fields",
1579
+ description: "The caller's input entries by name (`initialFields` — at `startInstance`, the values the start would seed; at a pre-flight, the values gathered so far, so a read of a not-yet-supplied entry is GROQ null). Document references bind as GDR envelopes — `$fields.<entry>.id` is the GDR URI, never a string authors assemble — a singular `doc.ref` or `subject` included (nothing hydrates at the gate or the pre-flight). Pathed reads are deploy-checked against these envelope shapes."
1275
1580
  } ], GUARD_PREDICATE_VARS = [ {
1276
1581
  name: "guard",
1277
1582
  description: "The guard document itself (its `metadata` carries deploy-time resolved values)."
@@ -1421,6 +1726,18 @@ function releaseRef({res: res, releaseName: releaseName}) {
1421
1726
  };
1422
1727
  }
1423
1728
 
1729
+ function isSingleDocRefKind(kind) {
1730
+ return kind === "doc.ref" || kind === "subject";
1731
+ }
1732
+
1733
+ function refKindAcceptsTypes(kind) {
1734
+ return isSingleDocRefKind(kind) || kind === "doc.refs";
1735
+ }
1736
+
1737
+ function isSingleDocRefEntry(entry) {
1738
+ return isSingleDocRefKind(entry._type);
1739
+ }
1740
+
1424
1741
  function isTodoListItem(row) {
1425
1742
  if (typeof row != "object" || row === null) return !1;
1426
1743
  const candidate = row, status = candidate.status;
@@ -1471,13 +1788,39 @@ const GdrUriSchema = v__namespace.custom(s => typeof s == "string" && isGdrUri(s
1471
1788
  }), tolerantObject()({
1472
1789
  type: v__namespace.literal("role"),
1473
1790
  role: NonEmptyString
1474
- }) ]), NullableString = v__namespace.union([ v__namespace.null(), v__namespace.string() ]), NullableNumber = v__namespace.union([ v__namespace.null(), v__namespace.number() ]), NullableBoolean = v__namespace.union([ v__namespace.null(), v__namespace.boolean() ]), NullableDateTime = v__namespace.union([ v__namespace.null(), IsoTimestamp ]), NullableDate = v__namespace.union([ v__namespace.null(), v__namespace.pipe(v__namespace.string(), v__namespace.regex(/^\d{4}-\d{2}-\d{2}$/, "must be a `YYYY-MM-DD` date")) ]), NullableUrl = NullableString, fieldValueSchemas = {
1791
+ }) ]), NullableString = v__namespace.union([ v__namespace.null(), v__namespace.string() ]), NullableNumber = v__namespace.union([ v__namespace.null(), v__namespace.number() ]), NullableBoolean = v__namespace.union([ v__namespace.null(), v__namespace.boolean() ]), NullableProgress = v__namespace.union([ v__namespace.null(), v__namespace.pipe(v__namespace.number(), v__namespace.finite("progress must be a finite number"), v__namespace.minValue(0, "progress must be at least 0"), v__namespace.maxValue(100, "progress must be at most 100")) ]), NullableDateTime = v__namespace.union([ v__namespace.null(), IsoTimestamp ]), NullableDate = v__namespace.union([ v__namespace.null(), v__namespace.pipe(v__namespace.string(), v__namespace.regex(/^\d{4}-\d{2}-\d{2}$/, "must be a `YYYY-MM-DD` date")) ]), NullableUrl = NullableString, CHOICE_KINDS = /* @__PURE__ */ new Set([ "string", "text", "number", "url", "date", "datetime", "dateTime" ]);
1792
+
1793
+ function normalizedChoiceKind(kind) {
1794
+ return kind === "dateTime" ? "datetime" : kind;
1795
+ }
1796
+
1797
+ function checkChoiceList(args) {
1798
+ const {entryType: entryType, options: options, validation: validation} = args;
1799
+ if (options === void 0) return;
1800
+ if (!CHOICE_KINDS.has(entryType)) return [ `\`options\` is not valid on "${entryType}" values` ];
1801
+ const kind = normalizedChoiceKind(entryType), issues = options.list.flatMap((option, index) => checkValueAgainst({
1802
+ entryType: kind,
1803
+ value: option.value,
1804
+ validation: validation
1805
+ }, valueSchemas)?.map(issue => `at options.list.${index}.value: ${issue}`) ?? []), seen = /* @__PURE__ */ new Set;
1806
+ for (const option of options.list) seen.has(option.value) && issues.push(`duplicate option value ${JSON.stringify(option.value)}`),
1807
+ seen.add(option.value);
1808
+ return issues.length === 0 ? void 0 : issues;
1809
+ }
1810
+
1811
+ function choiceValueIssues(options, value) {
1812
+ if (!(options === void 0 || value === null || value === void 0)) return options.list.some(option => Object.is(option.value, value)) ? void 0 : [ `value ${JSON.stringify(value)} is not declared in \`options.list\`; expected one of ${options.list.map(option => JSON.stringify(option.value)).join(", ")}` ];
1813
+ }
1814
+
1815
+ const fieldValueSchemas = {
1475
1816
  "doc.ref": v__namespace.union([ v__namespace.null(), GdrShape ]),
1476
1817
  "doc.refs": v__namespace.array(GdrShape),
1818
+ subject: v__namespace.union([ v__namespace.null(), GdrShape ]),
1477
1819
  "release.ref": v__namespace.union([ v__namespace.null(), ReleaseRefShape ]),
1478
1820
  string: NullableString,
1479
1821
  text: NullableString,
1480
1822
  number: NullableNumber,
1823
+ progress: NullableProgress,
1481
1824
  boolean: NullableBoolean,
1482
1825
  date: NullableDate,
1483
1826
  datetime: NullableDateTime,
@@ -1491,7 +1834,56 @@ const GdrUriSchema = v__namespace.custom(s => typeof s == "string" && isGdrUri(s
1491
1834
  };
1492
1835
 
1493
1836
  function shapeValueSchema(shape, leaf) {
1494
- return shape.type === "object" ? objectSchema(shape.fields ?? [], leaf) : shape.type === "array" ? v__namespace.array(objectSchema(shape.of ?? [], leaf)) : leaf[shape.type] ?? v__namespace.any();
1837
+ if (shape.type === "object") return objectSchema(shape.fields ?? [], leaf);
1838
+ if (shape.type === "array") return v__namespace.array(objectSchema(shape.of ?? [], leaf));
1839
+ const schema = leaf[shape.type] ?? v__namespace.any();
1840
+ return constrainedScalarSchema({
1841
+ schema: schema,
1842
+ entryType: shape.type,
1843
+ ...shape
1844
+ });
1845
+ }
1846
+
1847
+ function scalarMeasurement(entryType, value) {
1848
+ if ((entryType === "number" || entryType === "progress") && typeof value == "number") return value;
1849
+ if ((entryType === "string" || entryType === "text") && typeof value == "string") return value.length;
1850
+ }
1851
+
1852
+ function scalarBoundIssue(args) {
1853
+ const {entryType: entryType, measured: measured, bound: bound, limit: limit} = args;
1854
+ return bound === void 0 || limit === "min" && measured >= bound || limit === "max" && measured <= bound ? void 0 : `${entryType === "number" || entryType === "progress" ? "" : "length "}must be ${limit === "min" ? "greater than or equal to" : "less than or equal to"} ${bound}`;
1855
+ }
1856
+
1857
+ function scalarValidationIssues(args) {
1858
+ const {entryType: entryType, validation: validation, value: value} = args;
1859
+ if (validation === void 0 || value === null || value === void 0) return;
1860
+ const measured = scalarMeasurement(entryType, value);
1861
+ if (measured === void 0) return;
1862
+ const issues = [ scalarBoundIssue({
1863
+ entryType: entryType,
1864
+ measured: measured,
1865
+ bound: validation.min,
1866
+ limit: "min"
1867
+ }), scalarBoundIssue({
1868
+ entryType: entryType,
1869
+ measured: measured,
1870
+ bound: validation.max,
1871
+ limit: "max"
1872
+ }) ].filter(issue => issue !== void 0);
1873
+ return issues.length === 0 ? void 0 : issues;
1874
+ }
1875
+
1876
+ function constrainedScalarSchema(args) {
1877
+ const {schema: schema, entryType: entryType, options: options, validation: validation} = args;
1878
+ return options === void 0 && validation === void 0 ? schema : v__namespace.pipe(schema, v__namespace.check(value => choiceValueIssues(options, value) === void 0 && scalarValidationIssues({
1879
+ entryType: entryType,
1880
+ validation: validation,
1881
+ value: value
1882
+ }) === void 0, issue => [ ...choiceValueIssues(options, issue.input) ?? [], ...scalarValidationIssues({
1883
+ entryType: entryType,
1884
+ validation: validation,
1885
+ value: issue.input
1886
+ }) ?? [] ].join("; ")));
1495
1887
  }
1496
1888
 
1497
1889
  function objectSchema(fields, leaf) {
@@ -1514,7 +1906,7 @@ function appendItemSchema(entryType, shape) {
1514
1906
  function rejectedRefTypes(args) {
1515
1907
  const {entryType: entryType, types: types, value: value} = args;
1516
1908
  if (types === void 0 || value === null || value === void 0) return [];
1517
- if (entryType !== "doc.ref" && entryType !== "doc.refs") return [];
1909
+ if (!refKindAcceptsTypes(entryType)) return [];
1518
1910
  let items = [ value ];
1519
1911
  return entryType === "doc.refs" && (items = Array.isArray(value) ? value : []),
1520
1912
  [ ...new Set(items.map(gdrTypeOf).filter(t => t !== void 0 && !types.includes(t))) ];
@@ -1549,6 +1941,10 @@ function checkValueAgainst(args, leaf) {
1549
1941
  entryType: args.entryType,
1550
1942
  types: args.types,
1551
1943
  value: args.value
1944
+ }) ?? choiceValueIssues(args.options, args.value) ?? scalarValidationIssues({
1945
+ entryType: args.entryType,
1946
+ validation: args.validation,
1947
+ value: args.value
1552
1948
  }) : formatIssues(result.issues);
1553
1949
  }
1554
1950
 
@@ -1579,6 +1975,7 @@ const AuthoringRefId = v__namespace.pipe(v__namespace.string(), v__namespace.che
1579
1975
  ...valueSchemas,
1580
1976
  "doc.ref": v__namespace.union([ v__namespace.null(), AuthoringGdrShape ]),
1581
1977
  "doc.refs": v__namespace.array(AuthoringGdrShape),
1978
+ subject: v__namespace.union([ v__namespace.null(), AuthoringGdrShape ]),
1582
1979
  "release.ref": v__namespace.union([ v__namespace.null(), v__namespace.looseObject({
1583
1980
  id: AuthoringRefId,
1584
1981
  type: v__namespace.literal("system.release"),
@@ -1618,10 +2015,10 @@ function validateFieldAppendItem(args) {
1618
2015
  });
1619
2016
  }
1620
2017
 
1621
- function formatIssues(issues) {
2018
+ function formatIssues(issues, formatMessage = issue => issue.message) {
1622
2019
  return issues.map(i => {
1623
2020
  const keys = i.path?.map(p => p.key) ?? [];
1624
- return `${keys.length > 0 ? `at ${keys.join(".")}: ` : ""}${i.message}`;
2021
+ return `${keys.length > 0 ? `at ${keys.join(".")}: ` : ""}${formatMessage(i)}`;
1625
2022
  });
1626
2023
  }
1627
2024
 
@@ -1747,7 +2144,15 @@ function groupMembershipNames(group) {
1747
2144
  return group === void 0 ? [] : typeof group == "string" ? [ group ] : [ ...group ];
1748
2145
  }
1749
2146
 
1750
- const FIELD_VALUE_KINDS = [ "doc.ref", "doc.refs", "release.ref", "string", "text", "number", "boolean", "date", "datetime", "url", "actor", "assignee", "assignees", "object", "array" ], FieldValueKindSchema = picklist(FIELD_VALUE_KINDS), FieldKindSchema = picklist(FIELD_VALUE_KINDS), FieldEntryName = groqIdentifier("`$fields.<name>`");
2147
+ const FIELD_VALUE_KINDS = [ "doc.ref", "doc.refs", "subject", "release.ref", "string", "text", "number", "progress", "boolean", "date", "datetime", "url", "actor", "assignee", "assignees", "object", "array" ], FieldValueKindSchema = picklist(FIELD_VALUE_KINDS), FieldKindSchema = picklist(FIELD_VALUE_KINDS), FieldEntryName = groqIdentifier("`$fields.<name>`"), FiniteNumber = v__namespace.pipe(v__namespace.number(), v__namespace.finite("must be finite")), ScalarValidationSchema = v__namespace.pipe(v__namespace.strictObject({
2148
+ min: v__namespace.optional(FiniteNumber),
2149
+ max: v__namespace.optional(FiniteNumber)
2150
+ }), v__namespace.check(validation => validation.min !== void 0 || validation.max !== void 0, "declare at least one bound, or omit `validation`"), v__namespace.check(validation => validation.min === void 0 || validation.max === void 0 || validation.min <= validation.max, "`min` must be less than or equal to `max`")), ChoiceOptionsSchema = v__namespace.strictObject({
2151
+ list: v__namespace.pipe(v__namespace.array(v__namespace.strictObject({
2152
+ title: NonEmpty,
2153
+ value: v__namespace.union([ v__namespace.string(), v__namespace.number() ])
2154
+ })), v__namespace.minLength(1, "declare at least one choice, or omit `options`"))
2155
+ });
1751
2156
 
1752
2157
  function asShape(input) {
1753
2158
  return typeof input == "object" && input !== null ? input : {};
@@ -1781,14 +2186,16 @@ function compositeChecked(entries) {
1781
2186
  return v__namespace.pipe(v__namespace.strictObject(entries), v__namespace.check(input => compositeShapeOk(input), issue => compositeShapeMessage(issue.input)), v__namespace.check(input => duplicateSubfieldName(input) === void 0, issue => `duplicate sub-field name "${duplicateSubfieldName(issue.input)}" — sub-field names must be unique within \`fields\` / \`of\``));
1782
2187
  }
1783
2188
 
1784
- const FieldShapeSchema = v__namespace.lazy(() => compositeChecked({
2189
+ const FieldShapeSchema = v__namespace.lazy(() => v__namespace.pipe(compositeChecked({
1785
2190
  type: FieldValueKindSchema,
1786
2191
  name: FieldEntryName,
1787
2192
  title: v__namespace.optional(v__namespace.string()),
1788
2193
  description: v__namespace.optional(v__namespace.string()),
2194
+ options: v__namespace.optional(ChoiceOptionsSchema),
2195
+ validation: v__namespace.optional(ScalarValidationSchema),
1789
2196
  fields: v__namespace.optional(v__namespace.array(FieldShapeSchema)),
1790
2197
  of: v__namespace.optional(v__namespace.array(FieldShapeSchema))
1791
- })), StoredEditableSchema = v__namespace.union([ v__namespace.literal(!0), NonEmpty ]), AuthoringEditableSchema = v__namespace.union([ v__namespace.literal(!0), v__namespace.array(NonEmpty), NonEmpty ]);
2198
+ }), choiceOptionsCheck(), scalarValidationCheck())), StoredEditableSchema = v__namespace.union([ v__namespace.literal(!0), NonEmpty ]), AuthoringEditableSchema = v__namespace.union([ v__namespace.literal(!0), v__namespace.array(NonEmpty), NonEmpty ]);
1792
2199
 
1793
2200
  function fieldBase(editable, group) {
1794
2201
  return {
@@ -1806,6 +2213,8 @@ function fieldEntryFields(editable, group) {
1806
2213
  return {
1807
2214
  type: FieldKindSchema,
1808
2215
  ...fieldBase(editable, group),
2216
+ options: v__namespace.optional(ChoiceOptionsSchema),
2217
+ validation: v__namespace.optional(ScalarValidationSchema),
1809
2218
  types: v__namespace.optional(v__namespace.pipe(v__namespace.array(NonEmpty), v__namespace.minLength(1, "declare at least one accepted type, or omit `types` to accept any"))),
1810
2219
  fields: v__namespace.optional(v__namespace.array(FieldShapeSchema)),
1811
2220
  of: v__namespace.optional(v__namespace.array(FieldShapeSchema))
@@ -1818,7 +2227,9 @@ function literalSeedIssues(entry) {
1818
2227
  value: entry.initialValue.value,
1819
2228
  types: entry.types,
1820
2229
  fields: entry.fields,
1821
- of: entry.of
2230
+ of: entry.of,
2231
+ options: entry.options,
2232
+ validation: entry.validation
1822
2233
  });
1823
2234
  }
1824
2235
 
@@ -1827,10 +2238,41 @@ function literalSeedCheck() {
1827
2238
  }
1828
2239
 
1829
2240
  function refTypesCheck() {
1830
- return v__namespace.check(entry => entry.types === void 0 || entry.type === "doc.ref" || entry.type === "doc.refs", issue => `\`types\` is only valid on \`doc.ref\` / \`doc.refs\` entries, not "${issue.input.type}"`);
2241
+ return v__namespace.check(entry => entry.types === void 0 || refKindAcceptsTypes(entry.type), issue => `\`types\` is only valid on \`doc.ref\` / \`doc.refs\` / \`subject\` entries, not "${issue.input.type}"`);
1831
2242
  }
1832
2243
 
1833
- const FieldEntrySchema = pinned()(v__namespace.pipe(compositeChecked(fieldEntryFields(StoredEditableSchema, StoredGroupMembershipSchema)), refTypesCheck(), literalSeedCheck())), RawAuthoringFieldEntrySchema = pinned()(v__namespace.pipe(compositeChecked(fieldEntryFields(AuthoringEditableSchema, AuthoringGroupMembershipSchema)), refTypesCheck(), literalSeedCheck())), ClaimFieldSchema = pinned()(v__namespace.strictObject({
2244
+ function choiceOptionsCheck() {
2245
+ return v__namespace.check(entry => checkChoiceList({
2246
+ entryType: entry.type,
2247
+ options: entry.options,
2248
+ validation: entry.validation
2249
+ }) === void 0, issue => (checkChoiceList({
2250
+ entryType: issue.input.type,
2251
+ options: issue.input.options,
2252
+ validation: issue.input.validation
2253
+ }) ?? []).join("; "));
2254
+ }
2255
+
2256
+ const SCALAR_VALIDATION_KINDS = /* @__PURE__ */ new Set([ "string", "text", "number", "progress" ]);
2257
+
2258
+ function scalarValidationCheck() {
2259
+ return v__namespace.check(entry => scalarValidationDeclarationIssues(entry) === void 0, issue => (scalarValidationDeclarationIssues(issue.input) ?? []).join("; "));
2260
+ }
2261
+
2262
+ function scalarValidationDeclarationIssues(entry) {
2263
+ const {type: type, validation: validation} = entry;
2264
+ if (validation === void 0) return;
2265
+ if (!SCALAR_VALIDATION_KINDS.has(type)) return [ `\`validation\` is only valid on \`string\` / \`text\` / \`number\` / \`progress\` values, not "${type}"` ];
2266
+ if (type === "progress") {
2267
+ const issues2 = Object.entries(validation).flatMap(([bound, value]) => typeof value == "number" && value >= 0 && value <= 100 ? [] : [ `\`validation.${bound}\` must stay within the progress kind's 0–100 contract` ]);
2268
+ return issues2.length === 0 ? void 0 : issues2;
2269
+ }
2270
+ if (type === "number") return;
2271
+ const issues = Object.entries(validation).flatMap(([bound, value]) => Number.isInteger(value) && value >= 0 ? [] : [ `\`validation.${bound}\` must be a non-negative integer for ${type} length` ]);
2272
+ return issues.length === 0 ? void 0 : issues;
2273
+ }
2274
+
2275
+ const FieldEntrySchema = pinned()(v__namespace.pipe(compositeChecked(fieldEntryFields(StoredEditableSchema, StoredGroupMembershipSchema)), refTypesCheck(), choiceOptionsCheck(), scalarValidationCheck(), literalSeedCheck())), RawAuthoringFieldEntrySchema = pinned()(v__namespace.pipe(compositeChecked(fieldEntryFields(AuthoringEditableSchema, AuthoringGroupMembershipSchema)), refTypesCheck(), choiceOptionsCheck(), scalarValidationCheck(), literalSeedCheck())), ClaimFieldSchema = pinned()(v__namespace.strictObject({
1834
2276
  type: v__namespace.literal("claim"),
1835
2277
  name: FieldEntryName,
1836
2278
  title: v__namespace.optional(v__namespace.string()),
@@ -1861,17 +2303,25 @@ const TodoListFieldSchema = pinned()(v__namespace.strictObject(listSugarFields("
1861
2303
  with: v__namespace.optional(v__namespace.record(NonEmpty, ConditionSchema)),
1862
2304
  context: v__namespace.optional(v__namespace.record(NonEmpty, ConditionSchema)),
1863
2305
  onExit: v__namespace.optional(picklist([ "detach", "abort" ]))
1864
- }), ActionParamSchema = v__namespace.strictObject({
2306
+ }), ActionParamSchema = v__namespace.pipe(v__namespace.strictObject({
1865
2307
  type: picklist([ "string", "number", "boolean", "url", "dateTime", "actor", "doc.ref", "doc.refs", "json" ]),
1866
2308
  name: NonEmpty,
1867
2309
  title: v__namespace.optional(v__namespace.string()),
1868
2310
  description: v__namespace.optional(v__namespace.string()),
1869
- required: v__namespace.optional(v__namespace.boolean())
1870
- });
2311
+ required: v__namespace.optional(v__namespace.boolean()),
2312
+ options: v__namespace.optional(ChoiceOptionsSchema),
2313
+ validation: v__namespace.optional(ScalarValidationSchema)
2314
+ }), choiceOptionsCheck(), scalarValidationCheck());
2315
+
2316
+ function hasUniqueSemanticNamespaces(semantics) {
2317
+ const namespaces = semantics.map(semantic => semantic.split(".", 1)[0]);
2318
+ return new Set(namespaces).size === namespaces.length;
2319
+ }
1871
2320
 
1872
2321
  function actionFields(op, group) {
1873
2322
  return {
1874
2323
  name: NonEmpty,
2324
+ semantics: v__namespace.optional(v__namespace.pipe(v__namespace.array(picklist(ACTION_SEMANTICS)), v__namespace.minLength(1, "declare at least one semantic, or omit `semantics`"), v__namespace.check(hasUniqueSemanticNamespaces, "declare at most one semantic from each namespace"))),
1875
2325
  title: v__namespace.optional(v__namespace.string()),
1876
2326
  description: v__namespace.optional(v__namespace.string()),
1877
2327
  group: v__namespace.optional(group),
@@ -2060,7 +2510,7 @@ function startKindOf(definition) {
2060
2510
  }
2061
2511
 
2062
2512
  function isSubjectEntry(entry) {
2063
- return entry.required === !0 && (entry.type === "doc.ref" || entry.type === "doc.refs");
2513
+ return entry.type === "subject";
2064
2514
  }
2065
2515
 
2066
2516
  function isInputSourced(entry) {
@@ -2562,6 +3012,52 @@ function checkAssigneesEntries(def, issues) {
2562
3012
  });
2563
3013
  }
2564
3014
 
3015
+ function nestedSubjectPaths(shapes, base) {
3016
+ return (shapes ?? []).flatMap((shape, i) => isSubjectEntry(shape) ? [ [ ...base, i, "type" ] ] : [ ...nestedSubjectPaths(shape.fields, [ ...base, i, "fields" ]), ...nestedSubjectPaths(shape.of, [ ...base, i, "of" ]) ]);
3017
+ }
3018
+
3019
+ function checkSubjectEffectOutputs(def, issues) {
3020
+ for (const [i, stage] of def.stages.entries()) for (const [j, activity] of (stage.activities ?? []).entries()) for (const [a, action] of (activity.actions ?? []).entries()) pushSubjectOutputIssues({
3021
+ action: action,
3022
+ path: [ "stages", i, "activities", j, "actions", a ],
3023
+ issues: issues
3024
+ });
3025
+ }
3026
+
3027
+ function pushSubjectOutputIssues(args) {
3028
+ const {action: action, path: path, issues: issues} = args;
3029
+ for (const [e, effect] of (action.effects ?? []).entries()) {
3030
+ const base = [ ...path, "effects", e, "outputs" ];
3031
+ for (const nestedPath of nestedSubjectPaths(effect.outputs, base)) issues.push({
3032
+ path: nestedPath,
3033
+ message: `effect "${effect.name}" declares a \`subject\` output shape — no subject reader ever looks at effect outputs. Declare \`doc.ref\` for a document-valued output`
3034
+ });
3035
+ }
3036
+ }
3037
+
3038
+ function checkSubjectEntries(def, issues) {
3039
+ for (const {entries: entries, scope: scope, path: path, label: label} of fieldScopes(def)) {
3040
+ const subjects = (entries ?? []).flatMap((entry, n) => isSubjectEntry(entry) ? [ {
3041
+ entry: entry,
3042
+ n: n
3043
+ } ] : []);
3044
+ if (scope !== "workflow") for (const {entry: entry, n: n} of subjects) issues.push({
3045
+ path: [ ...path, n, "type" ],
3046
+ message: `${label} entry "${entry.name}" is a \`subject\` — the subject names the document the WORKFLOW is about, so it is valid only on a workflow-scope entry. Declare \`doc.ref\` for a plain reference here`
3047
+ }); else for (const {n: n} of subjects.slice(1)) issues.push({
3048
+ path: [ ...path, n ],
3049
+ message: "at most one subject-kind field entry per workflow — the runtime identifies THE subject by kind, and a second one makes it ambiguous"
3050
+ });
3051
+ for (const [n, entry] of (entries ?? []).entries()) {
3052
+ const nested = [ ...nestedSubjectPaths(entry.fields, [ ...path, n, "fields" ]), ...nestedSubjectPaths(entry.of, [ ...path, n, "of" ]) ];
3053
+ for (const nestedPath of nested) issues.push({
3054
+ path: nestedPath,
3055
+ message: `${label} entry "${entry.name}" declares a \`subject\` sub-field — a nested subject can never be read as the workflow's subject. Declare \`doc.ref\` for a nested reference`
3056
+ });
3057
+ }
3058
+ }
3059
+ }
3060
+
2565
3061
  function checkActivityTerminalPaths(def, issues) {
2566
3062
  for (const [i, stage] of def.stages.entries()) {
2567
3063
  const resolvable = terminallyResolvableActivities(stage);
@@ -2612,12 +3108,30 @@ function checkStart(def, issues) {
2612
3108
  if (def.start !== void 0 && (def.lifecycle === "child" && issues.push({
2613
3109
  path: [ "start" ],
2614
3110
  message: "a spawn-only (lifecycle 'child') definition declares `start` — children are instantiated by a parent's `spawn`, never started standalone, so the block would never apply. Remove `start`, or drop `lifecycle: 'child'`"
2615
- }), checkStartFilterReads(def, issues), checkStartAllowedReads(def, issues), def.start.kind === "autonomous")) for (const [n, entry] of (def.fields ?? []).entries()) entry.required !== !0 || isSubjectEntry(entry) || issues.push({
3111
+ }), checkStartFilterReads(def, issues), checkStartAllowedReads(def, issues), checkStartSubjectVariable(def, issues),
3112
+ def.start.kind === "autonomous")) for (const [n, entry] of (def.fields ?? []).entries()) entry.required !== !0 || isSubjectEntry(entry) || issues.push({
2616
3113
  path: [ "fields", n, "required" ],
2617
- message: `start.kind 'autonomous' means runs are initiated by a system reacting to a document, so every required input must be derivable from that triggering document — required entry "${entry.name}" (kind "${entry.type}") is not a document reference. Make it optional, seed it another way (query/literal), or declare it doc.ref / doc.refs`
3114
+ message: `start.kind 'autonomous' means runs are initiated by a system reacting to a document, so every required input must be derivable from that triggering document — required entry "${entry.name}" (kind "${entry.type}") is not the workflow's subject. Make it optional, seed it another way (query/literal), or declare it the \`subject\` entry (the document the run is about)`
2618
3115
  });
2619
3116
  }
2620
3117
 
3118
+ function checkStartSubjectVariable(def, issues) {
3119
+ const subject = (def.fields ?? []).find(isSubjectEntry);
3120
+ for (const [key, condition] of [ [ "filter", def.start?.filter ], [ "allowed", def.start?.allowed ] ]) if (condition !== void 0 && conditionParameterNames(condition).has(SUBJECT_HAS_IN_FLIGHT_INSTANCE_VAR)) {
3121
+ if (subject === void 0) {
3122
+ issues.push({
3123
+ path: [ "start", key ],
3124
+ message: `start.${key} reads $${SUBJECT_HAS_IN_FLIGHT_INSTANCE_VAR}, but the definition declares no \`subject\` entry — the engine has no prospective subject identity to match. Declare a \`subject\` entry (the document the workflow is about), or remove the variable`
3125
+ });
3126
+ continue;
3127
+ }
3128
+ key === "allowed" && !isInputSourced(subject) && issues.push({
3129
+ path: [ "start", key ],
3130
+ message: `start.allowed reads $${SUBJECT_HAS_IN_FLIGHT_INSTANCE_VAR}, but the definition's subject entry "${subject.name}" is not \`input\`-sourced — the start gate cannot bind its prospective subject. Make the subject input-sourced, or remove the variable`
3131
+ });
3132
+ }
3133
+ }
3134
+
2621
3135
  function checkStartFilterReads(def, issues) {
2622
3136
  const filter = def.start?.filter;
2623
3137
  filter !== void 0 && (conditionParameterNames(filter).has("fields") && issues.push({
@@ -2625,7 +3139,7 @@ function checkStartFilterReads(def, issues) {
2625
3139
  message: "start.filter reads $fields, but the filter is browse-time-pure — a start surface evaluates it per document, before any inputs exist, so $fields cannot be bound. Move the input-dependent rule to start.allowed, the start-time permission predicate that binds $fields and is enforced by startInstance"
2626
3140
  }), readsRootDocument(filter) && !(def.fields ?? []).some(isSubjectEntry) && issues.push({
2627
3141
  path: [ "start", "filter" ],
2628
- message: "start.filter reads the candidate document (its root), but the definition declares no required subject entry (a required doc.ref / doc.refs input) — a read surface would never have a document to bind as root, so every root read is GROQ null and the filter silently misevaluates. Declare a required subject entry, or gate on the dataset instead"
3142
+ message: "start.filter reads the candidate document (its root), but the definition declares no `subject` entry — a read surface would never have a document to bind as root, so every root read is GROQ null and the filter silently misevaluates. Declare a `subject` entry (the document the workflow is about), or gate on the dataset instead"
2629
3143
  }));
2630
3144
  }
2631
3145
 
@@ -2942,7 +3456,7 @@ function checkFieldReadOpValues(def, issues) {
2942
3456
  ops: site.ops,
2943
3457
  path: site.path,
2944
3458
  label: site.label,
2945
- activityEntries: entryMap(site.activity.fields)
3459
+ activityEntries: site.activity.fields ?? []
2946
3460
  });
2947
3461
  }
2948
3462
 
@@ -2964,6 +3478,9 @@ function fieldReadsIn(value, path) {
2964
3478
 
2965
3479
  function checkOpFieldRead({read: read, where: where, path: path, workflowEntries: workflowEntries, stageEntries: stageEntries, activityEntries: activityEntries, issues: issues}) {
2966
3480
  const hosts = [ {
3481
+ scope: "activity",
3482
+ entries: activityEntries
3483
+ }, {
2967
3484
  scope: "stage",
2968
3485
  entries: stageEntries
2969
3486
  }, {
@@ -2976,8 +3493,7 @@ function checkOpFieldRead({read: read, where: where, path: path, workflowEntries
2976
3493
  message: opFieldReadMissMessage({
2977
3494
  read: read,
2978
3495
  where: where,
2979
- hosts: hosts,
2980
- activityEntries: activityEntries
3496
+ hosts: hosts
2981
3497
  })
2982
3498
  });
2983
3499
  return;
@@ -2991,9 +3507,9 @@ function checkOpFieldRead({read: read, where: where, path: path, workflowEntries
2991
3507
  });
2992
3508
  }
2993
3509
 
2994
- function opFieldReadMissMessage({read: read, where: where, hosts: hosts, activityEntries: activityEntries}) {
2995
- const searched = read.scope === void 0 ? "stage or workflow scope" : `${read.scope} scope`, activityHint = activityEntries?.has(read.field) ? ` "${read.field}" is an activity-scope field, and op-time field reads resolve against stage and workflow scopes only — declare it at stage scope to read it from an op.` : "", known = hosts.flatMap(host => host.entries.map(entry => `${host.scope}:${entry.name}`));
2996
- return `${where} reads field "${read.field}", which is not declared at ${searched} — the read resolves to undefined at op time, so the write silently lands empty.${activityHint} Known: ${known.join(", ") || "(none)"}`;
3510
+ function opFieldReadMissMessage({read: read, where: where, hosts: hosts}) {
3511
+ const searched = read.scope === void 0 ? "activity, stage, or workflow scope" : `${read.scope} scope`, known = hosts.flatMap(host => host.entries.map(entry => `${host.scope}:${entry.name}`));
3512
+ return `${where} reads field "${read.field}", which is not declared at ${searched} — the read resolves to undefined at op time, so the write silently lands empty. Known: ${known.join(", ") || "(none)"}`;
2997
3513
  }
2998
3514
 
2999
3515
  function checkUpdateWhereOps(def, issues) {
@@ -3156,10 +3672,12 @@ const SCALAR = {
3156
3672
  kind: "list",
3157
3673
  item: GDR_VALUE
3158
3674
  }),
3675
+ subject: () => DOC_CONTENT,
3159
3676
  "release.ref": () => RELEASE_VALUE,
3160
3677
  string: () => SCALAR,
3161
3678
  text: () => SCALAR,
3162
3679
  number: () => SCALAR,
3680
+ progress: () => SCALAR,
3163
3681
  boolean: () => SCALAR,
3164
3682
  date: () => SCALAR,
3165
3683
  datetime: () => SCALAR,
@@ -3180,7 +3698,8 @@ const SCALAR = {
3180
3698
  })
3181
3699
  }, START_ALLOWED_VALUE_NODES = {
3182
3700
  ...VALUE_NODES,
3183
- "doc.ref": () => GDR_VALUE
3701
+ "doc.ref": () => GDR_VALUE,
3702
+ subject: () => GDR_VALUE
3184
3703
  };
3185
3704
 
3186
3705
  function valueNodeFor(shape, nodes) {
@@ -3252,11 +3771,14 @@ function checkWorkflowInvariants(def) {
3252
3771
  checkRequiredField(def, issues), checkStart(def, issues), checkPredicates(def, issues),
3253
3772
  checkUnboundConditionVars(def, issues), checkConditionFieldReads(def, issues), checkFieldReadSeeds(def, issues),
3254
3773
  checkFieldReadOpValues(def, issues), checkUpdateWhereOps(def, issues), checkGuardFieldReads(def, issues),
3255
- checkAssigneesEntries(def, issues), checkActivityTerminalPaths(def, issues), checkTerminalStageActivities(def, issues),
3774
+ checkAssigneesEntries(def, issues), checkSubjectEntries(def, issues), checkSubjectEffectOutputs(def, issues),
3775
+ checkActivityTerminalPaths(def, issues), checkTerminalStageActivities(def, issues),
3256
3776
  checkTriggeredActionParams(def, issues), checkStoredRolesPlacement(def, issues),
3257
3777
  checkGroups(def, issues), issues;
3258
3778
  }
3259
3779
 
3780
+ exports.ACTION_SEMANTICS = ACTION_SEMANTICS;
3781
+
3260
3782
  exports.ACTIVITY_KINDS = ACTIVITY_KINDS;
3261
3783
 
3262
3784
  exports.ACTIVITY_STATUSES = ACTIVITY_STATUSES;
@@ -3287,6 +3809,12 @@ exports.CONDITION_VARS = CONDITION_VARS;
3287
3809
 
3288
3810
  exports.ContractViolationError = ContractViolationError;
3289
3811
 
3812
+ exports.DATA_MODEL_CHANGES = DATA_MODEL_CHANGES;
3813
+
3814
+ exports.DATA_MODEL_MIN_READER = DATA_MODEL_MIN_READER;
3815
+
3816
+ exports.DATA_MODEL_VERSION = DATA_MODEL_VERSION;
3817
+
3290
3818
  exports.DEFAULT_TRANSITION_WHEN = DEFAULT_TRANSITION_WHEN;
3291
3819
 
3292
3820
  exports.DOCUMENT_VALUE_PERMISSIONS = DOCUMENT_VALUE_PERMISSIONS;
@@ -3329,22 +3857,34 @@ exports.IsoTimestamp = IsoTimestamp;
3329
3857
 
3330
3858
  exports.MUTATION_GUARD_ACTIONS = MUTATION_GUARD_ACTIONS;
3331
3859
 
3860
+ exports.ModelVersionAheadError = ModelVersionAheadError;
3861
+
3332
3862
  exports.NonEmptyString = NonEmptyString;
3333
3863
 
3334
3864
  exports.PersistedDocShapeError = PersistedDocShapeError;
3335
3865
 
3866
+ exports.READER_MODEL_ROLLOUT_URL = READER_MODEL_ROLLOUT_URL;
3867
+
3336
3868
  exports.RESERVED_CONDITION_VARS = RESERVED_CONDITION_VARS;
3337
3869
 
3338
3870
  exports.RESOURCE_ALIAS_NAME_SOURCE = RESOURCE_ALIAS_NAME_SOURCE;
3339
3871
 
3872
+ exports.ReaderModelAcknowledgementError = ReaderModelAcknowledgementError;
3873
+
3340
3874
  exports.START_ALLOWED_VARS = START_ALLOWED_VARS;
3341
3875
 
3342
3876
  exports.START_FILTER_VARS = START_FILTER_VARS;
3343
3877
 
3878
+ exports.SUBJECT_HAS_IN_FLIGHT_INSTANCE_VAR = SUBJECT_HAS_IN_FLIGHT_INSTANCE_VAR;
3879
+
3880
+ exports.SpawnContractsInvalidError = SpawnContractsInvalidError;
3881
+
3344
3882
  exports.StoredFieldOpSchema = StoredFieldOpSchema;
3345
3883
 
3346
3884
  exports.WORKFLOW_DEFINITION_TYPE = WORKFLOW_DEFINITION_TYPE;
3347
3885
 
3886
+ exports.WORKFLOW_INSTANCE_TYPE = WORKFLOW_INSTANCE_TYPE;
3887
+
3348
3888
  exports.WorkflowConfigSchema = WorkflowConfigSchema;
3349
3889
 
3350
3890
  exports.WorkflowError = WorkflowError;
@@ -3353,10 +3893,16 @@ exports.actorFulfillsRole = actorFulfillsRole;
3353
3893
 
3354
3894
  exports.andConditions = andConditions;
3355
3895
 
3896
+ exports.assertReadableModel = assertReadableModel;
3897
+
3898
+ exports.assertReaderModelAcknowledgement = assertReaderModelAcknowledgement;
3899
+
3356
3900
  exports.checkFieldValue = checkFieldValue;
3357
3901
 
3358
3902
  exports.checkWorkflowInvariants = checkWorkflowInvariants;
3359
3903
 
3904
+ exports.choiceValueIssues = choiceValueIssues;
3905
+
3360
3906
  exports.clientConfigFromResource = clientConfigFromResource;
3361
3907
 
3362
3908
  exports.conditionEffectReads = conditionEffectReads;
@@ -3389,6 +3935,8 @@ exports.evaluatePredicates = evaluatePredicates;
3389
3935
 
3390
3936
  exports.extractDocumentId = extractDocumentId;
3391
3937
 
3938
+ exports.fieldTreeShape = fieldTreeShape;
3939
+
3392
3940
  exports.fieldValueSchemas = fieldValueSchemas;
3393
3941
 
3394
3942
  exports.formatIssuePath = formatIssuePath;
@@ -3425,6 +3973,10 @@ exports.isNotesEntry = isNotesEntry;
3425
3973
 
3426
3974
  exports.isParseableInstant = isParseableInstant;
3427
3975
 
3976
+ exports.isSingleDocRefEntry = isSingleDocRefEntry;
3977
+
3978
+ exports.isSingleDocRefKind = isSingleDocRefKind;
3979
+
3428
3980
  exports.isStartableDefinition = isStartableDefinition;
3429
3981
 
3430
3982
  exports.isSubjectEntry = isSubjectEntry;
@@ -3437,8 +3989,20 @@ exports.isTodoListItem = isTodoListItem;
3437
3989
 
3438
3990
  exports.isUnevaluable = isUnevaluable;
3439
3991
 
3992
+ exports.isUnprimed = isUnprimed;
3993
+
3440
3994
  exports.labelFor = labelFor;
3441
3995
 
3996
+ exports.minReaderModelOf = minReaderModelOf;
3997
+
3998
+ exports.modelStampFor = modelStampFor;
3999
+
4000
+ exports.modelVersionOf = modelVersionOf;
4001
+
4002
+ exports.parentRef = parentRef;
4003
+
4004
+ exports.parseDefinitionSnapshot = parseDefinitionSnapshot;
4005
+
3442
4006
  exports.parseGdr = parseGdr;
3443
4007
 
3444
4008
  exports.parseOrThrow = parseOrThrow;
@@ -3457,6 +4021,8 @@ exports.refDashboard = refDashboard;
3457
4021
 
3458
4022
  exports.refDataset = refDataset;
3459
4023
 
4024
+ exports.refKindAcceptsTypes = refKindAcceptsTypes;
4025
+
3460
4026
  exports.refMediaLibrary = refMediaLibrary;
3461
4027
 
3462
4028
  exports.refTypeIssues = refTypeIssues;
@@ -3467,6 +4033,10 @@ exports.releaseDocId = releaseDocId;
3467
4033
 
3468
4034
  exports.releaseRef = releaseRef;
3469
4035
 
4036
+ exports.requiredModelFeatures = requiredModelFeatures;
4037
+
4038
+ exports.requiredReaderModel = requiredReaderModel;
4039
+
3470
4040
  exports.resourceAliasesToMap = resourceAliasesToMap;
3471
4041
 
3472
4042
  exports.resourceFromGdrUri = resourceFromGdrUri;
@@ -3481,6 +4051,8 @@ exports.runGroq = runGroq;
3481
4051
 
3482
4052
  exports.sameResource = sameResource;
3483
4053
 
4054
+ exports.scalarValidationIssues = scalarValidationIssues;
4055
+
3484
4056
  exports.schemaTreeShape = schemaTreeShape;
3485
4057
 
3486
4058
  exports.selfGdr = selfGdr;
@@ -3489,6 +4061,8 @@ exports.startKindOf = startKindOf;
3489
4061
 
3490
4062
  exports.tagScopeFilter = tagScopeFilter;
3491
4063
 
4064
+ exports.terminalState = terminalState;
4065
+
3492
4066
  exports.toBareId = toBareId;
3493
4067
 
3494
4068
  exports.toPhysicalGdr = toPhysicalGdr;