@sanity/workflow-engine 0.26.0 → 0.28.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -1,5 +1,70 @@
1
1
  # @sanity/workflow-engine
2
2
 
3
+ ## 0.28.0
4
+
5
+ ### Minor Changes
6
+
7
+ - 5050b06: **BREAKING:** Authoring a deployment now types through `WorkflowDeploymentInput` / `WorkflowConfigInput`, which require `expectedMinReaderModel` as the current reader-floor literal. Passing a parsed `WorkflowDeployment` / `WorkflowConfig` (where the floor is optional/unverified) into `defineWorkflowConfig` or `defineWorkflows` is a type error — share the authored deployment object instead of `config.deployments[n]`. The same pin shows up on the blueprint resource: `EditorialWorkflowsResource.deployment` and `parseWorkflowDeployment`'s return type are now `AcknowledgedDeployment` (floor asserted to the current literal), so a hand-constructed provider resource must carry that literal too.
8
+
9
+ At runtime, config parse no longer rejects a stale or missing floor on an untargeted deployment. Only deployment-scoped commands assert, and only the selected deployment: definition deploy, `--check` / `--dry-run`, blueprint provision, `start`, `definition delete`, and `definition diff` (the last is a deployment-scoped read). Instance-id commands (`fire-action`, `abort`, `set-stage`, `reset-activity`) deliberately do not assert — they resolve by instance id, not by a declared deployment's acknowledgement — so an unacknowledged floor does not stop those instance commits.
10
+
11
+ Upgrade TypeScript configs and blueprint manifests that fed a parsed deployment into those helpers: keep a shared authored object (`satisfies WorkflowDeploymentInput`) for both `defineWorkflowConfig` and `defineWorkflows`, and give any hand-built `EditorialWorkflowsResource` the current floor literal on `deployment`. Existing configs that already acknowledge the current floor keep working at runtime; a stale selected deployment still fails with `ReaderModelAcknowledgementError` (headline + short steps; the CLI renders it through the clean styled-error path).
12
+
13
+ **Docs impact:** Update the CLI / blueprint authoring examples and the prerelease reader-floor guidance so they name `WorkflowConfigInput` / `WorkflowDeploymentInput` / `AcknowledgedDeployment`, forbid passing `config.deployments[n]` into `defineWorkflows`, state that instance-id writes are outside the acknowledgement gate, and stop implying whole-config parse-time rejection for commands that never select a deployment.
14
+
15
+ - a044ba5: Report a Studio start whose auto-advance lost a write race as the finished run
16
+ it is. Starting a workflow from the Studio while another runtime (a deployed
17
+ Function, a script) drives the same instance could hand the editor a warning
18
+ toast — "'…' started but didn't finish", with a raw `unexpected revision ID`
19
+ mutation error under it — for a run that had in fact completed: the Studio's own
20
+ auto-advance simply lost the write race to whoever committed the equivalent move
21
+ first. That toast was indistinguishable from a genuinely stuck workflow. The
22
+ Studio now confirms the completed start instead of warning about it.
23
+
24
+ Narrow by design: only a lost revision race whose run is already complete is
25
+ reclassified. A conflict that left the run in flight, and any other reason an
26
+ auto-advance failed, still surface as before.
27
+
28
+ `@sanity/workflow-engine` exports `isRevisionConflict`, the predicate that tells
29
+ a lost optimistic-locking race from a real error, so integrations can classify
30
+ one without matching on message text. It answers on the error alone, so narrow
31
+ to a single rev-guarded write before asking — a bare 409 also covers a create-id
32
+ collision.
33
+
34
+ **No upgrade action required.** Engine behaviour is unchanged and the new export
35
+ is additive.
36
+
37
+ **Docs impact:** `isRevisionConflict` is new public engine surface, added to the
38
+ errors section of `docs/reference.md` alongside the concurrency errors it
39
+ classifies; mirror that entry wherever published reference material lists the
40
+ engine's error helpers.
41
+
42
+ ### Patch Changes
43
+
44
+ - 1e4a5da: When two runtimes both try to create the same stage guard after each observing it absent — for example a deployed Function reacting to instance commits while a script advances the same workflow — the losing create no longer aborts guard deploy. It falls through to the body-reconciling patch the existing-document path already uses, and writes its own resolution of the guard's conditions rather than assuming the two are identical. Concurrent deploys of an already-present guard were already a patch and are unchanged.
45
+
46
+ **No upgrade action required.**
47
+
48
+ **Docs impact: None** — `docs/reference.md` already documents `deployStageGuards` as an idempotent upsert.
49
+
50
+ ## 0.27.0
51
+
52
+ ### Minor Changes
53
+
54
+ - 780cf93: **BREAKING:** `ProjectMember.roles` is now `readonly {name: string; title?: string}[]` instead of `readonly string[]`, and `AssigneeStack`'s `roles` prop takes the same records rather than name strings. This affects integrations that build or read `ProjectMember` rows directly, or render `AssigneeStack` themselves. Read `role.name` wherever a role name was read before, and pass role records rather than name strings into `projectMemberRow` and `AssigneeStack`. Until migrated, TypeScript fails at those sites. Integrations using `useProjectMembers` from `@sanity/workflow-sdk` or the Studio plugin's own equivalent get the new shape without changes, because the adapters own the projection.
55
+
56
+ A role now reads as its project title rather than its machine name — `Administrator`, not `administrator` — wherever one is shown: picker role rows, assignee badges, the instance-snapshot pills, and the hover hint naming a collapsed assignee cluster. A square role avatar takes its letters from the title too, so `Blueprints Deployer` reads as `BD` where `blueprints-deployer` could only ever give one letter; its colour still derives from the machine name, so retitling a project role keeps the role's colour. A role whose membership record carries no title — or a title that is only whitespace, which counts as none — and a role named by an assignee that no current member holds, both still read as the machine name. `roleLabel`, `roleLabelFor`, and `memberRoleFor` are exported for callers rendering their own role labels.
57
+
58
+ Both people-pickers now say who a person is, so choosing one no longer requires knowing the org chart. Search matches role names and titles as well as display name and email, so typing a role narrows the list to its holders. Members are also listed by display name rather than in the order the host supplied them, which was the sequence people joined the project — expect the list order to change, and on a large project to become usable. And hovering a row previews the account behind the name — a larger avatar badged with the person's identity provider, their email, and the roles they hold. Marks exist for Google, GitHub, and `saml-`-prefixed deployments; any other provider badges nothing rather than showing an empty circle. That is what tells two members sharing a display name apart, which no role label could. Rows share one tooltip delay group, so the wait to open is paid once and moving along the list swaps the preview rather than waiting again at each row.
59
+
60
+ `MemberAvatar` takes an optional `loginProvider` to badge the provider mark onto its corner. `ProjectMember` gains optional `loginProvider` and `isCurrentUser`; both are populated by the adapters, so integrations using `useProjectMembers` get them without changes.
61
+
62
+ Neither picker ranks or groups its member rows by the roles those members hold, and neither claims who is eligible for an activity. (The roles-and-members picker still lists selectable roles above the members, as it did before.) An activity has no role gate; only an action does, and a manually fired action's `roles` is folded into its `filter` at desugar, so the accepted set is not readable from a deployed definition. A picker has nothing to derive eligibility from, and a ranked list would assert something no engine or Content Lake check backs.
63
+
64
+ Stored values are unchanged. An assignee still persists the machine role name, and titles are display only.
65
+
66
+ **Docs impact:** Update the `@sanity/workflow-components` member-selection reference for the `ProjectMember.roles` and `AssigneeStack` `roles` shapes and the `roleLabel` / `roleLabelFor` / `memberRoleFor` exports (done in this package's README). Any concept or guide page showing a role in Studio UI should show titles rather than machine names, and the assignment guide should state that a picker never restricts or ranks who may be assigned. Add the `ProjectMember.roles` migration to the release notes.
67
+
3
68
  ## 0.26.0
4
69
 
5
70
  ## 0.25.0
@@ -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 {
@@ -4068,12 +3787,6 @@ exports.CONDITION_VARS = CONDITION_VARS;
4068
3787
 
4069
3788
  exports.ContractViolationError = ContractViolationError;
4070
3789
 
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;
4076
-
4077
3790
  exports.DEFAULT_TRANSITION_WHEN = DEFAULT_TRANSITION_WHEN;
4078
3791
 
4079
3792
  exports.DOCUMENT_VALUE_PERMISSIONS = DOCUMENT_VALUE_PERMISSIONS;
@@ -4116,20 +3829,14 @@ exports.IsoTimestamp = IsoTimestamp;
4116
3829
 
4117
3830
  exports.MUTATION_GUARD_ACTIONS = MUTATION_GUARD_ACTIONS;
4118
3831
 
4119
- exports.ModelVersionAheadError = ModelVersionAheadError;
4120
-
4121
3832
  exports.NonEmptyString = NonEmptyString;
4122
3833
 
4123
3834
  exports.PersistedDocShapeError = PersistedDocShapeError;
4124
3835
 
4125
- exports.READER_MODEL_ROLLOUT_URL = READER_MODEL_ROLLOUT_URL;
4126
-
4127
3836
  exports.RESERVED_CONDITION_VARS = RESERVED_CONDITION_VARS;
4128
3837
 
4129
3838
  exports.RESOURCE_ALIAS_NAME_SOURCE = RESOURCE_ALIAS_NAME_SOURCE;
4130
3839
 
4131
- exports.ReaderModelAcknowledgementError = ReaderModelAcknowledgementError;
4132
-
4133
3840
  exports.START_FILTER_VARS = START_FILTER_VARS;
4134
3841
 
4135
3842
  exports.START_REQUIREMENT_VARS = START_REQUIREMENT_VARS;
@@ -4144,8 +3851,6 @@ exports.VersionSpecificDatasetGdrError = VersionSpecificDatasetGdrError;
4144
3851
 
4145
3852
  exports.WORKFLOW_DEFINITION_TYPE = WORKFLOW_DEFINITION_TYPE;
4146
3853
 
4147
- exports.WORKFLOW_INSTANCE_TYPE = WORKFLOW_INSTANCE_TYPE;
4148
-
4149
3854
  exports.WorkflowConfigSchema = WorkflowConfigSchema;
4150
3855
 
4151
3856
  exports.WorkflowError = WorkflowError;
@@ -4154,10 +3859,6 @@ exports.actorFulfillsRole = actorFulfillsRole;
4154
3859
 
4155
3860
  exports.andConditions = andConditions;
4156
3861
 
4157
- exports.assertReadableModel = assertReadableModel;
4158
-
4159
- exports.assertReaderModelAcknowledgement = assertReaderModelAcknowledgement;
4160
-
4161
3862
  exports.checkWorkflowInvariants = checkWorkflowInvariants;
4162
3863
 
4163
3864
  exports.choiceValueIssues = choiceValueIssues;
@@ -4198,8 +3899,6 @@ exports.evaluatePredicates = evaluatePredicates;
4198
3899
 
4199
3900
  exports.extractDocumentId = extractDocumentId;
4200
3901
 
4201
- exports.fieldTreeShape = fieldTreeShape;
4202
-
4203
3902
  exports.fieldValueSchemas = fieldValueSchemas;
4204
3903
 
4205
3904
  exports.firstCarriedGlobalId = firstCarriedGlobalId;
@@ -4254,24 +3953,10 @@ exports.isTodoListItem = isTodoListItem;
4254
3953
 
4255
3954
  exports.isUnevaluable = isUnevaluable;
4256
3955
 
4257
- exports.isUnprimed = isUnprimed;
4258
-
4259
3956
  exports.labelFor = labelFor;
4260
3957
 
4261
3958
  exports.lakePrincipalId = lakePrincipalId;
4262
3959
 
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
3960
  exports.parseFieldValue = parseFieldValue;
4276
3961
 
4277
3962
  exports.parseGdr = parseGdr;
@@ -4304,10 +3989,6 @@ exports.releaseDocId = releaseDocId;
4304
3989
 
4305
3990
  exports.releaseRef = releaseRef;
4306
3991
 
4307
- exports.requiredModelFeatures = requiredModelFeatures;
4308
-
4309
- exports.requiredReaderModel = requiredReaderModel;
4310
-
4311
3992
  exports.resourceAliasesToMap = resourceAliasesToMap;
4312
3993
 
4313
3994
  exports.resourceFromGdrUri = resourceFromGdrUri;
@@ -4332,8 +4013,6 @@ exports.startKindOf = startKindOf;
4332
4013
 
4333
4014
  exports.tagScopeFilter = tagScopeFilter;
4334
4015
 
4335
- exports.terminalState = terminalState;
4336
-
4337
4016
  exports.toBareId = toBareId;
4338
4017
 
4339
4018
  exports.toPhysicalGdr = toPhysicalGdr;