@sanity/workflow-engine 0.19.0 → 0.21.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -4,6 +4,8 @@ import { conditionOutcome, runGroq as runGroq$1, evaluateConditionOutcome as eva
4
4
 
5
5
  import { parse } from "groq-js";
6
6
 
7
+ import { isDraftId, isVersionId, getPublishedId } from "@sanity/id-utils";
8
+
7
9
  class WorkflowError extends Error {
8
10
  kind;
9
11
  constructor(kind, message, options) {
@@ -99,12 +101,33 @@ function isUnprimed(instance) {
99
101
 
100
102
  function parseDefinitionSnapshotValue(instance) {
101
103
  try {
102
- return JSON.parse(instance.definitionSnapshot);
104
+ return normalizeLegacyActivityRequirements(JSON.parse(instance.definitionSnapshot));
103
105
  } catch (err) {
104
106
  rethrowWithContext(err, `Failed to parse definitionSnapshot on instance "${instance._id}"`);
105
107
  }
106
108
  }
107
109
 
110
+ function normalizeLegacyActivityRequirements(value) {
111
+ for (const stage of arrayMember(value, "stages")) for (const activity of arrayMember(stage, "activities")) normalizeLegacyRequirementMap(activity);
112
+ return value;
113
+ }
114
+
115
+ function arrayMember(value, key) {
116
+ if (typeof value != "object" || value === null) return [];
117
+ const member = value[key];
118
+ return Array.isArray(member) ? member : [];
119
+ }
120
+
121
+ function normalizeLegacyRequirementMap(value) {
122
+ if (typeof value != "object" || value === null) return;
123
+ const activity = value, requirements = activity.requirements;
124
+ typeof requirements != "object" || requirements === null || Array.isArray(requirements) || (activity.requirements = Object.entries(requirements).map(([name, query]) => ({
125
+ type: "groq",
126
+ name: name,
127
+ query: query
128
+ })));
129
+ }
130
+
108
131
  function parseDefinitionSnapshot(instance) {
109
132
  return parseDefinitionSnapshotValue(instance);
110
133
  }
@@ -113,7 +136,7 @@ function parentRef(instance) {
113
136
  return instance.ancestors.at(-1);
114
137
  }
115
138
 
116
- 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";
139
+ const DATA_MODEL_VERSION = 4, DATA_MODEL_MIN_READER = 4, READER_MODEL_ROLLOUT_URL = "https://github.com/sanity-io/workflows/blob/main/docs/reader-model-rollout.md";
117
140
 
118
141
  class ReaderModelAcknowledgementError extends WorkflowError {
119
142
  code="WORKFLOW_READER_MODEL_ACKNOWLEDGEMENT_MISMATCH";
@@ -123,7 +146,7 @@ class ReaderModelAcknowledgementError extends WorkflowError {
123
146
  documentationUrl=READER_MODEL_ROLLOUT_URL;
124
147
  constructor(expectedMinReaderModel, context = "Deployment") {
125
148
  const expected = expectedMinReaderModel === void 0 ? "missing" : String(expectedMinReaderModel);
126
- 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}`),
149
+ 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. Instances written before the new floor may stop matching user-identity queries, and older readers refuse documents this engine touches — a prerelease deployment with no data worth migrating can reset every engine-owned document with \`sanity-workflows nuke\` and start fresh. ${READER_MODEL_ROLLOUT_URL}`),
127
150
  this.name = "ReaderModelAcknowledgementError", this.expectedMinReaderModel = expectedMinReaderModel;
128
151
  }
129
152
  }
@@ -188,6 +211,22 @@ const DATA_MODEL_CHANGES = Object.freeze([ Object.freeze({
188
211
  compatibility: "additive",
189
212
  applicability: "detectable",
190
213
  summary: "Pending-effect claims carry an exact-claim token gating mid-dispatch state reports."
214
+ }), Object.freeze({
215
+ id: "classified-principal-ids",
216
+ introducedInModel: 4,
217
+ minReaderModel: 4,
218
+ documentTypes: Object.freeze([ "instance" ]),
219
+ compatibility: "reader-floor",
220
+ applicability: "unconditional",
221
+ 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."
222
+ }), Object.freeze({
223
+ id: "readiness-requirements",
224
+ introducedInModel: 4,
225
+ minReaderModel: 4,
226
+ documentTypes: Object.freeze([ "definition" ]),
227
+ compatibility: "reader-floor",
228
+ applicability: "detectable",
229
+ summary: "Start and activity readiness use named polymorphic requirement arrays."
191
230
  }) ]);
192
231
 
193
232
  function recordOf(value) {
@@ -248,6 +287,11 @@ function hasClaimTokens(document) {
248
287
  });
249
288
  }
250
289
 
290
+ function hasReadinessRequirements(document) {
291
+ const root = recordOf(document);
292
+ 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)));
293
+ }
294
+
251
295
  const featureDetectors = {
252
296
  "governed-model-stamps": () => !0,
253
297
  "subject-field-kind": document => hasFieldKind(document, "subject"),
@@ -255,7 +299,9 @@ const featureDetectors = {
255
299
  "action-semantics": hasActionSemantics,
256
300
  "inclusive-scalar-bounds": hasScalarValidation,
257
301
  "progress-field-kind": document => hasFieldKind(document, "progress"),
258
- "effect-claim-tokens": hasClaimTokens
302
+ "effect-claim-tokens": hasClaimTokens,
303
+ "classified-principal-ids": () => !0,
304
+ "readiness-requirements": hasReadinessRequirements
259
305
  };
260
306
 
261
307
  function requiredModelFeatures(documentType, document) {
@@ -269,7 +315,7 @@ function requiredReaderModel(documentType, document) {
269
315
  function modelStampFor(args) {
270
316
  return {
271
317
  modelVersion: DATA_MODEL_VERSION,
272
- minReaderModel: Math.max(args.storedMinReaderModel ?? 0, requiredReaderModel(args.documentType, args.document))
318
+ minReaderModel: Math.max(DATA_MODEL_MIN_READER, args.storedMinReaderModel ?? 0, requiredReaderModel(args.documentType, args.document))
273
319
  };
274
320
  }
275
321
 
@@ -342,6 +388,21 @@ function andConditions(parts) {
342
388
 
343
389
  const KNOWN_SCHEMES = /* @__PURE__ */ new Set([ "dataset", "canvas", "media-library", "dashboard" ]), KNOWN_SCHEMES_TEXT = [ ...KNOWN_SCHEMES ].join(", ");
344
390
 
391
+ class VersionSpecificDatasetGdrError extends Error {
392
+ documentId;
393
+ stableDocumentId;
394
+ constructor(documentId, uri) {
395
+ const stableDocumentId = getPublishedId(documentId);
396
+ super(`Invalid GDR "${uri}": dataset document ID "${documentId}" identifies a stored draft or release version. Use the stable document ID "${stableDocumentId}" and select drafts/releases through the workflow perspective.`),
397
+ this.name = "VersionSpecificDatasetGdrError", this.documentId = documentId, this.stableDocumentId = stableDocumentId;
398
+ }
399
+ }
400
+
401
+ function assertStableDatasetDocumentId(documentId, uri) {
402
+ const sanityId = documentId;
403
+ if (!(!isDraftId(sanityId) && !isVersionId(sanityId))) throw new VersionSpecificDatasetGdrError(documentId, uri);
404
+ }
405
+
345
406
  function parseGdr(uri) {
346
407
  const colon = uri.indexOf(":");
347
408
  if (colon < 0) throw new Error(`Invalid GDR "${uri}": must be a URI of form "<scheme>:<...id-parts>". Known schemes: ${KNOWN_SCHEMES_TEXT}.`);
@@ -351,11 +412,12 @@ function parseGdr(uri) {
351
412
  if (parts.some(part => part.length === 0)) throw new Error(`Invalid GDR "${uri}": id parts must be non-empty (no leading, trailing, or doubled ":").`);
352
413
  if (scheme === "dataset") {
353
414
  if (parts.length !== 3) throw new Error(`Invalid GDR "${uri}": dataset scheme requires <projectId>:<dataset>:<documentId> (3 parts after scheme); got ${parts.length}.`);
354
- return {
415
+ const documentId = parts[2];
416
+ return assertStableDatasetDocumentId(documentId, uri), {
355
417
  scheme: "dataset",
356
418
  projectId: parts[0],
357
419
  dataset: parts[1],
358
- documentId: parts[2]
420
+ documentId: documentId
359
421
  };
360
422
  }
361
423
  if (parts.length !== 2) throw new Error(`Invalid GDR "${uri}": ${scheme} scheme requires <resourceId>:<documentId> (2 parts after scheme); got ${parts.length}.`);
@@ -375,7 +437,11 @@ function tryParseGdr(uri) {
375
437
  }
376
438
 
377
439
  function gdrUri(parts) {
378
- return parts.scheme === "dataset" ? `dataset:${parts.projectId}:${parts.dataset}:${parts.documentId}` : `${parts.scheme}:${parts.resourceId}:${parts.documentId}`;
440
+ if (parts.scheme === "dataset") {
441
+ const uri = `dataset:${parts.projectId}:${parts.dataset}:${parts.documentId}`;
442
+ return assertStableDatasetDocumentId(parts.documentId, uri), uri;
443
+ }
444
+ return `${parts.scheme}:${parts.resourceId}:${parts.documentId}`;
379
445
  }
380
446
 
381
447
  function extractDocumentId(gdrUriString) {
@@ -778,8 +844,8 @@ function desugarStart(start) {
778
844
  ...start.filter !== void 0 ? {
779
845
  filter: start.filter
780
846
  } : {},
781
- ...start.allowed !== void 0 ? {
782
- allowed: start.allowed
847
+ ...start.requirements !== void 0 ? {
848
+ requirements: start.requirements
783
849
  } : {}
784
850
  };
785
851
  }
@@ -1541,7 +1607,7 @@ const ACTION_SEMANTICS = [ "decision.accept", "decision.decline" ], FIELD_SCOPES
1541
1607
  binding: "always",
1542
1608
  label: "the spawned subworkflows",
1543
1609
  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`."
1544
- } ], 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 = [ {
1610
+ } ], 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 = [ {
1545
1611
  name: "tag",
1546
1612
  label: "this engine tag",
1547
1613
  description: "The engine's tag partition — scope `*[...]` instance scans with `tag == $tag`."
@@ -1553,11 +1619,7 @@ const ACTION_SEMANTICS = [ "decision.accept", "decision.decline" ], FIELD_SCOPES
1553
1619
  name: "now",
1554
1620
  label: "the current time",
1555
1621
  description: "The ISO clock reading of the evaluating engine."
1556
- }, {
1557
- name: SUBJECT_HAS_IN_FLIGHT_INSTANCE_VAR,
1558
- label: "the subject already has an in-flight workflow",
1559
- description: "Whether any instance in this engine tag, across all definitions, has the same resource-qualified subject and no `completedAt`. Advisory under concurrent starts."
1560
- } ], START_ALLOWED_VARS = [ ...START_FILTER_VARS, {
1622
+ } ], START_REQUIREMENT_VARS = [ ...START_FILTER_VARS, {
1561
1623
  name: "fields",
1562
1624
  label: "the start's input fields",
1563
1625
  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."
@@ -1742,6 +1804,37 @@ function isNotesEntry(entry) {
1742
1804
  return columns !== void 0 && columns.has("body") && columns.has("actor") && columns.has("at");
1743
1805
  }
1744
1806
 
1807
+ const ANONYMOUS_IDENTITY = "<anonymous>", SYSTEM_IDENTITY = "<system>", E_PREFIXED_PROJECT_ID = /^e-(.+)$/;
1808
+
1809
+ function classifyPrincipalId(id) {
1810
+ if (id === ANONYMOUS_IDENTITY || id === SYSTEM_IDENTITY) return {
1811
+ namespace: "sentinel"
1812
+ };
1813
+ if (id.startsWith("g")) return {
1814
+ namespace: "global",
1815
+ globalId: id
1816
+ };
1817
+ if (id.startsWith("p-")) return {
1818
+ namespace: "robot",
1819
+ globalId: id
1820
+ };
1821
+ const embeddedGlobal = E_PREFIXED_PROJECT_ID.exec(id)?.[1];
1822
+ return embeddedGlobal !== void 0 ? embeddedGlobal.startsWith("g") ? {
1823
+ namespace: "project",
1824
+ globalId: embeddedGlobal
1825
+ } : {
1826
+ namespace: "unknown"
1827
+ } : id.startsWith("p") ? {
1828
+ namespace: "project"
1829
+ } : {
1830
+ namespace: "unknown"
1831
+ };
1832
+ }
1833
+
1834
+ function lakePrincipalId(args) {
1835
+ return args.localPrincipalId ?? args.actor.id;
1836
+ }
1837
+
1745
1838
  class FieldValueShapeError extends WorkflowError {
1746
1839
  entryType;
1747
1840
  entryName;
@@ -1782,11 +1875,11 @@ function checkChoiceList(args) {
1782
1875
  const {entryType: entryType, options: options, validation: validation} = args;
1783
1876
  if (options === void 0) return;
1784
1877
  if (!CHOICE_KINDS.has(entryType)) return [ `\`options\` is not valid on "${entryType}" values` ];
1785
- const kind = normalizedChoiceKind(entryType), issues = options.list.flatMap((option, index) => checkValueAgainst({
1878
+ const kind = normalizedChoiceKind(entryType), issues = options.list.flatMap((option, index) => issuesOf(checkValueAgainst({
1786
1879
  entryType: kind,
1787
1880
  value: option.value,
1788
1881
  validation: validation
1789
- }, valueSchemas)?.map(issue => `at options.list.${index}.value: ${issue}`) ?? []), seen = /* @__PURE__ */ new Set;
1882
+ }, valueSchemas))?.map(issue => `at options.list.${index}.value: ${issue}`) ?? []), seen = /* @__PURE__ */ new Set;
1790
1883
  for (const option of options.list) seen.has(option.value) && issues.push(`duplicate option value ${JSON.stringify(option.value)}`),
1791
1884
  seen.add(option.value);
1792
1885
  return issues.length === 0 ? void 0 : issues;
@@ -1812,8 +1905,27 @@ const fieldValueSchemas = {
1812
1905
  actor: v.union([ v.null(), ActorShape ]),
1813
1906
  assignee: v.union([ v.null(), AssigneeShape ]),
1814
1907
  assignees: v.array(AssigneeShape)
1815
- }, valueSchemas = {
1908
+ }, WritePrincipalId = v.pipe(NonEmptyString, v.rawTransform(({dataset: dataset, addIssue: addIssue}) => {
1909
+ const classified = classifyPrincipalId(dataset.value);
1910
+ return classified.namespace === "global" || classified.namespace === "robot" ? dataset.value : classified.namespace === "project" && classified.globalId !== void 0 ? classified.globalId : (addIssue({
1911
+ message: `principal id "${dataset.value}" is not an account-global user id. Workflow user ids are the global \`sanityUserId\` (or a robot token's id). Resolve project members through your surface's member hook, or /projects/<projectId>/users/<id> → sanityUserId.`
1912
+ }), dataset.value);
1913
+ })), ActorWriteShape = tolerantObject()({
1914
+ kind: v.picklist(ACTOR_KINDS),
1915
+ id: WritePrincipalId,
1916
+ roles: v.exactOptional(v.array(v.string())),
1917
+ onBehalfOf: v.exactOptional(v.string())
1918
+ }), AssigneeWriteShape = v.union([ tolerantObject()({
1919
+ type: v.literal("user"),
1920
+ id: WritePrincipalId
1921
+ }), tolerantObject()({
1922
+ type: v.literal("role"),
1923
+ role: NonEmptyString
1924
+ }) ]), valueSchemas = {
1816
1925
  ...fieldValueSchemas,
1926
+ actor: v.nullable(ActorWriteShape),
1927
+ assignee: v.nullable(AssigneeWriteShape),
1928
+ assignees: v.array(AssigneeWriteShape),
1817
1929
  query: v.any()
1818
1930
  };
1819
1931
 
@@ -1884,7 +1996,7 @@ function wholeValueSchema(args) {
1884
1996
  function appendItemSchema(entryType, shape) {
1885
1997
  if (entryType === "array") return objectSchema(shape.of ?? [], valueSchemas);
1886
1998
  if (entryType === "doc.refs") return GdrShape;
1887
- if (entryType === "assignees") return AssigneeShape;
1999
+ if (entryType === "assignees") return AssigneeWriteShape;
1888
2000
  }
1889
2001
 
1890
2002
  function rejectedRefTypes(args) {
@@ -1909,7 +2021,7 @@ function gdrTypeOf(item) {
1909
2021
  return typeof t == "string" ? t : void 0;
1910
2022
  }
1911
2023
 
1912
- function checkFieldValue(args) {
2024
+ function parseFieldValue(args) {
1913
2025
  return checkValueAgainst(args, valueSchemas);
1914
2026
  }
1915
2027
 
@@ -1919,9 +2031,14 @@ function checkValueAgainst(args, leaf) {
1919
2031
  shape: args,
1920
2032
  leaf: leaf
1921
2033
  });
1922
- if (schema === void 0) return [ `unknown field entry type ${args.entryType}` ];
2034
+ if (schema === void 0) return {
2035
+ issues: [ `unknown field entry type ${args.entryType}` ]
2036
+ };
1923
2037
  const result = v.safeParse(schema, args.value);
1924
- return result.success ? refTypeIssues({
2038
+ if (!result.success) return {
2039
+ issues: formatIssues(result.issues)
2040
+ };
2041
+ const postIssues = refTypeIssues({
1925
2042
  entryType: args.entryType,
1926
2043
  types: args.types,
1927
2044
  value: args.value
@@ -1929,17 +2046,27 @@ function checkValueAgainst(args, leaf) {
1929
2046
  entryType: args.entryType,
1930
2047
  validation: args.validation,
1931
2048
  value: args.value
1932
- }) : formatIssues(result.issues);
2049
+ });
2050
+ return postIssues !== void 0 ? {
2051
+ issues: postIssues
2052
+ } : {
2053
+ output: result.output
2054
+ };
2055
+ }
2056
+
2057
+ function issuesOf(check) {
2058
+ return "issues" in check ? check.issues : void 0;
1933
2059
  }
1934
2060
 
1935
2061
  function validateFieldValue(args) {
1936
- const issues = checkFieldValue(args);
1937
- if (issues !== void 0) throw new FieldValueShapeError({
2062
+ const check = checkValueAgainst(args, valueSchemas);
2063
+ if ("issues" in check) throw new FieldValueShapeError({
1938
2064
  entryType: args.entryType,
1939
2065
  entryName: args.entryName,
1940
- issues: issues,
2066
+ issues: check.issues,
1941
2067
  mode: "value"
1942
2068
  });
2069
+ return check.output;
1943
2070
  }
1944
2071
 
1945
2072
  const BARE_ID_SOURCE = "[A-Za-z0-9_][A-Za-z0-9._-]*", BARE_ID_RE = new RegExp(`^${BARE_ID_SOURCE}$`), ALIAS_REF_RE = new RegExp(`^@${RESOURCE_ALIAS_NAME_SOURCE}:${BARE_ID_SOURCE}$`);
@@ -1968,7 +2095,7 @@ const AuthoringRefId = v.pipe(v.string(), v.check(isAuthoringRefId, "must be a b
1968
2095
  };
1969
2096
 
1970
2097
  function checkLiteralSeed(args) {
1971
- return args.value === null ? [ "a literal seed cannot be null — omit `initialValue` to start the field empty" ] : checkValueAgainst(args, seedValueSchemas);
2098
+ return args.value === null ? [ "a literal seed cannot be null — omit `initialValue` to start the field empty" ] : issuesOf(checkValueAgainst(args, seedValueSchemas));
1972
2099
  }
1973
2100
 
1974
2101
  function validateFieldAppendItem(args) {
@@ -1997,13 +2124,15 @@ function validateFieldAppendItem(args) {
1997
2124
  issues: typeIssues,
1998
2125
  mode: "item"
1999
2126
  });
2127
+ return result.output;
2000
2128
  }
2001
2129
 
2002
2130
  function formatIssues(issues, formatMessage = issue => issue.message) {
2003
- return issues.map(i => {
2004
- const keys = i.path?.map(p => p.key) ?? [];
2005
- return `${keys.length > 0 ? `at ${keys.join(".")}: ` : ""}${formatMessage(i)}`;
2006
- });
2131
+ const formatOne = (issue, prefix) => {
2132
+ const keys = [ ...prefix, ...issue.path?.map(p => p.key) ?? [] ], sub = issue.issues?.filter(candidate => candidate.expected !== "null");
2133
+ return sub !== void 0 && sub.length > 0 ? sub.flatMap(candidate => formatOne(candidate, keys)) : [ `${keys.length > 0 ? `at ${keys.join(".")}: ` : ""}${formatMessage(issue)}` ];
2134
+ };
2135
+ return issues.flatMap(issue => formatOne(issue, []));
2007
2136
  }
2008
2137
 
2009
2138
  const NonEmpty = NonEmptyString, PositiveInt = v.pipe(v.number(), v.integer(), v.minValue(1)), GROQ_IDENTIFIER = /^[A-Za-z_][A-Za-z0-9_]*$/;
@@ -2013,7 +2142,15 @@ function groqIdentifier(referencedAs) {
2013
2142
  }
2014
2143
 
2015
2144
  function picklist(options) {
2016
- return v.picklist(options, `Invalid option: expected one of ${options.map(o => `"${o}"`).join("|")}`);
2145
+ return v.picklist(options, invalidOptionMessage(options));
2146
+ }
2147
+
2148
+ function invalidOptionMessage(options) {
2149
+ return `Invalid option: expected one of ${options.map(option => `"${option}"`).join("|")}`;
2150
+ }
2151
+
2152
+ function exhaustiveOptions() {
2153
+ return options => options;
2017
2154
  }
2018
2155
 
2019
2156
  function pinned() {
@@ -2028,12 +2165,12 @@ const LiteralSchema = v.strictObject({
2028
2165
  scope: v.optional(v.union([ v.literal("workflow"), v.literal("stage") ])),
2029
2166
  field: NonEmpty,
2030
2167
  path: v.optional(v.string())
2031
- }), FieldSourceSchema = v.union([ v.strictObject({
2168
+ }), FieldSourceSchema = v.variant("type", [ v.strictObject({
2032
2169
  type: v.literal("input")
2033
2170
  }), v.strictObject({
2034
2171
  type: v.literal("query"),
2035
2172
  query: NonEmpty
2036
- }), LiteralSchema, FieldReadSchema ]), ValueExprSchema = v.lazy(() => v.union([ LiteralSchema, FieldReadSchema, v.strictObject({
2173
+ }), LiteralSchema, FieldReadSchema ]), ValueExprSchema = v.lazy(() => v.variant("type", [ LiteralSchema, FieldReadSchema, v.strictObject({
2037
2174
  type: v.literal("param"),
2038
2175
  param: NonEmpty
2039
2176
  }), v.strictObject({
@@ -2128,7 +2265,7 @@ function groupMembershipNames(group) {
2128
2265
  return group === void 0 ? [] : typeof group == "string" ? [ group ] : [ ...group ];
2129
2266
  }
2130
2267
 
2131
- 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.pipe(v.number(), v.finite("must be finite")), ScalarValidationSchema = v.pipe(v.strictObject({
2268
+ 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), AUTHORING_FIELD_SUGAR_KINDS = exhaustiveOptions()([ "claim", "todoList", "notes" ]), AUTHORING_FIELD_KINDS = [ ...FIELD_VALUE_KINDS, ...AUTHORING_FIELD_SUGAR_KINDS ], AuthoringRawFieldKindSchema = v.picklist(FIELD_VALUE_KINDS, issue => `${invalidOptionMessage(AUTHORING_FIELD_KINDS)} but received ${JSON.stringify(issue.input)}`), FieldEntryName = groqIdentifier("`$fields.<name>`"), FiniteNumber = v.pipe(v.number(), v.finite("must be finite")), ScalarValidationSchema = v.pipe(v.strictObject({
2132
2269
  min: v.optional(FiniteNumber),
2133
2270
  max: v.optional(FiniteNumber)
2134
2271
  }), v.check(validation => validation.min !== void 0 || validation.max !== void 0, "declare at least one bound, or omit `validation`"), v.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.strictObject({
@@ -2193,9 +2330,9 @@ function fieldBase(editable, group) {
2193
2330
  };
2194
2331
  }
2195
2332
 
2196
- function fieldEntryFields(editable, group) {
2333
+ function fieldEntryFields({editable: editable, group: group, kind: kind = FieldKindSchema}) {
2197
2334
  return {
2198
- type: FieldKindSchema,
2335
+ type: kind,
2199
2336
  ...fieldBase(editable, group),
2200
2337
  options: v.optional(ChoiceOptionsSchema),
2201
2338
  validation: v.optional(ScalarValidationSchema),
@@ -2256,7 +2393,14 @@ function scalarValidationDeclarationIssues(entry) {
2256
2393
  return issues.length === 0 ? void 0 : issues;
2257
2394
  }
2258
2395
 
2259
- const FieldEntrySchema = pinned()(v.pipe(compositeChecked(fieldEntryFields(StoredEditableSchema, StoredGroupMembershipSchema)), refTypesCheck(), choiceOptionsCheck(), scalarValidationCheck(), literalSeedCheck())), RawAuthoringFieldEntrySchema = pinned()(v.pipe(compositeChecked(fieldEntryFields(AuthoringEditableSchema, AuthoringGroupMembershipSchema)), refTypesCheck(), choiceOptionsCheck(), scalarValidationCheck(), literalSeedCheck())), ClaimFieldSchema = pinned()(v.strictObject({
2396
+ const FieldEntrySchema = pinned()(v.pipe(compositeChecked(fieldEntryFields({
2397
+ editable: StoredEditableSchema,
2398
+ group: StoredGroupMembershipSchema
2399
+ })), refTypesCheck(), choiceOptionsCheck(), scalarValidationCheck(), literalSeedCheck())), RawAuthoringFieldEntrySchema = pinned()(v.pipe(compositeChecked(fieldEntryFields({
2400
+ editable: AuthoringEditableSchema,
2401
+ group: AuthoringGroupMembershipSchema,
2402
+ kind: AuthoringRawFieldKindSchema
2403
+ })), refTypesCheck(), choiceOptionsCheck(), scalarValidationCheck(), literalSeedCheck())), ClaimFieldSchema = pinned()(v.strictObject({
2260
2404
  type: v.literal("claim"),
2261
2405
  name: FieldEntryName,
2262
2406
  title: v.optional(v.string()),
@@ -2271,7 +2415,10 @@ function listSugarFields(type) {
2271
2415
  };
2272
2416
  }
2273
2417
 
2274
- const TodoListFieldSchema = pinned()(v.strictObject(listSugarFields("todoList"))), NotesFieldSchema = pinned()(v.strictObject(listSugarFields("notes"))), AuthoringFieldEntrySchema = pinned()(v.union([ RawAuthoringFieldEntrySchema, ClaimFieldSchema, TodoListFieldSchema, NotesFieldSchema ])), EffectSchema = v.strictObject({
2418
+ const TodoListFieldSchema = pinned()(v.strictObject(listSugarFields("todoList"))), NotesFieldSchema = pinned()(v.strictObject(listSugarFields("notes"))), AuthoringFieldEntrySchema = pinned()(v.lazy(input => {
2419
+ const type = asShape(input).type;
2420
+ return type === "claim" ? ClaimFieldSchema : type === "todoList" ? TodoListFieldSchema : type === "notes" ? NotesFieldSchema : RawAuthoringFieldEntrySchema;
2421
+ })), EffectSchema = v.strictObject({
2275
2422
  name: NonEmpty,
2276
2423
  title: v.optional(v.string()),
2277
2424
  description: v.optional(v.string()),
@@ -2336,7 +2483,18 @@ const StoredActionSchema = pinned()(v.strictObject({
2336
2483
  filter: v.optional(ConditionSchema),
2337
2484
  params: v.optional(v.array(ActionParamSchema)),
2338
2485
  effects: v.optional(v.array(EffectSchema))
2339
- })), AuthoringActionSchema = pinned()(v.lazy(input => typeof input == "object" && input !== null && "type" in input ? ClaimActionSchema : RawAuthoringActionSchema));
2486
+ })), AuthoringActionSchema = pinned()(v.lazy(input => typeof input == "object" && input !== null && "type" in input ? ClaimActionSchema : RawAuthoringActionSchema)), requirementBase = {
2487
+ name: NonEmpty,
2488
+ title: v.optional(v.string()),
2489
+ description: v.optional(v.string())
2490
+ }, GroqRequirementSchemaRaw = v.strictObject({
2491
+ ...requirementBase,
2492
+ type: v.literal("groq"),
2493
+ query: ConditionSchema
2494
+ }), SingleSubjectRequirementSchemaRaw = v.strictObject({
2495
+ ...requirementBase,
2496
+ type: v.literal("singleSubject")
2497
+ }), GroqRequirementSchema = pinned()(GroqRequirementSchemaRaw), StartRequirementSchema = pinned()(v.variant("type", [ GroqRequirementSchemaRaw, SingleSubjectRequirementSchemaRaw ]));
2340
2498
 
2341
2499
  function activityFields({field: field, action: action, target: target, group: group}) {
2342
2500
  return {
@@ -2347,7 +2505,7 @@ function activityFields({field: field, action: action, target: target, group: gr
2347
2505
  group: v.optional(group),
2348
2506
  target: v.optional(target),
2349
2507
  filter: v.optional(ConditionSchema),
2350
- requirements: v.optional(v.record(NonEmpty, ConditionSchema)),
2508
+ requirements: v.optional(v.array(GroqRequirementSchema)),
2351
2509
  actions: v.optional(v.array(action)),
2352
2510
  fields: v.optional(v.array(field))
2353
2511
  };
@@ -2443,7 +2601,7 @@ function startFields(kind) {
2443
2601
  return {
2444
2602
  kind: kind,
2445
2603
  filter: v.optional(ConditionSchema),
2446
- allowed: v.optional(ConditionSchema)
2604
+ requirements: v.optional(v.array(StartRequirementSchema))
2447
2605
  };
2448
2606
  }
2449
2607
 
@@ -2582,6 +2740,13 @@ function checkActivities({def: def, i: i, activityNames: activityNames, issues:
2582
2740
  })),
2583
2741
  what: `action name in activity "${activity.name}"`,
2584
2742
  issues: issues
2743
+ }), checkDuplicates({
2744
+ names: (activity.requirements ?? []).map((requirement, r) => ({
2745
+ name: requirement.name,
2746
+ path: [ ...path, "requirements", r, "name" ]
2747
+ })),
2748
+ what: `requirement name in activity "${activity.name}"`,
2749
+ issues: issues
2585
2750
  }), checkStatusSetTargets({
2586
2751
  activity: activity,
2587
2752
  activityNames: activityNames,
@@ -2890,10 +3055,10 @@ function collectActivityConditionSites({activity: activity, path: path, stageFie
2890
3055
  policy: "cascade",
2891
3056
  fields: fields
2892
3057
  });
2893
- for (const [name, groq2] of Object.entries(activity.requirements ?? {})) sites.push({
2894
- groq: groq2,
2895
- path: [ ...path, "requirements", name ],
2896
- label: `activity "${activity.name}" requirement "${name}"`,
3058
+ for (const [index, requirement] of (activity.requirements ?? []).entries()) sites.push({
3059
+ groq: requirement.query,
3060
+ path: [ ...path, "requirements", index, "query" ],
3061
+ label: `activity "${activity.name}" requirement "${requirement.name}"`,
2897
3062
  policy: "caller-bound",
2898
3063
  fields: fields
2899
3064
  });
@@ -3089,73 +3254,83 @@ function checkTriggeredActionParams(def, issues) {
3089
3254
  }
3090
3255
 
3091
3256
  function checkStart(def, issues) {
3092
- if (def.start !== void 0 && (def.lifecycle === "child" && issues.push({
3257
+ if (def.start !== void 0 && (checkDuplicates({
3258
+ names: (def.start.requirements ?? []).map((requirement, index) => ({
3259
+ name: requirement.name,
3260
+ path: [ "start", "requirements", index, "name" ]
3261
+ })),
3262
+ what: "start requirement name",
3263
+ issues: issues
3264
+ }), def.lifecycle === "child" && issues.push({
3093
3265
  path: [ "start" ],
3094
3266
  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'`"
3095
- }), checkStartFilterReads(def, issues), checkStartAllowedReads(def, issues), checkStartSubjectVariable(def, issues),
3096
- def.start.kind === "autonomous")) for (const [n, entry] of (def.fields ?? []).entries()) entry.required !== !0 || isSubjectEntry(entry) || issues.push({
3267
+ }), checkStartFilterReads(def, issues), checkStartRequirementReads(def, issues),
3268
+ checkSingleSubjectRequirements(def, issues), def.start.kind === "autonomous")) for (const [n, entry] of (def.fields ?? []).entries()) entry.required !== !0 || isSubjectEntry(entry) || issues.push({
3097
3269
  path: [ "fields", n, "required" ],
3098
3270
  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)`
3099
3271
  });
3100
3272
  }
3101
3273
 
3102
- function checkStartSubjectVariable(def, issues) {
3274
+ function checkSingleSubjectRequirements(def, issues) {
3275
+ const indexes = (def.start?.requirements ?? []).map((requirement, index) => ({
3276
+ requirement: requirement,
3277
+ index: index
3278
+ })).filter(({requirement: requirement}) => requirement.type === "singleSubject"), [first] = indexes;
3279
+ if (first === void 0) return;
3103
3280
  const subject = (def.fields ?? []).find(isSubjectEntry);
3104
- 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)) {
3105
- if (subject === void 0) {
3106
- issues.push({
3107
- path: [ "start", key ],
3108
- 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`
3109
- });
3110
- continue;
3111
- }
3112
- key === "allowed" && !isInputSourced(subject) && issues.push({
3113
- path: [ "start", key ],
3114
- 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`
3281
+ if (subject === void 0) {
3282
+ issues.push({
3283
+ path: [ "start", "requirements", first.index ],
3284
+ message: "a singleSubject start requirement caps the definition at one in-flight run per subject, but the definition declares no `subject` entry — there is no subject identity to dedupe on, so the rule could never apply. Declare a `subject` entry (the document the workflow is about), or remove the requirement"
3115
3285
  });
3286
+ return;
3116
3287
  }
3288
+ isInputSourced(subject) || issues.push({
3289
+ path: [ "start", "requirements", first.index ],
3290
+ message: `a singleSubject start requirement matches the prospective subject against in-flight runs, but the definition's subject entry "${subject.name}" is not \`input\`-sourced — the start gate cannot bind a prospective subject. Make the subject input-sourced, or remove the requirement`
3291
+ });
3117
3292
  }
3118
3293
 
3119
3294
  function checkStartFilterReads(def, issues) {
3120
3295
  const filter = def.start?.filter;
3121
3296
  filter !== void 0 && (conditionParameterNames(filter).has("fields") && issues.push({
3122
3297
  path: [ "start", "filter" ],
3123
- 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"
3298
+ 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"
3124
3299
  }), readsRootDocument(filter) && !(def.fields ?? []).some(isSubjectEntry) && issues.push({
3125
3300
  path: [ "start", "filter" ],
3126
3301
  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"
3127
3302
  }));
3128
3303
  }
3129
3304
 
3130
- function checkStartAllowedReads(def, issues) {
3131
- const allowed = def.start?.allowed;
3132
- if (allowed === void 0) return;
3305
+ function checkStartRequirementReads(def, issues) {
3133
3306
  const bindable = new Map((def.fields ?? []).filter(isInputSourced).map(entry => [ entry.name, entry ])), declared = new Set((def.fields ?? []).map(entry => entry.name)), nullVerdict = `so the read is GROQ null and null semantics decide the verdict (refuse-all or vacuously-allow, by the expression's shape), never the caller's real input. Bindable (input) fields: ${knownList(bindable.keys())}`;
3134
- for (const read of conditionFieldReads(allowed)) {
3135
- const entry = bindable.get(read.name);
3136
- if (entry === void 0) {
3137
- issues.push({
3138
- path: [ "start", "allowed" ],
3139
- message: declared.has(read.name) ? `start.allowed reads $fields.${read.name}, but "${read.name}" is not an \`input\`-sourced entry — $fields binds only the caller's input entries (query/literal/fieldRead entries resolve at materialisation, after the start gate), ${nullVerdict}` : `start.allowed reads $fields.${read.name}, but no workflow-scope field entry named "${read.name}" is declared — $fields binds only the caller's input entries, ${nullVerdict}`
3307
+ for (const [index, requirement] of (def.start?.requirements ?? []).entries()) if (requirement.type === "groq") {
3308
+ for (const read of conditionFieldReads(requirement.query)) {
3309
+ const entry = bindable.get(read.name);
3310
+ if (entry === void 0) {
3311
+ issues.push({
3312
+ path: [ "start", "requirements", index, "query" ],
3313
+ message: declared.has(read.name) ? `start requirement reads $fields.${read.name}, but "${read.name}" is not an \`input\`-sourced entry — $fields binds only the caller's input entries (query/literal/fieldRead entries resolve at materialisation, after the start gate), ${nullVerdict}` : `start requirement reads $fields.${read.name}, but no workflow-scope field entry named "${read.name}" is declared — $fields binds only the caller's input entries, ${nullVerdict}`
3314
+ });
3315
+ continue;
3316
+ }
3317
+ pushFieldReadPathIssue({
3318
+ where: "start requirement",
3319
+ read: {
3320
+ field: read.name,
3321
+ path: read.path
3322
+ },
3323
+ target: entry,
3324
+ path: [ "start", "requirements", index, "query" ],
3325
+ issues: issues,
3326
+ nodes: START_REQUIREMENT_VALUE_NODES
3140
3327
  });
3141
- continue;
3142
3328
  }
3143
- pushFieldReadPathIssue({
3144
- where: "start.allowed",
3145
- read: {
3146
- field: read.name,
3147
- path: read.path
3148
- },
3149
- target: entry,
3150
- path: [ "start", "allowed" ],
3151
- issues: issues,
3152
- nodes: START_ALLOWED_VALUE_NODES
3329
+ readsRootDocument(requirement.query) && issues.push({
3330
+ path: [ "start", "requirements", index, "query" ],
3331
+ message: "start requirement reads the candidate document as its root, but no root ever binds in the start-requirement context — startInstance holds inputs, not a loaded document, so the read is GROQ null and null semantics decide the verdict, never the workflow's real state. Read the subject as $fields.<entry> (its GDR URI is $fields.<entry>.id); a per-document visibility rule belongs in start.filter"
3153
3332
  });
3154
3333
  }
3155
- readsRootDocument(allowed) && issues.push({
3156
- path: [ "start", "allowed" ],
3157
- message: "start.allowed reads the candidate document as its root, but no root ever binds in the start-allowed context — startInstance holds inputs, not a loaded document, so the read is GROQ null and null semantics decide the verdict, never the workflow's real state. Read the subject as $fields.<entry> (its GDR URI is $fields.<entry>.id); a per-document visibility rule belongs in start.filter"
3158
- });
3159
3334
  }
3160
3335
 
3161
3336
  function checkGroups(def, issues) {
@@ -3680,7 +3855,7 @@ const SCALAR = {
3680
3855
  kind: "rows",
3681
3856
  of: shape.of ?? []
3682
3857
  })
3683
- }, START_ALLOWED_VALUE_NODES = {
3858
+ }, START_REQUIREMENT_VALUE_NODES = {
3684
3859
  ...VALUE_NODES,
3685
3860
  "doc.ref": () => GDR_VALUE,
3686
3861
  subject: () => GDR_VALUE
@@ -3761,4 +3936,4 @@ function checkWorkflowInvariants(def) {
3761
3936
  checkGroups(def, issues), issues;
3762
3937
  }
3763
3938
 
3764
- export { ACTION_SEMANTICS, ACTIVITY_KINDS, ACTIVITY_STATUSES, ACTOR_KINDS, ActorShape, AuthoringActionSchema, AuthoringActivitySchema, AuthoringFieldEntrySchema, AuthoringGuardSchema, AuthoringOpSchema, AuthoringStageSchema, AuthoringTransitionSchema, AuthoringWorkflowSchema, CALLER_BOUND_VARS, CONDITION_VARS, ContractViolationError, DATA_MODEL_CHANGES, DATA_MODEL_MIN_READER, DATA_MODEL_VERSION, DEFAULT_TRANSITION_WHEN, DOCUMENT_VALUE_PERMISSIONS, DRIVER_KINDS, DefinitionInUseError, DefinitionNotFoundError, EFFECTS_READ, EXECUTOR_CLASSIFICATIONS, EffectNotFoundError, EffectSchema, FIELD_READ, FIELD_SCOPES, FIELD_VALUE_KINDS, FILTER_SCOPE_VARS, FieldValueShapeError, GROUP_KINDS, GUARD_PREDICATE_VARS, GdrShape, GroupSchema, InstanceNotFoundError, IsoTimestamp, MUTATION_GUARD_ACTIONS, ModelVersionAheadError, NonEmptyString, PersistedDocShapeError, READER_MODEL_ROLLOUT_URL, RESERVED_CONDITION_VARS, RESOURCE_ALIAS_NAME_SOURCE, ReaderModelAcknowledgementError, START_ALLOWED_VARS, START_FILTER_VARS, SUBJECT_HAS_IN_FLIGHT_INSTANCE_VAR, SpawnContractsInvalidError, StoredFieldOpSchema, WORKFLOW_DEFINITION_TYPE, WORKFLOW_INSTANCE_TYPE, WorkflowConfigSchema, WorkflowError, actorFulfillsRole, andConditions, assertReadableModel, assertReaderModelAcknowledgement, checkFieldValue, checkWorkflowInvariants, choiceValueIssues, clientConfigFromResource, conditionEffectReads, conditionFieldReadNames, conditionParameterNames, conditionSyntaxIssues, datasetResourceParts, definitionDocId, deriveActivityKind, deriveExecutorClassification, desugarWorkflow, driverKind, errorMessage, evaluateCondition, evaluateConditionOutcome, evaluatePredicates, extractDocumentId, fieldTreeShape, fieldValueSchemas, formatIssuePath, formatIssues, formatValidationError, gdrFromResource, gdrRef, gdrResourcePrefix, gdrUri, groq, groupMembershipNames, isBareSeedId, isCascadeFired, isGdr, isGdrUri, isGuardReadExpr, isInputSourced, isNotesEntry, isParseableInstant, isSingleDocRefEntry, isSingleDocRefKind, isStartableDefinition, isSubjectEntry, isTerminalActivityStatus, isTodoListEntry, isTodoListItem, isUnevaluable, isUnprimed, labelFor, minReaderModelOf, modelStampFor, modelVersionOf, parentRef, parseDefinitionSnapshot, parseGdr, parseOrThrow, parsePersistedDoc, parseResourceGdr, parseStoredDefinition, readsRootDocument, refCanvas, refDashboard, refDataset, refKindAcceptsTypes, refMediaLibrary, refTypeIssues, rejectedRefTypes, releaseDocId, releaseRef, requiredModelFeatures, requiredReaderModel, resourceAliasesToMap, resourceFromGdrUri, resourceFromParsed, resourceGdr, rethrowWithContext, runGroq, sameResource, scalarValidationIssues, schemaTreeShape, selfGdr, startKindOf, tagScopeFilter, terminalState, toBareId, toPhysicalGdr, tolerantEntries, tolerantObject, tryParseGdr, validateFieldAppendItem, validateFieldValue, validateResourceAliasName, validateTag };
3939
+ export { ACTION_SEMANTICS, ACTIVITY_KINDS, ACTIVITY_STATUSES, ACTOR_KINDS, ANONYMOUS_IDENTITY, ActorShape, AuthoringActionSchema, AuthoringActivitySchema, AuthoringFieldEntrySchema, AuthoringGuardSchema, AuthoringOpSchema, AuthoringStageSchema, AuthoringTransitionSchema, AuthoringWorkflowSchema, CALLER_BOUND_VARS, CONDITION_VARS, ContractViolationError, DATA_MODEL_CHANGES, DATA_MODEL_MIN_READER, DATA_MODEL_VERSION, DEFAULT_TRANSITION_WHEN, DOCUMENT_VALUE_PERMISSIONS, DRIVER_KINDS, DefinitionInUseError, DefinitionNotFoundError, EFFECTS_READ, EXECUTOR_CLASSIFICATIONS, EffectNotFoundError, EffectSchema, FIELD_READ, FIELD_SCOPES, FIELD_VALUE_KINDS, FILTER_SCOPE_VARS, FieldValueShapeError, GROUP_KINDS, GUARD_PREDICATE_VARS, GdrShape, GroupSchema, InstanceNotFoundError, IsoTimestamp, MUTATION_GUARD_ACTIONS, ModelVersionAheadError, NonEmptyString, PersistedDocShapeError, READER_MODEL_ROLLOUT_URL, RESERVED_CONDITION_VARS, RESOURCE_ALIAS_NAME_SOURCE, ReaderModelAcknowledgementError, START_FILTER_VARS, START_REQUIREMENT_VARS, SYSTEM_IDENTITY, SpawnContractsInvalidError, StoredFieldOpSchema, VersionSpecificDatasetGdrError, WORKFLOW_DEFINITION_TYPE, WORKFLOW_INSTANCE_TYPE, WorkflowConfigSchema, WorkflowError, actorFulfillsRole, andConditions, assertReadableModel, assertReaderModelAcknowledgement, checkWorkflowInvariants, choiceValueIssues, classifyPrincipalId, clientConfigFromResource, conditionEffectReads, conditionFieldReadNames, conditionParameterNames, conditionSyntaxIssues, datasetResourceParts, definitionDocId, deriveActivityKind, deriveExecutorClassification, desugarWorkflow, driverKind, errorMessage, evaluateCondition, evaluateConditionOutcome, evaluatePredicates, extractDocumentId, fieldTreeShape, fieldValueSchemas, formatIssuePath, formatIssues, formatValidationError, gdrFromResource, gdrRef, gdrResourcePrefix, gdrUri, groq, groupMembershipNames, isBareSeedId, isCascadeFired, isGdr, isGdrUri, isGuardReadExpr, isInputSourced, isNotesEntry, isParseableInstant, isSingleDocRefEntry, isSingleDocRefKind, isStartableDefinition, isSubjectEntry, isTerminalActivityStatus, isTodoListEntry, isTodoListItem, isUnevaluable, isUnprimed, labelFor, lakePrincipalId, minReaderModelOf, modelStampFor, modelVersionOf, parentRef, parseDefinitionSnapshot, parseFieldValue, parseGdr, parseOrThrow, parsePersistedDoc, parseResourceGdr, parseStoredDefinition, readsRootDocument, refCanvas, refDashboard, refDataset, refKindAcceptsTypes, refMediaLibrary, refTypeIssues, rejectedRefTypes, releaseDocId, releaseRef, requiredModelFeatures, requiredReaderModel, resourceAliasesToMap, resourceFromGdrUri, resourceFromParsed, resourceGdr, rethrowWithContext, runGroq, sameResource, scalarValidationIssues, schemaTreeShape, selfGdr, startKindOf, tagScopeFilter, terminalState, toBareId, toPhysicalGdr, tolerantEntries, tolerantObject, tryParseGdr, validateFieldAppendItem, validateFieldValue, validateResourceAliasName, validateTag };