@sanity/workflow-engine 0.27.0 → 0.29.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,41 @@ function _interopNamespaceCompat(e) {
20
20
 
21
21
  var v__namespace = /* @__PURE__ */ _interopNamespaceCompat(v);
22
22
 
23
+ function isCascadeFired(action) {
24
+ return action.when !== void 0;
25
+ }
26
+
27
+ function deriveActivityKind(activity) {
28
+ if (activity.target !== void 0) return "manual";
29
+ const actions = activity.actions ?? [];
30
+ return actions.some(a => !isCascadeFired(a)) ? "user" : actions.some(a => (a.effects ?? []).length > 0 || a.spawn !== void 0) ? "service" : actions.length > 0 ? "receive" : "script";
31
+ }
32
+
33
+ function deriveExecutorClassification(activity) {
34
+ if (activity.target !== void 0) return "off-system";
35
+ const actions = activity.actions ?? [], cascadeFired = actions.filter(isCascadeFired).length;
36
+ return cascadeFired === actions.length ? "autonomous" : cascadeFired === 0 ? "interactive" : "hybrid";
37
+ }
38
+
39
+ function driverKind(actor) {
40
+ return actor.kind === "person" || actor.kind === "agent" ? actor.kind : "service";
41
+ }
42
+
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
+ function andConditions(parts) {
54
+ const present = parts.filter(p => p !== void 0);
55
+ if (present.length !== 0) return present.length === 1 ? present[0] : present.map(p => `(${p})`).join(" && ");
56
+ }
57
+
23
58
  class WorkflowError extends Error {
24
59
  kind;
25
60
  constructor(kind, message, options) {
@@ -93,322 +128,6 @@ function effectNotFoundMessage(args) {
93
128
  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
129
  }
95
130
 
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 normalizeLegacyActivityRequirements(JSON.parse(instance.definitionSnapshot));
119
- } catch (err) {
120
- rethrowWithContext(err, `Failed to parse definitionSnapshot on instance "${instance._id}"`);
121
- }
122
- }
123
-
124
- function normalizeLegacyActivityRequirements(value) {
125
- for (const stage of arrayMember(value, "stages")) for (const activity of arrayMember(stage, "activities")) normalizeLegacyRequirementMap(activity);
126
- return value;
127
- }
128
-
129
- function arrayMember(value, key) {
130
- if (typeof value != "object" || value === null) return [];
131
- const member = value[key];
132
- return Array.isArray(member) ? member : [];
133
- }
134
-
135
- function normalizeLegacyRequirementMap(value) {
136
- if (typeof value != "object" || value === null) return;
137
- const activity = value, requirements = activity.requirements;
138
- typeof requirements != "object" || requirements === null || Array.isArray(requirements) || (activity.requirements = Object.entries(requirements).map(([name, query]) => ({
139
- type: "groq",
140
- name: name,
141
- query: query
142
- })));
143
- }
144
-
145
- function parseDefinitionSnapshot(instance) {
146
- return parseDefinitionSnapshotValue(instance);
147
- }
148
-
149
- function parentRef(instance) {
150
- return instance.ancestors.at(-1);
151
- }
152
-
153
- const DATA_MODEL_VERSION = 5, DATA_MODEL_MIN_READER = 4, READER_MODEL_ROLLOUT_URL = "https://www.sanity.io/docs/editorial-workflows/prerelease";
154
-
155
- class ReaderModelAcknowledgementError extends WorkflowError {
156
- code="WORKFLOW_READER_MODEL_ACKNOWLEDGEMENT_MISMATCH";
157
- expectedMinReaderModel;
158
- engineMinReaderModel=DATA_MODEL_MIN_READER;
159
- engineModelVersion=DATA_MODEL_VERSION;
160
- documentationUrl=READER_MODEL_ROLLOUT_URL;
161
- constructor(expectedMinReaderModel, context = "Deployment") {
162
- const expected = expectedMinReaderModel === void 0 ? "missing" : String(expectedMinReaderModel);
163
- super("reader-model-acknowledgement", `${context} expected reader floor ${expected}; the installed engine requires acknowledgement ${DATA_MODEL_MIN_READER}. Do not change the acknowledgement yet: accepting ${DATA_MODEL_MIN_READER} authorizes this engine to write documents that older readers will refuse. Upgrade every Studio, CLI, MCP server, Function, and other runtime that reads engine-owned documents; verify that rollout in every environment sharing the workflow resource; then change the literal in deployment configuration and deploy the writer. Rollout guide: ${READER_MODEL_ROLLOUT_URL}`),
164
- this.name = "ReaderModelAcknowledgementError", this.expectedMinReaderModel = expectedMinReaderModel;
165
- }
166
- }
167
-
168
- function assertReaderModelAcknowledgement(expectedMinReaderModel, context) {
169
- if (typeof expectedMinReaderModel != "number" || !Number.isFinite(expectedMinReaderModel) || !Number.isInteger(expectedMinReaderModel) || expectedMinReaderModel < 0 || expectedMinReaderModel !== DATA_MODEL_MIN_READER) throw new ReaderModelAcknowledgementError(expectedMinReaderModel, context);
170
- }
171
-
172
- const DATA_MODEL_CHANGES = Object.freeze([ Object.freeze({
173
- id: "governed-model-stamps",
174
- introducedInModel: 1,
175
- minReaderModel: 0,
176
- documentTypes: Object.freeze([ "definition", "instance" ]),
177
- compatibility: "additive",
178
- applicability: "unconditional",
179
- summary: "Definition and instance documents carry model provenance and reader-floor stamps."
180
- }), Object.freeze({
181
- id: "subject-field-kind",
182
- introducedInModel: 2,
183
- minReaderModel: 0,
184
- documentTypes: Object.freeze([ "definition", "instance" ]),
185
- compatibility: "additive",
186
- applicability: "detectable",
187
- summary: "A workflow-level subject field identifies the document a workflow is about."
188
- }), Object.freeze({
189
- id: "typed-scalar-choice-lists",
190
- introducedInModel: 2,
191
- minReaderModel: 2,
192
- documentTypes: Object.freeze([ "definition", "instance" ]),
193
- compatibility: "reader-floor",
194
- applicability: "detectable",
195
- summary: "Scalar fields may constrain writes to a persisted typed choice list."
196
- }), Object.freeze({
197
- id: "action-semantics",
198
- introducedInModel: 2,
199
- minReaderModel: 0,
200
- documentTypes: Object.freeze([ "definition" ]),
201
- compatibility: "additive",
202
- applicability: "detectable",
203
- summary: "Ordinary actions may carry a closed bag of advisory workflow semantics."
204
- }), Object.freeze({
205
- id: "inclusive-scalar-bounds",
206
- introducedInModel: 2,
207
- minReaderModel: 2,
208
- documentTypes: Object.freeze([ "definition", "instance" ]),
209
- compatibility: "reader-floor",
210
- applicability: "detectable",
211
- summary: "String, text, and number values may carry persisted inclusive bounds."
212
- }), Object.freeze({
213
- id: "progress-field-kind",
214
- introducedInModel: 3,
215
- minReaderModel: 0,
216
- documentTypes: Object.freeze([ "definition", "instance" ]),
217
- compatibility: "additive",
218
- applicability: "detectable",
219
- summary: "A progress field kind carries application-defined 0–100 completion."
220
- }), Object.freeze({
221
- id: "effect-claim-tokens",
222
- introducedInModel: 3,
223
- minReaderModel: 0,
224
- documentTypes: Object.freeze([ "instance" ]),
225
- compatibility: "additive",
226
- applicability: "detectable",
227
- summary: "Pending-effect claims carry an exact-claim token gating mid-dispatch state reports."
228
- }), Object.freeze({
229
- id: "classified-principal-ids",
230
- introducedInModel: 4,
231
- minReaderModel: 4,
232
- documentTypes: Object.freeze([ "instance" ]),
233
- compatibility: "reader-floor",
234
- applicability: "unconditional",
235
- summary: "Principal ids are namespace-classified: actor and assignee writes carry the account-global user id only, and readers resolve legacy project-scoped ids through the prefix classifier at the instance read funnel."
236
- }), Object.freeze({
237
- id: "readiness-requirements",
238
- introducedInModel: 4,
239
- minReaderModel: 4,
240
- documentTypes: Object.freeze([ "definition" ]),
241
- compatibility: "reader-floor",
242
- applicability: "detectable",
243
- summary: "Start and activity readiness use named polymorphic requirement arrays."
244
- }), Object.freeze({
245
- id: "due-date-field-kinds",
246
- introducedInModel: 5,
247
- minReaderModel: 0,
248
- documentTypes: Object.freeze([ "definition", "instance" ]),
249
- compatibility: "additive",
250
- applicability: "detectable",
251
- summary: "Due-date field kinds (dueDate, dueDatetime) mark a level deadline, elevated aliases of date/datetime carrying the same stored value."
252
- }) ]);
253
-
254
- function recordOf(value) {
255
- return value !== null && typeof value == "object" && !Array.isArray(value) ? value : void 0;
256
- }
257
-
258
- function recordsAt(record, key) {
259
- const value = record[key];
260
- return Array.isArray(value) ? value.map(recordOf).filter(item => item !== void 0) : [];
261
- }
262
-
263
- function nestedFieldEntries(entries) {
264
- return entries.flatMap(entry => [ entry, ...nestedFieldEntries(recordsAt(entry, "fields")), ...nestedFieldEntries(recordsAt(entry, "of")) ]);
265
- }
266
-
267
- function parsedDefinitionSnapshot(root) {
268
- if (typeof root.definitionSnapshot == "string") return recordOf(parseDefinitionSnapshotValue({
269
- _id: typeof root._id == "string" ? root._id : "<unknown instance>",
270
- definitionSnapshot: root.definitionSnapshot
271
- }));
272
- }
273
-
274
- function persistedFieldEntries(document) {
275
- const root = recordOf(document);
276
- if (root === void 0) return [];
277
- 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"));
278
- 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")) ]);
279
- }
280
-
281
- function hasChoiceList(document) {
282
- return persistedFieldEntries(document).some(entry => {
283
- const options = recordOf(entry.options);
284
- return options !== void 0 && Array.isArray(options.list);
285
- });
286
- }
287
-
288
- function hasFieldKind(document, kind) {
289
- return persistedFieldEntries(document).some(entry => entry.type === kind || entry._type === kind);
290
- }
291
-
292
- function hasActionSemantics(document) {
293
- const root = recordOf(document);
294
- return root === void 0 ? !1 : recordsAt(root, "stages").flatMap(stage => recordsAt(stage, "activities")).flatMap(activity => recordsAt(activity, "actions")).some(action => Array.isArray(action.semantics));
295
- }
296
-
297
- function hasScalarValidation(document) {
298
- return persistedFieldEntries(document).some(entry => {
299
- const validation = recordOf(entry.validation);
300
- return typeof validation?.min == "number" || typeof validation?.max == "number";
301
- });
302
- }
303
-
304
- function hasClaimTokens(document) {
305
- const root = recordOf(document);
306
- return root === void 0 ? !1 : recordsAt(root, "pendingEffects").some(entry => {
307
- const claim = recordOf(entry.claim);
308
- return claim !== void 0 && typeof claim.claimToken == "string";
309
- });
310
- }
311
-
312
- function hasReadinessRequirements(document) {
313
- const root = recordOf(document);
314
- return root === void 0 ? !1 : Array.isArray(recordOf(root.start)?.requirements) ? !0 : recordsAt(root, "stages").some(stage => recordsAt(stage, "activities").some(activity => Array.isArray(activity.requirements)));
315
- }
316
-
317
- const featureDetectors = {
318
- "governed-model-stamps": () => !0,
319
- "subject-field-kind": document => hasFieldKind(document, "subject"),
320
- "typed-scalar-choice-lists": hasChoiceList,
321
- "action-semantics": hasActionSemantics,
322
- "inclusive-scalar-bounds": hasScalarValidation,
323
- "progress-field-kind": document => hasFieldKind(document, "progress"),
324
- "effect-claim-tokens": hasClaimTokens,
325
- "classified-principal-ids": () => !0,
326
- "readiness-requirements": hasReadinessRequirements,
327
- "due-date-field-kinds": document => hasFieldKind(document, "dueDate") || hasFieldKind(document, "dueDatetime")
328
- };
329
-
330
- function requiredModelFeatures(documentType, document) {
331
- return DATA_MODEL_CHANGES.filter(change => change.documentTypes.some(candidate => candidate === documentType) && featureDetectors[change.id](document));
332
- }
333
-
334
- function requiredReaderModel(documentType, document) {
335
- return Math.max(0, ...requiredModelFeatures(documentType, document).map(change => change.minReaderModel));
336
- }
337
-
338
- function modelStampFor(args) {
339
- return {
340
- modelVersion: DATA_MODEL_VERSION,
341
- minReaderModel: Math.max(DATA_MODEL_MIN_READER, args.storedMinReaderModel ?? 0, requiredReaderModel(args.documentType, args.document))
342
- };
343
- }
344
-
345
- function fieldTreeShape(value) {
346
- if (Array.isArray(value)) return value.map(fieldTreeShape);
347
- if (value === null) return "null";
348
- if (typeof value == "object") {
349
- const record = value;
350
- return Object.fromEntries(Object.keys(record).toSorted().map(key => [ key, fieldTreeShape(record[key]) ]));
351
- }
352
- return typeof value;
353
- }
354
-
355
- function modelVersionOf(doc) {
356
- const stamp = doc.modelVersion;
357
- return typeof stamp == "number" ? stamp : 0;
358
- }
359
-
360
- function minReaderModelOf(doc) {
361
- const floor = doc.minReaderModel;
362
- return typeof floor == "number" ? floor : modelVersionOf(doc);
363
- }
364
-
365
- class ModelVersionAheadError extends WorkflowError {
366
- documentId;
367
- documentModelVersion;
368
- requiredReaderModel;
369
- engineModelVersion;
370
- constructor(args) {
371
- 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.`),
372
- this.name = "ModelVersionAheadError", this.documentId = args.documentId, this.documentModelVersion = args.documentModelVersion,
373
- this.requiredReaderModel = args.requiredReaderModel, this.engineModelVersion = DATA_MODEL_VERSION;
374
- }
375
- }
376
-
377
- function assertReadableModel(doc) {
378
- const documentReaderModel = minReaderModelOf(doc);
379
- if (documentReaderModel > DATA_MODEL_VERSION) throw new ModelVersionAheadError({
380
- documentId: doc._id,
381
- documentModelVersion: modelVersionOf(doc),
382
- requiredReaderModel: documentReaderModel
383
- });
384
- return doc;
385
- }
386
-
387
- function isCascadeFired(action) {
388
- return action.when !== void 0;
389
- }
390
-
391
- function deriveActivityKind(activity) {
392
- if (activity.target !== void 0) return "manual";
393
- const actions = activity.actions ?? [];
394
- return actions.some(a => !isCascadeFired(a)) ? "user" : actions.some(a => (a.effects ?? []).length > 0 || a.spawn !== void 0) ? "service" : actions.length > 0 ? "receive" : "script";
395
- }
396
-
397
- function deriveExecutorClassification(activity) {
398
- if (activity.target !== void 0) return "off-system";
399
- const actions = activity.actions ?? [], cascadeFired = actions.filter(isCascadeFired).length;
400
- return cascadeFired === actions.length ? "autonomous" : cascadeFired === 0 ? "interactive" : "hybrid";
401
- }
402
-
403
- function driverKind(actor) {
404
- return actor.kind === "person" || actor.kind === "agent" ? actor.kind : "service";
405
- }
406
-
407
- function andConditions(parts) {
408
- const present = parts.filter(p => p !== void 0);
409
- if (present.length !== 0) return present.length === 1 ? present[0] : present.map(p => `(${p})`).join(" && ");
410
- }
411
-
412
131
  const KNOWN_SCHEMES = /* @__PURE__ */ new Set([ "dataset", "canvas", "media-library", "dashboard" ]), KNOWN_SCHEMES_TEXT = [ ...KNOWN_SCHEMES ].join(", ");
413
132
 
414
133
  class VersionSpecificDatasetGdrError extends Error {
@@ -820,6 +539,7 @@ function desugarWorkflow(authoring) {
820
539
  return {
821
540
  ...stripUndefined({
822
541
  name: stage.name,
542
+ semantics: stage.semantics,
823
543
  title: stage.title,
824
544
  description: stage.description,
825
545
  groups: stage.groups,
@@ -843,6 +563,7 @@ function desugarWorkflow(authoring) {
843
563
  definition: {
844
564
  ...stripUndefined({
845
565
  name: authoring.name,
566
+ semantics: authoring.semantics,
846
567
  title: authoring.title,
847
568
  description: authoring.description,
848
569
  groups: authoring.groups,
@@ -1069,6 +790,7 @@ function desugarActivity({activity: activity, path: path, stageEnv: stageEnv, ct
1069
790
  return {
1070
791
  ...stripUndefined({
1071
792
  name: activity.name,
793
+ semantics: activity.semantics,
1072
794
  title: activity.title,
1073
795
  description: activity.description,
1074
796
  groups: activity.groups,
@@ -1540,7 +1262,58 @@ function isTerminalActivityStatus(status) {
1540
1262
  return TERMINAL_ACTIVITY_STATUSES.includes(status);
1541
1263
  }
1542
1264
 
1543
- 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 = [ {
1265
+ const SIGNAL_SEMANTICS = [ "signal.positive", "signal.caution", "signal.critical" ], DECISION_SEMANTICS = [ "decision.accept", "decision.decline" ], ACTION_SEMANTICS = [ ...DECISION_SEMANTICS, ...SIGNAL_SEMANTICS ], 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" ];
1266
+
1267
+ function releaseDocId(releaseName) {
1268
+ return `_.releases.${releaseName}`;
1269
+ }
1270
+
1271
+ function releaseRef({res: res, releaseName: releaseName}) {
1272
+ if (releaseName.length === 0) throw new ContractViolationError("releaseRef: releaseName must be a non-empty release name");
1273
+ return {
1274
+ id: gdrFromResource(res, releaseDocId(releaseName)),
1275
+ type: "system.release",
1276
+ releaseName: releaseName
1277
+ };
1278
+ }
1279
+
1280
+ function isAlwaysArrayFieldKind(kind) {
1281
+ return kind === "doc.refs" || kind === "assignees" || kind === "array";
1282
+ }
1283
+
1284
+ function isSingleDocRefKind(kind) {
1285
+ return kind === "doc.ref" || kind === "subject";
1286
+ }
1287
+
1288
+ function refKindAcceptsTypes(kind) {
1289
+ return isSingleDocRefKind(kind) || kind === "doc.refs";
1290
+ }
1291
+
1292
+ function isSingleDocRefEntry(entry) {
1293
+ return isSingleDocRefKind(entry._type);
1294
+ }
1295
+
1296
+ function isTodoListItem(row) {
1297
+ if (typeof row != "object" || row === null) return !1;
1298
+ const candidate = row, status = candidate.status;
1299
+ return typeof candidate._key == "string" && typeof candidate.label == "string" && (status == null || typeof status == "string");
1300
+ }
1301
+
1302
+ function declaredRowColumns(entry) {
1303
+ if (("_type" in entry ? entry._type : entry.type) === "array") return new Set((("of" in entry ? entry.of : void 0) ?? []).map(shape => shape.name));
1304
+ }
1305
+
1306
+ function isTodoListEntry(entry) {
1307
+ const columns = declaredRowColumns(entry);
1308
+ return columns !== void 0 && columns.has("label") && columns.has("status");
1309
+ }
1310
+
1311
+ function isNotesEntry(entry) {
1312
+ const columns = declaredRowColumns(entry);
1313
+ return columns !== void 0 && columns.has("body") && columns.has("actor") && columns.has("at");
1314
+ }
1315
+
1316
+ const CONDITION_VARS = [ {
1544
1317
  name: "self",
1545
1318
  binding: "always",
1546
1319
  label: "this workflow instance",
@@ -1615,6 +1388,11 @@ const ACTION_SEMANTICS = [ "decision.accept", "decision.decline" ], FIELD_SCOPES
1615
1388
  binding: "caller",
1616
1389
  label: "your permissions",
1617
1390
  description: "Advisory per-permission booleans computed from the caller's grants; `undefined` without grants. Bound wherever grants ride the evaluation: the projection's rendered scope (fireAction-action filters, activity requirements, editability predicates) and the fireAction/editField commit gates. Deploy rejects it at every site that evaluates without grants: transition `when`s, activity filters, cascade-fired actions' `when`/`filter`, effect bindings, where-op `where`s, and the spawn `forEach`/`with`/`context` sites."
1391
+ }, {
1392
+ name: "attributes",
1393
+ binding: "caller",
1394
+ label: "your attributes",
1395
+ description: "Advisory org-level User Attributes for the caller (Enterprise — same values as lake `user::attributes()`), keyed by attribute name with each active scalar or array value. `undefined` on expected HTTP absence; unexpected fetch failures throw; empty page binds `{}`. Bound wherever grants ride the evaluation (same sites as `$can`). Soft-gate paths fetch at most 100 attributes (no further pages) and warn when the envelope reports `hasMore: true` (partial bag still binds). Not a security boundary — the Content Lake remains the only enforcement point."
1618
1396
  }, {
1619
1397
  name: "row",
1620
1398
  binding: "spawn",
@@ -1780,54 +1558,7 @@ function documentIdOf(doc) {
1780
1558
  return "(unknown id)";
1781
1559
  }
1782
1560
 
1783
- const ACTOR_KINDS = [ "person", "agent", "system" ];
1784
-
1785
- function releaseDocId(releaseName) {
1786
- return `_.releases.${releaseName}`;
1787
- }
1788
-
1789
- function releaseRef({res: res, releaseName: releaseName}) {
1790
- if (releaseName.length === 0) throw new ContractViolationError("releaseRef: releaseName must be a non-empty release name");
1791
- return {
1792
- id: gdrFromResource(res, releaseDocId(releaseName)),
1793
- type: "system.release",
1794
- releaseName: releaseName
1795
- };
1796
- }
1797
-
1798
- function isSingleDocRefKind(kind) {
1799
- return kind === "doc.ref" || kind === "subject";
1800
- }
1801
-
1802
- function refKindAcceptsTypes(kind) {
1803
- return isSingleDocRefKind(kind) || kind === "doc.refs";
1804
- }
1805
-
1806
- function isSingleDocRefEntry(entry) {
1807
- return isSingleDocRefKind(entry._type);
1808
- }
1809
-
1810
- function isTodoListItem(row) {
1811
- if (typeof row != "object" || row === null) return !1;
1812
- const candidate = row, status = candidate.status;
1813
- return typeof candidate._key == "string" && typeof candidate.label == "string" && (status == null || typeof status == "string");
1814
- }
1815
-
1816
- function declaredRowColumns(entry) {
1817
- if (("_type" in entry ? entry._type : entry.type) === "array") return new Set((("of" in entry ? entry.of : void 0) ?? []).map(shape => shape.name));
1818
- }
1819
-
1820
- function isTodoListEntry(entry) {
1821
- const columns = declaredRowColumns(entry);
1822
- return columns !== void 0 && columns.has("label") && columns.has("status");
1823
- }
1824
-
1825
- function isNotesEntry(entry) {
1826
- const columns = declaredRowColumns(entry);
1827
- return columns !== void 0 && columns.has("body") && columns.has("actor") && columns.has("at");
1828
- }
1829
-
1830
- const ANONYMOUS_IDENTITY = "<anonymous>", SYSTEM_IDENTITY = "<system>", E_PREFIXED_PROJECT_ID = /^e-(.+)$/;
1561
+ const ACTOR_KINDS = [ "person", "agent", "system" ], ANONYMOUS_IDENTITY = "<anonymous>", SYSTEM_IDENTITY = "<system>", E_PREFIXED_PROJECT_ID = /^e-(.+)$/;
1831
1562
 
1832
1563
  function classifyPrincipalId(id) {
1833
1564
  if (id === ANONYMOUS_IDENTITY || id === SYSTEM_IDENTITY) return {
@@ -2256,6 +1987,10 @@ function opSchemas(targetSchema) {
2256
1987
  type: v__namespace.literal("field.set"),
2257
1988
  target: targetSchema,
2258
1989
  value: ValueExprSchema
1990
+ }), v__namespace.strictObject({
1991
+ type: v__namespace.literal("field.setIfMissing"),
1992
+ target: targetSchema,
1993
+ value: ValueExprSchema
2259
1994
  }), v__namespace.strictObject({
2260
1995
  type: v__namespace.literal("field.unset"),
2261
1996
  target: targetSchema
@@ -2263,6 +1998,14 @@ function opSchemas(targetSchema) {
2263
1998
  type: v__namespace.literal("field.append"),
2264
1999
  target: targetSchema,
2265
2000
  value: ValueExprSchema
2001
+ }), v__namespace.strictObject({
2002
+ type: v__namespace.literal("field.inc"),
2003
+ target: targetSchema,
2004
+ value: v__namespace.optional(ValueExprSchema)
2005
+ }), v__namespace.strictObject({
2006
+ type: v__namespace.literal("field.dec"),
2007
+ target: targetSchema,
2008
+ value: v__namespace.optional(ValueExprSchema)
2266
2009
  }), v__namespace.strictObject({
2267
2010
  type: v__namespace.literal("field.updateWhere"),
2268
2011
  target: targetSchema,
@@ -2479,17 +2222,27 @@ const TodoListFieldSchema = pinned()(v__namespace.strictObject(listSugarFields("
2479
2222
  required: v__namespace.optional(v__namespace.boolean()),
2480
2223
  options: v__namespace.optional(ChoiceOptionsSchema),
2481
2224
  validation: v__namespace.optional(ScalarValidationSchema)
2482
- }), choiceOptionsCheck(), scalarValidationCheck());
2225
+ }), choiceOptionsCheck(), scalarValidationCheck()), CUSTOM_SEMANTIC_HINT = "`custom.<camelCaseMeaning>`", CustomSemanticSchema = v__namespace.custom(input => typeof input == "string" && /^custom\.[a-z][a-zA-Z0-9]*$/.test(input)), SemanticSchema = v__namespace.union([ picklist(SIGNAL_SEMANTICS), CustomSemanticSchema ], `expected ${SIGNAL_SEMANTICS.join(", ")}, or ${CUSTOM_SEMANTIC_HINT}`), ActionSemanticSchema = v__namespace.union([ picklist(ACTION_SEMANTICS), CustomSemanticSchema ], `expected ${ACTION_SEMANTICS.join(", ")}, or ${CUSTOM_SEMANTIC_HINT}`);
2226
+
2227
+ function semanticNamespace(semantic) {
2228
+ return semantic.startsWith("custom.") ? semantic : semantic.split(".", 1)[0] ?? semantic;
2229
+ }
2483
2230
 
2484
2231
  function hasUniqueSemanticNamespaces(semantics) {
2485
- const namespaces = semantics.map(semantic => semantic.split(".", 1)[0]);
2232
+ const namespaces = semantics.map(semanticNamespace);
2486
2233
  return new Set(namespaces).size === namespaces.length;
2487
2234
  }
2488
2235
 
2236
+ function semanticsFieldSchema(semantic) {
2237
+ return v__namespace.optional(v__namespace.pipe(v__namespace.array(semantic), v__namespace.minLength(1, "declare at least one semantic, or omit `semantics`"), v__namespace.check(hasUniqueSemanticNamespaces, "declare at most one semantic from each namespace")));
2238
+ }
2239
+
2240
+ const SemanticsFieldSchema = semanticsFieldSchema(SemanticSchema), ActionSemanticsFieldSchema = semanticsFieldSchema(ActionSemanticSchema);
2241
+
2489
2242
  function actionFields(op, group) {
2490
2243
  return {
2491
2244
  name: NonEmpty,
2492
- 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"))),
2245
+ semantics: ActionSemanticsFieldSchema,
2493
2246
  title: v__namespace.optional(v__namespace.string()),
2494
2247
  description: v__namespace.optional(v__namespace.string()),
2495
2248
  group: v__namespace.optional(group),
@@ -2536,6 +2289,7 @@ const StoredActionSchema = pinned()(v__namespace.strictObject({
2536
2289
  function activityFields({field: field, action: action, target: target, group: group}) {
2537
2290
  return {
2538
2291
  name: NonEmpty,
2292
+ semantics: SemanticsFieldSchema,
2539
2293
  title: v__namespace.optional(v__namespace.string()),
2540
2294
  description: v__namespace.optional(v__namespace.string()),
2541
2295
  groups: v__namespace.optional(v__namespace.array(GroupSchema)),
@@ -2609,6 +2363,7 @@ const GuardSchema = v__namespace.strictObject(guardFields(NonEmpty)), AuthoringG
2609
2363
  function stageFields({field: field, activity: activity, transition: transition, guard: guard, editable: editable}) {
2610
2364
  return {
2611
2365
  name: NonEmpty,
2366
+ semantics: SemanticsFieldSchema,
2612
2367
  title: v__namespace.optional(v__namespace.string()),
2613
2368
  description: v__namespace.optional(v__namespace.string()),
2614
2369
  groups: v__namespace.optional(v__namespace.array(GroupSchema)),
@@ -2647,6 +2402,7 @@ const StoredStartSchema = pinned()(v__namespace.strictObject(startFields(picklis
2647
2402
  function workflowFields({field: field, stage: stage, start: start}) {
2648
2403
  return {
2649
2404
  name: NonEmpty,
2405
+ semantics: SemanticsFieldSchema,
2650
2406
  title: NonEmpty,
2651
2407
  description: v__namespace.optional(v__namespace.string()),
2652
2408
  groups: v__namespace.optional(v__namespace.array(GroupSchema)),
@@ -2843,11 +2599,20 @@ function checkStageReachability({def: def, stageNames: stageNames, issues: issue
2843
2599
  });
2844
2600
  }
2845
2601
 
2602
+ function actionSites(def) {
2603
+ return def.stages.flatMap((stage, i) => (stage.activities ?? []).flatMap((activity, j) => (activity.actions ?? []).map((action, a) => ({
2604
+ action: action,
2605
+ activity: activity,
2606
+ stage: stage,
2607
+ path: [ "stages", i, "activities", j, "actions", a ]
2608
+ }))));
2609
+ }
2610
+
2846
2611
  function effectNameSites(def) {
2847
2612
  const sites = [];
2848
- for (const [i, stage] of def.stages.entries()) for (const [j, activity] of (stage.activities ?? []).entries()) for (const [a, action] of (activity.actions ?? []).entries()) collectEffects({
2613
+ for (const {action: action, path: path} of actionSites(def)) collectEffects({
2849
2614
  effects: action.effects,
2850
- path: [ "stages", i, "activities", j, "actions", a, "effects" ],
2615
+ path: [ ...path, "effects" ],
2851
2616
  sites: sites
2852
2617
  });
2853
2618
  return sites;
@@ -2978,13 +2743,22 @@ function checkUnboundConditionVars(def, issues) {
2978
2743
  }
2979
2744
  }
2980
2745
 
2746
+ const SOFT_GATE_VARS = {
2747
+ can: {
2748
+ noun: "the caller's grants"
2749
+ },
2750
+ attributes: {
2751
+ noun: "the caller's org-level user attributes"
2752
+ }
2753
+ }, SOFT_GATE_VAR_NAMES = Object.keys(SOFT_GATE_VARS);
2754
+
2981
2755
  function unboundVarsAt(site) {
2982
2756
  const callerVars = unboundCallerVars(site.policy);
2983
2757
  return site.bindsRow === !0 ? callerVars : [ ...callerVars, "row" ];
2984
2758
  }
2985
2759
 
2986
2760
  function unboundCallerVars(policy) {
2987
- return policy === "cascade" ? CALLER_BOUND_VARS : policy === "caller-bound" ? [ "params" ] : policy === "triggered-payload" ? [ "can", "params" ] : [ "can" ];
2761
+ return policy === "cascade" ? CALLER_BOUND_VARS : policy === "caller-bound" ? [ "params" ] : policy === "triggered-payload" ? [ ...SOFT_GATE_VAR_NAMES, "params" ] : SOFT_GATE_VAR_NAMES;
2988
2762
  }
2989
2763
 
2990
2764
  const ROW_BINDING_CLAUSE = "$row (the discovered row in a spawn projection; the stored row under test in a where-op) is bound only while a spawn `with` projection or a where-op `where` evaluates";
@@ -2994,7 +2768,12 @@ function rowVarMessage(site) {
2994
2768
  }
2995
2769
 
2996
2770
  function callerVarMessage(site, name) {
2997
- return site.policy === "cascade" ? `${site.label} reads $${name} — cascade gates (transition \`when\`s, activity \`filter\`s, a cascade-fired action's \`when\`/\`filter\`) must resolve identically no matter whose token drives the cascade ($assigned is constant false, the other caller vars hold no value); gate on instance state (e.g. a field an action wrote), or pin executing identities with \`roles\`` : site.policy === "caller-bound" ? `${site.label} reads $${name} — $params (the firing action's args) is bound only while the action's effect bindings and where-op \`where\`s evaluate; this site never binds it, so the condition could never pass. Bind $params in an effect binding or a where-op instead, or gate on a field an action wrote` : site.policy === "triggered-payload" && name === "params" ? `${site.label} reads $params — a cascade-fired action has no caller to supply args, so $params never holds a value in its payload; read fields or effect outputs instead` : `${site.label} reads $can — $can (the caller's grants) is bound only in the caller-bound projection (action filters, requirements, editable predicates) and never holds a value in cascade conditions; move the check to one of those sites or drop $can`;
2771
+ if (site.policy === "cascade") return `${site.label} reads $${name} — cascade gates (transition \`when\`s, activity \`filter\`s, a cascade-fired action's \`when\`/\`filter\`) must resolve identically no matter whose token drives the cascade ($assigned is constant false, the other caller vars hold no value); gate on instance state (e.g. a field an action wrote), or pin executing identities with \`roles\``;
2772
+ if (site.policy === "caller-bound") return `${site.label} reads $${name} — $params (the firing action's args) is bound only while the action's effect bindings and where-op \`where\`s evaluate; this site never binds it, so the condition could never pass. Bind $params in an effect binding or a where-op instead, or gate on a field an action wrote`;
2773
+ if (site.policy === "triggered-payload" && name === "params") return `${site.label} reads $params — a cascade-fired action has no caller to supply args, so $params never holds a value in its payload; read fields or effect outputs instead`;
2774
+ const softGate = SOFT_GATE_VARS[name];
2775
+ if (softGate !== void 0) return `${site.label} reads $${name} — $${name} (${softGate.noun}) is bound only in the caller-bound projection (action filters, requirements, editable predicates); this site never binds it. Move the check to one of those sites or drop $${name}`;
2776
+ throw new Error(`callerVarMessage: unreachable for $${name} at ${site.label} (policy ${site.policy})`);
2998
2777
  }
2999
2778
 
3000
2779
  function conditionSites(def) {
@@ -3249,9 +3028,9 @@ function belowScopeNestedSites(args) {
3249
3028
  }
3250
3029
 
3251
3030
  function checkLevelKindEffectOutputs(def, issues) {
3252
- for (const [i, stage] of def.stages.entries()) for (const [j, activity] of (stage.activities ?? []).entries()) for (const [a, action] of (activity.actions ?? []).entries()) pushOutputIssues({
3031
+ for (const {action: action, path: path} of actionSites(def)) pushOutputIssues({
3253
3032
  action: action,
3254
- path: [ "stages", i, "activities", j, "actions", a ],
3033
+ path: path,
3255
3034
  issues: issues
3256
3035
  });
3257
3036
  }
@@ -3333,18 +3112,18 @@ function storedRolesIssue(action) {
3333
3112
  }
3334
3113
 
3335
3114
  function checkStoredRolesPlacement(def, issues) {
3336
- for (const [i, stage] of def.stages.entries()) for (const [j, activity] of (stage.activities ?? []).entries()) for (const [a, action] of (activity.actions ?? []).entries()) {
3115
+ for (const {action: action, path: path} of actionSites(def)) {
3337
3116
  const message = storedRolesIssue(action);
3338
3117
  message !== void 0 && issues.push({
3339
- path: [ "stages", i, "activities", j, "actions", a, "roles" ],
3118
+ path: [ ...path, "roles" ],
3340
3119
  message: message
3341
3120
  });
3342
3121
  }
3343
3122
  }
3344
3123
 
3345
3124
  function checkTriggeredActionParams(def, issues) {
3346
- for (const [i, stage] of def.stages.entries()) for (const [j, activity] of (stage.activities ?? []).entries()) for (const [a, action] of (activity.actions ?? []).entries()) action.when === void 0 || (action.params ?? []).length === 0 || issues.push({
3347
- path: [ "stages", i, "activities", j, "actions", a, "params" ],
3125
+ for (const {action: action, path: path} of actionSites(def)) action.when === void 0 || (action.params ?? []).length === 0 || issues.push({
3126
+ path: [ ...path, "params" ],
3348
3127
  message: `action "${action.name}" declares params but is cascade-fired (\`when\`) — no caller ever supplies args to a trigger. Drop the params, or drop \`when\` to make it a fireAction-fired action`
3349
3128
  });
3350
3129
  }
@@ -3389,13 +3168,20 @@ function checkSingleSubjectRequirements(def, issues) {
3389
3168
 
3390
3169
  function checkStartFilterReads(def, issues) {
3391
3170
  const filter = def.start?.filter;
3392
- filter !== void 0 && (conditionParameterNames(filter).has("fields") && issues.push({
3171
+ if (filter === void 0) return;
3172
+ const params = conditionParameterNames(filter);
3173
+ params.has("fields") && issues.push({
3393
3174
  path: [ "start", "filter" ],
3394
3175
  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 a start requirement, the start-time readiness predicate that binds $fields and is enforced by startInstance"
3395
- }), readsRootDocument(filter) && !(def.fields ?? []).some(isSubjectEntry) && issues.push({
3176
+ });
3177
+ for (const name of CALLER_BOUND_VARS) params.has(name) && issues.push({
3178
+ path: [ "start", "filter" ],
3179
+ message: `start.filter reads $${name} — start.filter is a read-side document-visibility rule (definitionsForDocument / start controls); startInstance never evaluates it, and no caller bag binds there, so the read is GROQ null and the filter can never match. Drop $${name} from start.filter. A "who may start" rule belongs in a start requirement, not in the browse-time filter`
3180
+ });
3181
+ readsRootDocument(filter) && !(def.fields ?? []).some(isSubjectEntry) && issues.push({
3396
3182
  path: [ "start", "filter" ],
3397
3183
  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"
3398
- }));
3184
+ });
3399
3185
  }
3400
3186
 
3401
3187
  function checkStartRequirementReads(def, issues) {
@@ -3691,15 +3477,13 @@ function seedEarlierSiblingTarget(args) {
3691
3477
  }
3692
3478
 
3693
3479
  function opSites(def) {
3694
- const sites = [];
3695
- for (const [i, stage] of def.stages.entries()) for (const [j, activity] of (stage.activities ?? []).entries()) for (const [a, action] of (activity.actions ?? []).entries()) sites.push({
3480
+ return actionSites(def).map(({action: action, activity: activity, stage: stage, path: path}) => ({
3696
3481
  ops: action.ops,
3697
- path: [ "stages", i, "activities", j, "actions", a, "ops" ],
3482
+ path: [ ...path, "ops" ],
3698
3483
  label: `action "${action.name}"`,
3699
3484
  stage: stage,
3700
3485
  activity: activity
3701
- });
3702
- return sites;
3486
+ }));
3703
3487
  }
3704
3488
 
3705
3489
  function checkFieldReadOpValues(def, issues) {
@@ -3716,7 +3500,7 @@ function checkFieldReadOpValues(def, issues) {
3716
3500
  }
3717
3501
 
3718
3502
  function checkOpsFieldReads({ops: ops, path: path, label: label, ...ctx}) {
3719
- for (const [o, op] of (ops ?? []).entries()) if ("value" in op) for (const {read: read, path: readPath} of fieldReadsIn(op.value, [ ...path, o, "value" ])) checkOpFieldRead({
3503
+ for (const [o, op] of (ops ?? []).entries()) if (!(!("value" in op) || op.value === void 0)) for (const {read: read, path: readPath} of fieldReadsIn(op.value, [ ...path, o, "value" ])) checkOpFieldRead({
3720
3504
  ...ctx,
3721
3505
  read: read,
3722
3506
  path: readPath,
@@ -3767,35 +3551,55 @@ function opFieldReadMissMessage({read: read, where: where, hosts: hosts}) {
3767
3551
  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)"}`;
3768
3552
  }
3769
3553
 
3770
- function checkUpdateWhereOps(def, issues) {
3554
+ function checkFieldTargetOps(def, issues) {
3771
3555
  const workflow = def.fields ?? [];
3772
3556
  for (const site of opSites(def)) for (const [o, op] of (site.ops ?? []).entries()) {
3773
- if (op.type !== "field.updateWhere") continue;
3774
- const scopes = {
3775
- workflow: workflow,
3776
- stage: site.stage.fields ?? [],
3777
- activity: site.activity.fields ?? []
3778
- };
3779
- checkUpdateWhereTargetKind({
3557
+ const path = [ ...site.path, o ], rule = TARGET_KIND_RULES[op.type];
3558
+ rule !== void 0 && "target" in op && checkTargetKind({
3780
3559
  op: op,
3781
- path: [ ...site.path, o ],
3560
+ path: [ ...path, "target" ],
3782
3561
  label: site.label,
3783
- scopes: scopes,
3562
+ scopes: opTargetScopes(workflow, site),
3563
+ rule: rule,
3784
3564
  issues: issues
3785
- }), checkUpdateWhereMergeKeys({
3565
+ }), op.type === "field.updateWhere" && checkUpdateWhereMergeKeys({
3786
3566
  op: op,
3787
- path: [ ...site.path, o ],
3567
+ path: path,
3788
3568
  label: site.label,
3789
3569
  issues: issues
3790
3570
  });
3791
3571
  }
3792
3572
  }
3793
3573
 
3794
- function checkUpdateWhereTargetKind({op: op, path: path, label: label, scopes: scopes, issues: issues}) {
3574
+ const arithmeticTargetRule = {
3575
+ accepts: target => target.type === "number",
3576
+ issue: () => "arithmetic ops target `number` entries only"
3577
+ }, TARGET_KIND_RULES = {
3578
+ "field.inc": arithmeticTargetRule,
3579
+ "field.dec": arithmeticTargetRule,
3580
+ "field.setIfMissing": {
3581
+ accepts: target => !isAlwaysArrayFieldKind(target.type),
3582
+ issue: () => "setIfMissing applies to nullable entries only; an empty array entry already holds []"
3583
+ },
3584
+ "field.updateWhere": {
3585
+ accepts: target => target.type === "array",
3586
+ issue: target => "updateWhere merges declared row sub-fields, so its target must be an `array` entry" + rowOpsHint(target.type)
3587
+ }
3588
+ };
3589
+
3590
+ function opTargetScopes(workflow, site) {
3591
+ return {
3592
+ workflow: workflow,
3593
+ stage: site.stage.fields ?? [],
3594
+ activity: site.activity.fields ?? []
3595
+ };
3596
+ }
3597
+
3598
+ function checkTargetKind({op: op, path: path, label: label, scopes: scopes, rule: rule, issues: issues}) {
3795
3599
  const target = scopes[op.target.scope]?.find(entry => entry.name === op.target.field);
3796
- target === void 0 || target.type === "array" || issues.push({
3797
- path: [ ...path, "target" ],
3798
- message: `${label} field.updateWhere targets ${op.target.scope}-scope "${op.target.field}" (${target.type}) — updateWhere merges declared row sub-fields, so its target must be an \`array\` entry${rowOpsHint(target.type)}`
3600
+ target === void 0 || rule.accepts(target) || issues.push({
3601
+ path: path,
3602
+ message: `${label} ${op.type} targets ${op.target.scope}-scope "${op.target.field}" (${target.type}) — ${rule.issue(target)}`
3799
3603
  });
3800
3604
  }
3801
3605
 
@@ -4027,7 +3831,7 @@ function checkWorkflowInvariants(def) {
4027
3831
  }), checkEffectNames(def, issues), checkGuardNames(def, issues), checkFieldEntryNames(def, issues),
4028
3832
  checkRequiredField(def, issues), checkStart(def, issues), checkPredicates(def, issues),
4029
3833
  checkUnboundConditionVars(def, issues), checkConditionFieldReads(def, issues), checkFieldReadSeeds(def, issues),
4030
- checkFieldReadOpValues(def, issues), checkUpdateWhereOps(def, issues), checkGuardFieldReads(def, issues),
3834
+ checkFieldReadOpValues(def, issues), checkFieldTargetOps(def, issues), checkGuardFieldReads(def, issues),
4031
3835
  checkAssigneesEntries(def, issues), checkDueDateEntries(def, issues), checkSubjectEntries(def, issues),
4032
3836
  checkLevelKindEffectOutputs(def, issues), checkActivityTerminalPaths(def, issues),
4033
3837
  checkTerminalStageActivities(def, issues), checkTriggeredActionParams(def, issues),
@@ -4068,11 +3872,7 @@ exports.CONDITION_VARS = CONDITION_VARS;
4068
3872
 
4069
3873
  exports.ContractViolationError = ContractViolationError;
4070
3874
 
4071
- exports.DATA_MODEL_CHANGES = DATA_MODEL_CHANGES;
4072
-
4073
- exports.DATA_MODEL_MIN_READER = DATA_MODEL_MIN_READER;
4074
-
4075
- exports.DATA_MODEL_VERSION = DATA_MODEL_VERSION;
3875
+ exports.DECISION_SEMANTICS = DECISION_SEMANTICS;
4076
3876
 
4077
3877
  exports.DEFAULT_TRANSITION_WHEN = DEFAULT_TRANSITION_WHEN;
4078
3878
 
@@ -4116,19 +3916,15 @@ exports.IsoTimestamp = IsoTimestamp;
4116
3916
 
4117
3917
  exports.MUTATION_GUARD_ACTIONS = MUTATION_GUARD_ACTIONS;
4118
3918
 
4119
- exports.ModelVersionAheadError = ModelVersionAheadError;
4120
-
4121
3919
  exports.NonEmptyString = NonEmptyString;
4122
3920
 
4123
3921
  exports.PersistedDocShapeError = PersistedDocShapeError;
4124
3922
 
4125
- exports.READER_MODEL_ROLLOUT_URL = READER_MODEL_ROLLOUT_URL;
4126
-
4127
3923
  exports.RESERVED_CONDITION_VARS = RESERVED_CONDITION_VARS;
4128
3924
 
4129
3925
  exports.RESOURCE_ALIAS_NAME_SOURCE = RESOURCE_ALIAS_NAME_SOURCE;
4130
3926
 
4131
- exports.ReaderModelAcknowledgementError = ReaderModelAcknowledgementError;
3927
+ exports.SIGNAL_SEMANTICS = SIGNAL_SEMANTICS;
4132
3928
 
4133
3929
  exports.START_FILTER_VARS = START_FILTER_VARS;
4134
3930
 
@@ -4144,8 +3940,6 @@ exports.VersionSpecificDatasetGdrError = VersionSpecificDatasetGdrError;
4144
3940
 
4145
3941
  exports.WORKFLOW_DEFINITION_TYPE = WORKFLOW_DEFINITION_TYPE;
4146
3942
 
4147
- exports.WORKFLOW_INSTANCE_TYPE = WORKFLOW_INSTANCE_TYPE;
4148
-
4149
3943
  exports.WorkflowConfigSchema = WorkflowConfigSchema;
4150
3944
 
4151
3945
  exports.WorkflowError = WorkflowError;
@@ -4154,10 +3948,6 @@ exports.actorFulfillsRole = actorFulfillsRole;
4154
3948
 
4155
3949
  exports.andConditions = andConditions;
4156
3950
 
4157
- exports.assertReadableModel = assertReadableModel;
4158
-
4159
- exports.assertReaderModelAcknowledgement = assertReaderModelAcknowledgement;
4160
-
4161
3951
  exports.checkWorkflowInvariants = checkWorkflowInvariants;
4162
3952
 
4163
3953
  exports.choiceValueIssues = choiceValueIssues;
@@ -4198,8 +3988,6 @@ exports.evaluatePredicates = evaluatePredicates;
4198
3988
 
4199
3989
  exports.extractDocumentId = extractDocumentId;
4200
3990
 
4201
- exports.fieldTreeShape = fieldTreeShape;
4202
-
4203
3991
  exports.fieldValueSchemas = fieldValueSchemas;
4204
3992
 
4205
3993
  exports.firstCarriedGlobalId = firstCarriedGlobalId;
@@ -4222,6 +4010,8 @@ exports.groq = groq;
4222
4010
 
4223
4011
  exports.groupMembershipNames = groupMembershipNames;
4224
4012
 
4013
+ exports.isAlwaysArrayFieldKind = isAlwaysArrayFieldKind;
4014
+
4225
4015
  exports.isBareSeedId = isBareSeedId;
4226
4016
 
4227
4017
  exports.isCascadeFired = isCascadeFired;
@@ -4254,24 +4044,10 @@ exports.isTodoListItem = isTodoListItem;
4254
4044
 
4255
4045
  exports.isUnevaluable = isUnevaluable;
4256
4046
 
4257
- exports.isUnprimed = isUnprimed;
4258
-
4259
4047
  exports.labelFor = labelFor;
4260
4048
 
4261
4049
  exports.lakePrincipalId = lakePrincipalId;
4262
4050
 
4263
- exports.minReaderModelOf = minReaderModelOf;
4264
-
4265
- exports.modelStampFor = modelStampFor;
4266
-
4267
- exports.modelVersionOf = modelVersionOf;
4268
-
4269
- exports.parentRef = parentRef;
4270
-
4271
- exports.parseDefinitionSnapshot = parseDefinitionSnapshot;
4272
-
4273
- exports.parseDefinitionSnapshotValue = parseDefinitionSnapshotValue;
4274
-
4275
4051
  exports.parseFieldValue = parseFieldValue;
4276
4052
 
4277
4053
  exports.parseGdr = parseGdr;
@@ -4304,10 +4080,6 @@ exports.releaseDocId = releaseDocId;
4304
4080
 
4305
4081
  exports.releaseRef = releaseRef;
4306
4082
 
4307
- exports.requiredModelFeatures = requiredModelFeatures;
4308
-
4309
- exports.requiredReaderModel = requiredReaderModel;
4310
-
4311
4083
  exports.resourceAliasesToMap = resourceAliasesToMap;
4312
4084
 
4313
4085
  exports.resourceFromGdrUri = resourceFromGdrUri;
@@ -4332,8 +4104,6 @@ exports.startKindOf = startKindOf;
4332
4104
 
4333
4105
  exports.tagScopeFilter = tagScopeFilter;
4334
4106
 
4335
- exports.terminalState = terminalState;
4336
-
4337
4107
  exports.toBareId = toBareId;
4338
4108
 
4339
4109
  exports.toPhysicalGdr = toPhysicalGdr;