@sanity/workflow-engine 0.20.0 → 0.21.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.cjs CHANGED
@@ -279,6 +279,10 @@ const HIGH_FREQUENCY_SAMPLE_MS = 6e4, WorkflowDefinitionDeployed = defineWorkflo
279
279
  name: "Editorial Workflows Stage Set",
280
280
  version: 1,
281
281
  description: "The set-stage admin override was invoked (changed: false = already at the target stage)"
282
+ }), WorkflowActivityReset = defineWorkflowEvent({
283
+ name: "Editorial Workflows Activity Reset",
284
+ version: 1,
285
+ description: "The reset-activity admin override was invoked (changed: false = already at the target status, or the instance was terminal)"
282
286
  }), WorkflowDefinitionDeleted = defineWorkflowEvent({
283
287
  name: "Editorial Workflows Definition Deleted",
284
288
  version: 1,
@@ -859,7 +863,7 @@ function toGroqDescribeContext(ctx) {
859
863
  };
860
864
  }
861
865
 
862
- const VAR_LABELS = new Map([ ...invariants.START_ALLOWED_VARS, ...invariants.CONDITION_VARS ].map(entry => [ entry.name, entry.label ]));
866
+ const VAR_LABELS = new Map([ ...invariants.START_REQUIREMENT_VARS, ...invariants.CONDITION_VARS ].map(entry => [ entry.name, entry.label ]));
863
867
 
864
868
  function renderWorkflowRead(read, ctx) {
865
869
  if (read.variable === "fields" && typeof read.path[0] == "string") {
@@ -932,13 +936,6 @@ function clauseVarRequirement(requirement) {
932
936
  params: {},
933
937
  text: "no activity in this stage may have failed"
934
938
  });
935
- if (target.variable === invariants.SUBJECT_HAS_IN_FLIGHT_INSTANCE_VAR) return kind === "truthy" ? groqConditionDescribe.phrase("requirement.subject-has-in-flight-instance", {
936
- params: {},
937
- text: "the subject must already have an in-flight workflow"
938
- }) : groqConditionDescribe.phrase("requirement.subject-has-no-in-flight-instance", {
939
- params: {},
940
- text: "the subject must not already have an in-flight workflow"
941
- });
942
939
  }
943
940
  }
944
941
 
@@ -1434,14 +1431,14 @@ function activitySites(activity, stage) {
1434
1431
  activity: activity.name
1435
1432
  },
1436
1433
  condition: activity.filter
1437
- } ] : [], ...Object.entries(activity.requirements ?? {}).map(([requirement, condition]) => ({
1434
+ } ] : [], ...(activity.requirements ?? []).map(requirement => ({
1438
1435
  stage: stage,
1439
1436
  address: {
1440
1437
  kind: "requirement",
1441
1438
  activity: activity.name,
1442
- requirement: requirement
1439
+ requirement: requirement.name
1443
1440
  },
1444
- condition: condition
1441
+ condition: requirement.query
1445
1442
  })), ...(activity.actions ?? []).flatMap(action => [ ...action.filter !== void 0 ? [ {
1446
1443
  stage: stage,
1447
1444
  address: {
@@ -1509,13 +1506,7 @@ async function evaluateStartFilter(args) {
1509
1506
  const {filter: filter, definition: definition, document: document, scope: scope} = args, parsed = parseStartFilter({
1510
1507
  filter: filter,
1511
1508
  definition: definition
1512
- });
1513
- assertFilterSubject({
1514
- readsSubject: parsed.readsSubject,
1515
- definition: definition,
1516
- scope: scope
1517
- });
1518
- const dataset = await filterDataset(parsed.needsDataset, scope);
1509
+ }), dataset = await filterDataset(parsed.needsDataset, scope);
1519
1510
  if (dataset === void 0) return !1;
1520
1511
  try {
1521
1512
  const result = await (await groqJs.evaluate(parsed.tree, {
@@ -1525,8 +1516,7 @@ async function evaluateStartFilter(args) {
1525
1516
  dataset: dataset,
1526
1517
  params: startContextParams({
1527
1518
  definition: definition,
1528
- scope: scope,
1529
- dataset: dataset
1519
+ scope: scope
1530
1520
  })
1531
1521
  })).get();
1532
1522
  return invariants.isUnevaluable(result) ? !1 : !!result;
@@ -1542,11 +1532,9 @@ async function evaluateStartFilter(args) {
1542
1532
  function parseStartFilter(args) {
1543
1533
  const {filter: filter, definition: definition} = args;
1544
1534
  try {
1545
- const readsSubject = readsSubjectHasInFlightInstance(filter);
1546
1535
  return {
1547
1536
  tree: groqJs.parse(filter),
1548
- needsDataset: groqConditionDescribe.analyzeCondition(filter).readsDataset || readsSubject,
1549
- readsSubject: readsSubject
1537
+ needsDataset: groqConditionDescribe.analyzeCondition(filter).readsDataset
1550
1538
  };
1551
1539
  } catch (err) {
1552
1540
  rethrowNamingDefinition({
@@ -1557,70 +1545,81 @@ function parseStartFilter(args) {
1557
1545
  }
1558
1546
  }
1559
1547
 
1560
- function assertFilterSubject(args) {
1561
- if (!(!args.readsSubject || args.scope?.subject !== void 0)) throw new invariants.ContractViolationError(`start.filter on definition "${args.definition.name ?? "<unnamed>"}" reads $${invariants.SUBJECT_HAS_IN_FLIGHT_INSTANCE_VAR}, but the caller supplied no resource-qualified \`scope.subject\` — a loaded document alone cannot identify its project and dataset.`);
1562
- }
1563
-
1564
1548
  async function filterDataset(needsDataset, scope) {
1565
1549
  if (!needsDataset) return [];
1566
1550
  if (scope?.fetchDataset !== void 0) return scope.fetchDataset();
1567
1551
  }
1568
1552
 
1569
- async function explainStartAllowed(args) {
1570
- const {allowed: allowed, definition: definition, fields: fields, scope: scope} = args;
1553
+ async function explainStartRequirement(args) {
1554
+ const {query: query, definition: definition, fields: fields, scope: scope} = args;
1571
1555
  let needsDataset;
1572
1556
  try {
1573
- needsDataset = groqConditionDescribe.analyzeCondition(allowed).readsDataset || readsSubjectHasInFlightInstance(allowed);
1557
+ needsDataset = groqConditionDescribe.analyzeCondition(query).readsDataset;
1574
1558
  } catch (err) {
1575
1559
  rethrowNamingDefinition({
1576
1560
  err: err,
1577
1561
  definition: definition,
1578
- key: "allowed"
1562
+ key: "requirement"
1579
1563
  });
1580
1564
  }
1581
1565
  let dataset = [];
1582
1566
  if (needsDataset) {
1583
- if (scope?.fetchDataset === void 0) throw new invariants.ContractViolationError(`start.allowed on definition "${definition.name ?? "<unnamed>"}" reads the dataset (\`*[...]\`), but the caller supplied no \`scope.fetchDataset\` — evaluating over an empty slice would let a count()-style rule pass vacuously. Supply the instance slice.`);
1567
+ if (scope?.fetchDataset === void 0) throw new invariants.ContractViolationError(`start requirement on definition "${definition.name ?? "<unnamed>"}" reads the dataset (\`*[...]\`), but the caller supplied no \`scope.fetchDataset\` — evaluating over an empty slice would let a count()-style rule pass vacuously. Supply the instance slice.`);
1584
1568
  dataset = await scope.fetchDataset();
1585
1569
  }
1586
1570
  try {
1587
1571
  return await groqConditionDescribe.explainCondition({
1588
- condition: allowed,
1572
+ condition: query,
1589
1573
  dataset: dataset,
1590
1574
  params: startContextParams({
1591
1575
  definition: definition,
1592
1576
  scope: scope,
1593
- fields: fields,
1594
- dataset: dataset
1577
+ fields: fields
1595
1578
  })
1596
1579
  });
1597
1580
  } catch (err) {
1598
1581
  rethrowNamingDefinition({
1599
1582
  err: err,
1600
1583
  definition: definition,
1601
- key: "allowed"
1584
+ key: "requirement"
1602
1585
  });
1603
1586
  }
1604
1587
  }
1605
1588
 
1606
- function unboundAllowedReads(allowed, fields) {
1607
- return [ ...invariants.conditionFieldReadNames(allowed) ].filter(name => !Object.hasOwn(fields, name));
1589
+ function unboundRequirementReads(query, fields) {
1590
+ return [ ...invariants.conditionFieldReadNames(query) ].filter(name => !Object.hasOwn(fields, name));
1591
+ }
1592
+
1593
+ function hasSingleSubjectRequirement(definition) {
1594
+ return definition.start?.requirements?.some(requirement => requirement.type === "singleSubject") ?? !1;
1595
+ }
1596
+
1597
+ async function singleSubjectRequirementRefused(args) {
1598
+ const {definition: definition, fields: fields, scope: scope} = args, name = singleSubjectDefinitionName(definition), subject = (fields !== void 0 ? startSubject(definition, fields) : void 0) ?? scope?.subject;
1599
+ if (subject === void 0) return !1;
1600
+ if (scope?.fetchDataset === void 0) throw new invariants.ContractViolationError(`singleSubject requirement on definition "${name}" scans the tag's instance slice, but the caller supplied no \`scope.fetchDataset\` — evaluating over an empty slice would let the rule pass vacuously. Supply the projected start slice.`);
1601
+ const dataset = await scope.fetchDataset();
1602
+ return sliceHasInFlightSubject({
1603
+ dataset: dataset,
1604
+ subject: subject,
1605
+ definition: name
1606
+ });
1608
1607
  }
1609
1608
 
1610
- function unboundAllowedReadsWithSubject(args) {
1611
- const {allowed: allowed, fields: fields, definition: definition} = args, subjectField = (definition.fields ?? []).find(invariants.isSubjectEntry)?.name, reads = unboundAllowedReads(allowed, fields);
1612
- return subjectField !== void 0 && readsSubjectHasInFlightInstance(allowed) && !Object.hasOwn(fields, subjectField) && !reads.includes(subjectField) && reads.push(subjectField),
1613
- reads;
1609
+ function singleSubjectDefinitionName(definition) {
1610
+ const label = definition.name ?? "<unnamed>";
1611
+ if (definition.start?.requirements?.find(requirement => requirement.type === "singleSubject") === void 0) throw new invariants.ContractViolationError(`singleSubjectRequirementRefused called for definition "${label}", which declares no \`singleSubject\` requirement — evaluate only what the definition declares.`);
1612
+ if (definition.name === void 0) throw new invariants.ContractViolationError("singleSubjectRequirementRefused needs the definition `name` — the rule scopes its in-flight scan to instances of the definition, which a nameless source cannot identify.");
1613
+ return definition.name;
1614
1614
  }
1615
1615
 
1616
1616
  function rethrowNamingDefinition({err: err, definition: definition, key: key}) {
1617
- invariants.rethrowWithContext(err, `start.${key} on definition "${definition.name ?? "<unnamed>"}" failed to evaluate (check the predicate and its evaluation inputs)`);
1617
+ invariants.rethrowWithContext(err, `${key === "filter" ? "start.filter" : "start requirement"} on definition "${definition.name ?? "<unnamed>"}" failed to evaluate (check the predicate and its evaluation inputs)`);
1618
1618
  }
1619
1619
 
1620
- function startContextParams({definition: definition, scope: scope, fields: fields, dataset: dataset}) {
1621
- const subject = fields === void 0 ? scope?.subject : startSubject(definition, fields) ?? scope?.subject, params = baseStartParams(definition, scope);
1622
- return fields !== void 0 && (params.fields = fields), subject !== void 0 && (params[invariants.SUBJECT_HAS_IN_FLIGHT_INSTANCE_VAR] = subjectHasInFlightInstance(dataset, subject)),
1623
- params;
1620
+ function startContextParams({definition: definition, scope: scope, fields: fields}) {
1621
+ const params = baseStartParams(definition, scope);
1622
+ return fields !== void 0 && (params.fields = fields), params;
1624
1623
  }
1625
1624
 
1626
1625
  function baseStartParams(definition, scope) {
@@ -1637,10 +1636,6 @@ function baseStartParams(definition, scope) {
1637
1636
  };
1638
1637
  }
1639
1638
 
1640
- function readsSubjectHasInFlightInstance(groq) {
1641
- return invariants.conditionParameterNames(groq).has(invariants.SUBJECT_HAS_IN_FLIGHT_INSTANCE_VAR);
1642
- }
1643
-
1644
1639
  function startSubject(definition, fields) {
1645
1640
  const subjectEntry = (definition.fields ?? []).find(invariants.isSubjectEntry);
1646
1641
  if (subjectEntry === void 0) return;
@@ -1648,15 +1643,12 @@ function startSubject(definition, fields) {
1648
1643
  return invariants.isGdr(value) ? value.id : void 0;
1649
1644
  }
1650
1645
 
1651
- function subjectHasInFlightInstance(dataset, subject) {
1646
+ function sliceHasInFlightSubject(args) {
1647
+ const {dataset: dataset, subject: subject, definition: definition} = args;
1652
1648
  return dataset.some(row => {
1653
1649
  if (typeof row != "object" || row === null) return !1;
1654
1650
  const instance = row;
1655
- return instance._type !== invariants.WORKFLOW_INSTANCE_TYPE || instance.completedAt !== void 0 || !Array.isArray(instance.fields) ? !1 : instance.fields.some(entry => {
1656
- if (typeof entry != "object" || entry === null) return !1;
1657
- const field = entry;
1658
- return field._type === "subject" && invariants.isGdr(field.value) && field.value.id === subject;
1659
- });
1651
+ return instance.completedAt != null || instance.definition !== definition ? !1 : instance.subject === subject;
1660
1652
  });
1661
1653
  }
1662
1654
 
@@ -1686,11 +1678,11 @@ function startFilterSyntaxIssues(groq) {
1686
1678
  });
1687
1679
  }
1688
1680
 
1689
- function startAllowedSyntaxIssues(groq) {
1681
+ function startRequirementSyntaxIssues(groq) {
1690
1682
  return startContextSyntaxIssues({
1691
1683
  groq: groq,
1692
- vars: invariants.START_ALLOWED_VARS,
1693
- context: "start-allowed"
1684
+ vars: invariants.START_REQUIREMENT_VARS,
1685
+ context: "start-requirement"
1694
1686
  });
1695
1687
  }
1696
1688
 
@@ -1698,7 +1690,7 @@ function startContextSyntaxIssues({groq: groq, vars: vars, context: context, ski
1698
1690
  try {
1699
1691
  groqJs.parse(groq);
1700
1692
  } catch (err) {
1701
- return [ err instanceof Error ? err.message : String(err) ];
1693
+ return [ invariants.errorMessage(err) ];
1702
1694
  }
1703
1695
  const bound = new Set(vars.map(v2 => v2.name));
1704
1696
  return [ ...invariants.conditionParameterNames(groq) ].filter(name => !bound.has(name) && name !== skip).map(name => `reads $${name}, which the ${context} context does not bind (an unbound variable is GROQ null, so the predicate silently misevaluates — failing closed or passing vacuously by shape). Bound here: ` + vars.map(v2 => `$${v2.name}`).join(", "));
@@ -2538,24 +2530,24 @@ function applyFieldSet(op, ctx) {
2538
2530
  src: op.value,
2539
2531
  ctx: ctx,
2540
2532
  target: entrySlot(entry)
2541
- });
2542
- return invariants.validateFieldValue({
2533
+ }), validated = invariants.validateFieldValue({
2543
2534
  entryType: entry._type,
2544
2535
  entryName: entry.name,
2545
2536
  value: value,
2546
2537
  ...entryShape(entry)
2547
- }), assertRuntimeRefsWithinSurface({
2538
+ });
2539
+ return assertRuntimeRefsWithinSurface({
2548
2540
  entryType: entry._type,
2549
2541
  entryName: entry.name,
2550
- value: value,
2542
+ value: validated,
2551
2543
  ...entryShape(entry),
2552
2544
  ctx: ctx,
2553
2545
  src: op.value
2554
- }), setEntryValue(entry, value), {
2546
+ }), setEntryValue(entry, validated), {
2555
2547
  opType: op.type,
2556
2548
  target: op.target,
2557
2549
  resolved: {
2558
- value: value
2550
+ value: validated
2559
2551
  }
2560
2552
  };
2561
2553
  }
@@ -2616,27 +2608,27 @@ function applyFieldAppend(op, ctx) {
2616
2608
  ...slot !== void 0 ? {
2617
2609
  target: slot
2618
2610
  } : {}
2619
- });
2620
- invariants.validateFieldAppendItem({
2611
+ }), validated = invariants.validateFieldAppendItem({
2621
2612
  entryType: entry._type,
2622
2613
  entryName: entry.name,
2623
2614
  item: item,
2624
2615
  types: entry._type === "doc.refs" ? entry.types : void 0,
2625
2616
  of: entry._type === "array" ? entry.of : void 0
2626
- }), assertRuntimeRefsWithinSurface({
2617
+ });
2618
+ assertRuntimeRefsWithinSurface({
2627
2619
  entryType: entry._type === "doc.refs" ? "doc.ref" : "object",
2628
2620
  entryName: entry.name,
2629
- value: item,
2621
+ value: validated,
2630
2622
  fields: entry._type === "array" ? entry.of : void 0,
2631
2623
  ctx: ctx,
2632
2624
  src: op.value
2633
2625
  });
2634
2626
  const current = Array.isArray(entry.value) ? entry.value : [];
2635
- return setEntryValue(entry, [ ...current, withRowKey(item) ]), {
2627
+ return setEntryValue(entry, [ ...current, withRowKey(validated) ]), {
2636
2628
  opType: op.type,
2637
2629
  target: op.target,
2638
2630
  resolved: {
2639
- item: item
2631
+ item: validated
2640
2632
  }
2641
2633
  };
2642
2634
  }
@@ -2664,8 +2656,9 @@ async function applyFieldUpdateWhere(op, ctx) {
2664
2656
  mode: "value",
2665
2657
  issues: [ `field.updateWhere value must resolve to an object of fields to merge (target "${op.target.field}")` ]
2666
2658
  });
2659
+ const mergeRecord = merge;
2667
2660
  requireNoReservedMergeKeys({
2668
- merge: merge,
2661
+ merge: mergeRecord,
2669
2662
  entry: entry,
2670
2663
  op: op
2671
2664
  });
@@ -2675,25 +2668,27 @@ async function applyFieldUpdateWhere(op, ctx) {
2675
2668
  ctx: ctx
2676
2669
  }), next = rows.map((row, index) => matches[index] ? {
2677
2670
  ...row,
2678
- ...merge
2679
- } : row);
2680
- return invariants.validateFieldValue({
2671
+ ...mergeRecord
2672
+ } : row), validated = invariants.validateFieldValue({
2681
2673
  entryType: entry._type,
2682
2674
  entryName: entry.name,
2683
2675
  value: next,
2684
2676
  of: entry.of
2685
- }), assertRuntimeRefsWithinSurface({
2677
+ });
2678
+ assertRuntimeRefsWithinSurface({
2686
2679
  entryType: "object",
2687
2680
  entryName: entry.name,
2688
2681
  value: merge,
2689
2682
  fields: entry.of,
2690
2683
  ctx: ctx,
2691
2684
  src: op.value
2692
- }), setEntryValue(entry, next), {
2685
+ }), setEntryValue(entry, validated);
2686
+ const firstMatch = matches.indexOf(!0), persistedRows = validated, persistedMerge = firstMatch === -1 ? merge : Object.fromEntries(Object.keys(mergeRecord).map(key => [ key, persistedRows[firstMatch]?.[key] ]));
2687
+ return {
2693
2688
  opType: op.type,
2694
2689
  target: op.target,
2695
2690
  resolved: {
2696
- merge: merge
2691
+ merge: persistedMerge
2697
2692
  }
2698
2693
  };
2699
2694
  }
@@ -2885,8 +2880,8 @@ function validateDefinition(definition) {
2885
2880
  address: address
2886
2881
  }));
2887
2882
  }
2888
- definition.start?.filter !== void 0 && v2.report("start.filter", startFilterSyntaxIssues(definition.start.filter)),
2889
- definition.start?.allowed !== void 0 && v2.report("start.allowed", startAllowedSyntaxIssues(definition.start.allowed));
2883
+ definition.start?.filter !== void 0 && v2.report("start.filter", startFilterSyntaxIssues(definition.start.filter));
2884
+ for (const [index, requirement] of (definition.start?.requirements ?? []).entries()) requirement.type === "groq" && v2.report(`start.requirements[${index}].query`, startRequirementSyntaxIssues(requirement.query));
2890
2885
  for (const entry of definition.fields ?? []) v2.checkEntry(entry, `workflow.fields "${entry.name}"`);
2891
2886
  for (const stage of definition.stages) validateStage(v2, stage);
2892
2887
  for (const issue of invariants.checkWorkflowInvariants(definition)) v2.errors.push(` · ${invariants.formatIssuePath(issue.path)}: ${issue.message}`);
@@ -3316,6 +3311,11 @@ function definitionsListGroq(versionOrder) {
3316
3311
  return `*[_type == "${invariants.WORKFLOW_DEFINITION_TYPE}" && ${invariants.tagScopeFilter()}] | order(name asc, version ${versionOrder})`;
3317
3312
  }
3318
3313
 
3314
+ function latestDefinitionsGroq() {
3315
+ const scoped = `_type == "${invariants.WORKFLOW_DEFINITION_TYPE}" && ${invariants.tagScopeFilter()}`;
3316
+ return `*[${scoped} && version == math::max(*[${scoped} && name == ^.name].version)] | order(name asc)`;
3317
+ }
3318
+
3319
3319
  function latestDeployedDefinitions(rows) {
3320
3320
  const byName = /* @__PURE__ */ new Map;
3321
3321
  for (const row of rows) {
@@ -3397,7 +3397,7 @@ function blockedState(input) {
3397
3397
  if (blocked !== void 0) return {
3398
3398
  state: "blocked",
3399
3399
  activity: blocked.activity.name,
3400
- requirements: blocked.unmetRequirements ?? [],
3400
+ requirements: (blocked.unmetRequirements ?? []).map(requirement => requirement.name),
3401
3401
  assignees: input.assignees[blocked.activity.name] ?? []
3402
3402
  };
3403
3403
  }
@@ -3440,7 +3440,7 @@ function diagnoseInstance(input) {
3440
3440
  };
3441
3441
  }
3442
3442
 
3443
- const RUNNABLE_VERBS = /* @__PURE__ */ new Set([ "set-stage", "abort", "drain-effects" ]);
3443
+ const RUNNABLE_VERBS = /* @__PURE__ */ new Set([ "set-stage", "abort", "drain-effects", "reset-activity" ]);
3444
3444
 
3445
3445
  function remediationsForCause(cause) {
3446
3446
  switch (cause.kind) {
@@ -3942,7 +3942,7 @@ async function resolveOneEntry({entry: entry, initialFields: initialFields, ctx:
3942
3942
  defaultValue: defaultValue
3943
3943
  });
3944
3944
  if (entry.initialValue?.type === "query") {
3945
- const issues = invariants.checkFieldValue({
3945
+ const check = invariants.parseFieldValue({
3946
3946
  entryType: entry.type,
3947
3947
  value: value,
3948
3948
  types: entry.types,
@@ -3951,9 +3951,9 @@ async function resolveOneEntry({entry: entry, initialFields: initialFields, ctx:
3951
3951
  options: entry.options,
3952
3952
  validation: entry.validation
3953
3953
  });
3954
- return issues !== void 0 ? (ctx.recordDiscard?.({
3954
+ return "issues" in check ? (ctx.recordDiscard?.({
3955
3955
  field: entry.name,
3956
- detail: issues.join("; ")
3956
+ detail: check.issues.join("; ")
3957
3957
  }), buildResolvedEntry({
3958
3958
  entry: entry,
3959
3959
  value: defaultValue,
@@ -3961,12 +3961,12 @@ async function resolveOneEntry({entry: entry, initialFields: initialFields, ctx:
3961
3961
  now: ctx.now
3962
3962
  })) : buildResolvedEntry({
3963
3963
  entry: entry,
3964
- value: value,
3964
+ value: check.output,
3965
3965
  _key: randomKey2(),
3966
3966
  now: ctx.now
3967
3967
  });
3968
3968
  }
3969
- return invariants.validateFieldValue({
3969
+ const validated = invariants.validateFieldValue({
3970
3970
  entryType: entry.type,
3971
3971
  entryName: entry.name,
3972
3972
  value: value,
@@ -3975,16 +3975,17 @@ async function resolveOneEntry({entry: entry, initialFields: initialFields, ctx:
3975
3975
  of: entry.of,
3976
3976
  options: entry.options,
3977
3977
  validation: entry.validation
3978
- }), entry.initialValue?.type === "input" && ctx.inputProvenance !== "definition" && assertRefsWithinSurface({
3978
+ });
3979
+ return entry.initialValue?.type === "input" && ctx.inputProvenance !== "definition" && assertRefsWithinSurface({
3979
3980
  entryType: entry.type,
3980
3981
  entryName: entry.name,
3981
- value: value,
3982
+ value: validated,
3982
3983
  fields: entry.fields,
3983
3984
  of: entry.of,
3984
3985
  surface: ctx.refSurface
3985
3986
  }), buildResolvedEntry({
3986
3987
  entry: entry,
3987
- value: value,
3988
+ value: validated,
3988
3989
  _key: randomKey2(),
3989
3990
  now: ctx.now
3990
3991
  });
@@ -4378,172 +4379,605 @@ function parseInstanceDocument(doc) {
4378
4379
  });
4379
4380
  }
4380
4381
 
4381
- async function getInstanceDocument(client, instanceId) {
4382
- const doc = await client.getDocument(instanceId);
4383
- return doc ? readInstanceDoc(doc) : void 0;
4384
- }
4382
+ const SYNC_COMMIT = {
4383
+ visibility: "sync"
4384
+ }, ENGINE_API_VERSION = "2026-04-29", REQUEST_TAG = {
4385
+ engine: "workflow",
4386
+ deploy: "workflow.deploy",
4387
+ deleteDefinition: "workflow.delete-definition",
4388
+ start: "workflow.start",
4389
+ fireAction: "workflow.fire-action",
4390
+ editField: "workflow.edit-field",
4391
+ completeEffect: "workflow.complete-effect",
4392
+ commitEffectOps: "workflow.commit-effect-ops",
4393
+ tick: "workflow.tick",
4394
+ evaluate: "workflow.evaluate",
4395
+ evaluateStart: "workflow.evaluate-start",
4396
+ diagnose: "workflow.diagnose",
4397
+ availableActions: "workflow.available-actions",
4398
+ setStage: "workflow.set-stage",
4399
+ abort: "workflow.abort",
4400
+ resetActivity: "workflow.reset-activity",
4401
+ getInstance: "workflow.get-instance",
4402
+ children: "workflow.children",
4403
+ instancesForDocument: "workflow.instances-for-document",
4404
+ definitionsForDocument: "workflow.definitions-for-document",
4405
+ query: "workflow.query",
4406
+ discover: "workflow.discover",
4407
+ guardQuery: "workflow.guard.query",
4408
+ guardDeploy: "workflow.guard.deploy",
4409
+ guardRefresh: "workflow.guard.refresh",
4410
+ guardRetract: "workflow.guard.retract",
4411
+ effectList: "workflow.effect.list",
4412
+ effectFind: "workflow.effect.find",
4413
+ drain: "workflow.drain",
4414
+ effect: "workflow.effect",
4415
+ verifyDefinitions: "workflow.verify-definitions",
4416
+ accessResolveActor: "workflow.access.resolve-actor",
4417
+ accessGrants: "workflow.access.grants"
4418
+ }, RAW_PATCH = /* @__PURE__ */ Symbol("workflow-engine.raw-patch");
4385
4419
 
4386
- function readInstanceDoc(doc) {
4387
- return parseInstanceDocument(invariants.assertReadableModel(doc));
4420
+ function unwrapPatch(patch) {
4421
+ return typeof patch == "object" && patch !== null && RAW_PATCH in patch ? patch[RAW_PATCH] : patch;
4388
4422
  }
4389
4423
 
4390
- async function reload({client: client, instanceId: instanceId, tag: tag}) {
4391
- const doc = await getInstanceDocument(client, instanceId);
4392
- if (!doc) throw new invariants.InstanceNotFoundError({
4393
- instanceId: instanceId
4394
- });
4395
- if (doc.tag !== tag) throw new invariants.InstanceNotFoundError({
4396
- instanceId: instanceId,
4397
- detail: "not visible to this engine: tag mismatch"
4398
- });
4399
- return doc;
4400
- }
4424
+ const wrapperCache = /* @__PURE__ */ new WeakMap, effectHandlerClientCache = /* @__PURE__ */ new WeakMap, RAW_CLIENT = /* @__PURE__ */ Symbol("workflow-engine.raw-client");
4401
4425
 
4402
- function contextEntry(name, value) {
4403
- const _key = randomKey();
4404
- return typeof value == "string" ? {
4405
- _key: _key,
4406
- _type: "context.string",
4407
- name: name,
4408
- value: value
4409
- } : typeof value == "number" ? {
4410
- _key: _key,
4411
- _type: "context.number",
4412
- name: name,
4413
- value: value
4414
- } : typeof value == "boolean" ? {
4415
- _key: _key,
4416
- _type: "context.boolean",
4417
- name: name,
4418
- value: value
4419
- } : {
4420
- _key: _key,
4421
- _type: "context.ref",
4422
- name: name,
4423
- value: value
4424
- };
4426
+ function unwrapRequestTag(client) {
4427
+ let current = client;
4428
+ for (;RAW_CLIENT in current; ) current = current[RAW_CLIENT];
4429
+ return current;
4425
4430
  }
4426
4431
 
4427
- function contextJsonEntry(name, value) {
4428
- return {
4429
- _key: randomKey(),
4430
- _type: "context.json",
4431
- name: name,
4432
- value: serializeContextValue(name, value)
4433
- };
4432
+ function withRequestTag(client, fallback) {
4433
+ let byTag = wrapperCache.get(client);
4434
+ byTag === void 0 && (byTag = /* @__PURE__ */ new Map, wrapperCache.set(client, byTag));
4435
+ const cached = byTag.get(fallback);
4436
+ if (cached !== void 0) return cached;
4437
+ const wrapped = buildTaggedClient(client, fallback);
4438
+ return byTag.set(fallback, wrapped), wrapped;
4434
4439
  }
4435
4440
 
4436
- function serializeContextValue(name, value) {
4437
- let json;
4438
- try {
4439
- json = JSON.stringify(value);
4440
- } catch (err) {
4441
- invariants.rethrowWithContext(err, `context entry "${name}" holds unserializable JSON`);
4441
+ function effectHandlerClient(client) {
4442
+ const cached = effectHandlerClientCache.get(client);
4443
+ if (cached !== void 0) return cached;
4444
+ let tagged;
4445
+ if (client.withConfig === void 0) tagged = withRequestTag(client, REQUEST_TAG.effect); else {
4446
+ const prefix = clientRequestTagPrefix(client), effectTag = composeRequestTag(prefix, REQUEST_TAG.effect);
4447
+ tagged = client.withConfig({
4448
+ requestTagPrefix: effectTag
4449
+ });
4442
4450
  }
4443
- if (json === void 0) throw new Error(`context entry "${name}" holds a non-JSON value (undefined, a function, or a symbol)`);
4444
- return json;
4451
+ return effectHandlerClientCache.set(client, tagged), tagged;
4445
4452
  }
4446
4453
 
4447
- function buildInstanceBase(args) {
4448
- const {id: id, now: now, actor: actor, perspective: perspective, executionContext: executionContext} = args, entries = [ {
4449
- _key: randomKey(),
4450
- _type: "stageEntered",
4451
- at: now,
4452
- stage: args.initialStage,
4453
- ...actor !== void 0 ? {
4454
- actor: actor
4455
- } : {}
4456
- }, ...args.extraHistory ?? [] ], history = executionContext !== void 0 ? stampHistoryEntries(entries, executionContext) : entries, body = {
4457
- _id: id,
4458
- _type: invariants.WORKFLOW_INSTANCE_TYPE,
4459
- _rev: "",
4460
- _createdAt: now,
4461
- _updatedAt: now,
4462
- tag: args.tag,
4463
- workflowResource: args.workflowResource,
4464
- definition: args.definitionName,
4465
- pinnedVersion: args.pinnedVersion,
4466
- ...args.pinnedContentHash !== void 0 ? {
4467
- pinnedContentHash: args.pinnedContentHash
4468
- } : {},
4469
- definitionSnapshot: JSON.stringify(args.definition),
4470
- fields: args.fields,
4471
- context: args.context,
4472
- ancestors: args.ancestors,
4473
- ...perspective !== void 0 ? {
4474
- perspective: perspective
4475
- } : {},
4476
- currentStage: args.initialStage,
4477
- stages: [],
4478
- subworkflows: [],
4479
- pendingEffects: [],
4480
- effectHistory: [],
4481
- history: history,
4482
- startedAt: now,
4483
- lastChangedAt: now
4484
- };
4485
- return {
4486
- ...body,
4487
- ...invariants.modelStampFor({
4488
- documentType: "instance",
4489
- document: body
4490
- })
4491
- };
4454
+ function effectHandlerResolver(resolver) {
4455
+ return mapResourceClientResolver(resolver, effectHandlerClient);
4492
4456
  }
4493
4457
 
4494
- async function hydrateSnapshot(args) {
4495
- const {client: client, clientForGdr: clientForGdr, instance: instance, overlay: overlay} = args, loaded = [], visited = /* @__PURE__ */ new Set;
4496
- loaded.push({
4497
- doc: instance,
4498
- resource: instance.workflowResource
4499
- }), visited.add(invariants.selfGdr(instance));
4500
- const {pending: pending, ordered: ordered} = planReads({
4501
- client: client,
4502
- clientForGdr: clientForGdr,
4503
- instance: instance,
4504
- overlay: overlay,
4505
- visited: visited
4506
- }), fetched = await readPending(pending);
4507
- for (const entry of ordered) if (!isPendingRead(entry)) loaded.push(entry); else {
4508
- const doc = fetched.get(entry);
4509
- doc !== void 0 && loaded.push({
4510
- doc: doc,
4511
- resource: entry.resource
4512
- });
4513
- }
4514
- return buildSnapshot({
4515
- docs: loaded
4516
- });
4458
+ function mapResourceClientResolver(resolver, mapClient) {
4459
+ if (resolver !== void 0) return parsed => {
4460
+ const client = resolver(parsed);
4461
+ return client === void 0 ? void 0 : mapClient(client);
4462
+ };
4517
4463
  }
4518
4464
 
4519
- function planReads(args) {
4520
- const {client: client, clientForGdr: clientForGdr, instance: instance, overlay: overlay, visited: visited} = args, pending = [], ordered = [];
4521
- for (const ref of collectWatchRefs(instance)) {
4522
- if (visited.has(ref.id)) continue;
4523
- visited.add(ref.id);
4524
- const held = overlay?.get(ref.id);
4525
- if (held !== void 0) ordered.push(held); else {
4526
- const read = routeRead({
4527
- defaultClient: client,
4528
- clientForGdr: clientForGdr,
4529
- defaultResource: instance.workflowResource,
4530
- uri: ref.id,
4531
- perspective: readsRaw(ref) ? "raw" : instance.perspective ?? DEFAULT_CONTENT_PERSPECTIVE
4532
- });
4533
- pending.push(read), ordered.push(read);
4534
- }
4535
- }
4536
- return {
4537
- pending: pending,
4538
- ordered: ordered
4539
- };
4465
+ function isWorkflowsFamilyPrefix(prefix) {
4466
+ return prefix === void 0 ? !1 : prefix === "sanity.workflows" || prefix.startsWith("sanity.workflows.") || prefix === "sanity.workflows-mcp";
4540
4467
  }
4541
4468
 
4542
- function isPendingRead(entry) {
4543
- return "client" in entry;
4469
+ function clientRequestTagPrefix(client) {
4470
+ const probe = client;
4471
+ return typeof probe.config == "function" ? probe.config().requestTagPrefix : void 0;
4544
4472
  }
4545
4473
 
4546
- const SNAPSHOT_READ_BATCH_SIZE = 100, SNAPSHOT_READ_CONCURRENCY = 4, snapshotDocsQuery = "*[_id in $ids]";
4474
+ function composeRequestTag(prefix, tag) {
4475
+ if (prefix === void 0) return tag;
4476
+ const relative = isWorkflowsFamilyPrefix(prefix) ? stripWorkflowRoot(tag) : tag;
4477
+ return `${prefix}.${relative}`;
4478
+ }
4479
+
4480
+ function stripWorkflowRoot(tag) {
4481
+ return tag.startsWith("workflow.") ? tag.slice(9) : tag;
4482
+ }
4483
+
4484
+ function buildTaggedClient(client, fallback) {
4485
+ const strip = isWorkflowsFamilyPrefix(clientRequestTagPrefix(unwrapRequestTag(client))), normalize = tag => strip ? stripWorkflowRoot(tag) : tag, stamp = options => options === void 0 ? {
4486
+ tag: normalize(fallback)
4487
+ } : options.tag === void 0 ? {
4488
+ ...options,
4489
+ tag: normalize(fallback)
4490
+ } : typeof options.tag == "string" && options.tag !== normalize(options.tag) ? {
4491
+ ...options,
4492
+ tag: normalize(options.tag)
4493
+ } : options, wrapPatch = patch => {
4494
+ let target = patch;
4495
+ const wrapped = {
4496
+ get [RAW_PATCH]() {
4497
+ return target;
4498
+ },
4499
+ set: props => (target = target.set(props), wrapped),
4500
+ setIfMissing: props => (target = target.setIfMissing(props), wrapped),
4501
+ unset: paths => (target = target.unset(paths), wrapped),
4502
+ ifRevisionId: rev => (target = target.ifRevisionId(rev), wrapped),
4503
+ commit: options => target.commit(stamp(options))
4504
+ };
4505
+ return wrapped;
4506
+ }, wrapTransaction = tx => {
4507
+ let target = tx;
4508
+ const wrapped = {
4509
+ create: doc => (target = target.create(doc), wrapped),
4510
+ patch: patch => (target = target.patch(unwrapPatch(patch)), wrapped),
4511
+ delete: id => (target = target.delete(id), wrapped),
4512
+ commit: options => target.commit(stamp(options))
4513
+ };
4514
+ return wrapped;
4515
+ }, overrides = {
4516
+ [RAW_CLIENT]: unwrapRequestTag(client),
4517
+ fetch: (query, params, options) => client.fetch(query, params, stamp(options)),
4518
+ getDocument: (id, options) => client.getDocument(id, stamp(options)),
4519
+ patch: documentId => wrapPatch(client.patch(documentId)),
4520
+ create: (doc, options) => client.create(doc, stamp(options)),
4521
+ transaction: () => wrapTransaction(client.transaction()),
4522
+ ...client.withConfig !== void 0 ? {
4523
+ withConfig: config => withRequestTag(client.withConfig(config), fallback)
4524
+ } : {},
4525
+ ...client.action !== void 0 ? {
4526
+ action: (action, options) => client.action(action, stamp(options))
4527
+ } : {},
4528
+ ...client.request !== void 0 ? {
4529
+ request: opts => client.request(stamp(opts))
4530
+ } : {}
4531
+ };
4532
+ return new Proxy(client, {
4533
+ has: (target, property) => Object.hasOwn(overrides, property) || property in target,
4534
+ get: (target, property) => {
4535
+ if (Object.hasOwn(overrides, property)) return Reflect.get(overrides, property, overrides);
4536
+ const value = Reflect.get(target, property, target);
4537
+ return typeof value == "function" ? value.bind(target) : value;
4538
+ }
4539
+ });
4540
+ }
4541
+
4542
+ const pinCache = /* @__PURE__ */ new WeakMap, enginePinned = /* @__PURE__ */ new WeakSet;
4543
+
4544
+ function pinApiVersion(client) {
4545
+ const raw = unwrapRequestTag(client);
4546
+ if (enginePinned.has(raw) || raw.withConfig === void 0) return client;
4547
+ let sibling = pinCache.get(raw);
4548
+ return sibling === void 0 && (sibling = raw.withConfig({
4549
+ apiVersion: ENGINE_API_VERSION
4550
+ }), pinCache.set(raw, sibling), enginePinned.add(unwrapRequestTag(sibling))), sibling;
4551
+ }
4552
+
4553
+ function taggedResolver(resolver, fallback) {
4554
+ return mapResourceClientResolver(resolver, client => withRequestTag(pinApiVersion(client), fallback));
4555
+ }
4556
+
4557
+ function taggedScope(args, tag) {
4558
+ const resourceClients = taggedResolver(args.resourceClients, tag);
4559
+ return {
4560
+ ...args,
4561
+ client: withRequestTag(pinApiVersion(args.client), tag),
4562
+ ...resourceClients !== void 0 ? {
4563
+ resourceClients: resourceClients
4564
+ } : {}
4565
+ };
4566
+ }
4567
+
4568
+ const ACTOR_KIND_SET = new Set(invariants.ACTOR_KINDS), resolutionCache = /* @__PURE__ */ new WeakMap, warnedInstances = /* @__PURE__ */ new WeakMap;
4569
+
4570
+ async function normalizeInstanceIdentities(args) {
4571
+ const {client: client, instance: instance} = args, pending = collectLegacyIds(instance);
4572
+ if (pending.size === 0) return instance;
4573
+ const resolved = await resolveLegacyIds({
4574
+ client: client,
4575
+ instance: instance,
4576
+ pending: pending
4577
+ }), unresolved = [ ...pending ].filter(id => !resolved.has(id));
4578
+ return unresolved.length > 0 ? (warnUnresolvedOnce({
4579
+ client: client,
4580
+ instance: instance,
4581
+ unresolved: unresolved
4582
+ }), instance) : rewriteIdentitySlots(instance, id => resolved.get(id));
4583
+ }
4584
+
4585
+ async function resolveLegacyIds(args) {
4586
+ const resolved = /* @__PURE__ */ new Map, directoryIds = [];
4587
+ for (const id of args.pending) {
4588
+ const {globalId: globalId} = invariants.classifyPrincipalId(id);
4589
+ globalId !== void 0 ? resolved.set(id, globalId) : directoryIds.push(id);
4590
+ }
4591
+ const projectId = anchorProjectId(args.instance.workflowResource);
4592
+ if (directoryIds.length === 0 || projectId === void 0) return resolved;
4593
+ const fromDirectory = await resolveThroughDirectory({
4594
+ client: args.client,
4595
+ projectId: projectId,
4596
+ ids: directoryIds
4597
+ });
4598
+ for (const [id, globalId] of fromDirectory) resolved.set(id, globalId);
4599
+ return resolved;
4600
+ }
4601
+
4602
+ function warnUnresolvedOnce(args) {
4603
+ const key = unwrapRequestTag(args.client);
4604
+ let warned = warnedInstances.get(key);
4605
+ warned === void 0 && (warned = /* @__PURE__ */ new Set, warnedInstances.set(key, warned)),
4606
+ !warned.has(args.instance._id) && (warned.add(args.instance._id), console.warn(`workflow: instance "${args.instance._id}" carries ${args.unresolved.length} legacy project-scoped principal id(s) the project-users directory could not resolve (${args.unresolved.join(", ")}). Its identity values are left as stored — comparisons against them fail closed — and the document does not self-heal until they resolve.`));
4607
+ }
4608
+
4609
+ function anchorProjectId(resource) {
4610
+ if (resource.type === "dataset") return invariants.datasetResourceParts(resource.id).projectId;
4611
+ }
4612
+
4613
+ function collectLegacyIds(instance) {
4614
+ const found = /* @__PURE__ */ new Set;
4615
+ return rewriteIdentitySlots(instance, id => {
4616
+ invariants.classifyPrincipalId(id).namespace === "project" && found.add(id);
4617
+ }), found;
4618
+ }
4619
+
4620
+ function rewriteIdentitySlots(instance, visit) {
4621
+ const record = instance, fields = walkEntries(record.fields, visit), stages = walkStages(record.stages, visit);
4622
+ return fields === record.fields && stages === record.stages ? instance : {
4623
+ ...record,
4624
+ fields: fields,
4625
+ stages: stages
4626
+ };
4627
+ }
4628
+
4629
+ function walkStages(stages, visit) {
4630
+ return Array.isArray(stages) ? shareMap(stages, stage => {
4631
+ const walked = walkEntryRow({
4632
+ row: stage,
4633
+ visit: visit
4634
+ });
4635
+ if (walked === null || typeof walked != "object") return walked;
4636
+ const record = walked, activities = walkActivities(record.activities, visit);
4637
+ return activities === record.activities ? walked === stage ? stage : walked : {
4638
+ ...record,
4639
+ activities: activities
4640
+ };
4641
+ }) : stages;
4642
+ }
4643
+
4644
+ function walkActivities(activities, visit) {
4645
+ return Array.isArray(activities) ? shareMap(activities, activity => walkEntryRow({
4646
+ row: activity,
4647
+ visit: visit
4648
+ })) : activities;
4649
+ }
4650
+
4651
+ function walkEntryRow(args) {
4652
+ const {row: row, visit: visit} = args;
4653
+ if (row === null || typeof row != "object") return row;
4654
+ const record = row, patch = {}, fields = walkEntries(record.fields, visit);
4655
+ if (fields !== record.fields && (patch.fields = fields), typeof record.completedBy == "string") {
4656
+ const stamped = visit(record.completedBy) ?? record.completedBy;
4657
+ stamped !== record.completedBy && (patch.completedBy = stamped);
4658
+ }
4659
+ return Object.keys(patch).length === 0 ? row : {
4660
+ ...record,
4661
+ ...patch
4662
+ };
4663
+ }
4664
+
4665
+ function walkEntries(entries, visit) {
4666
+ return Array.isArray(entries) ? shareMap(entries, entry => {
4667
+ if (entry === null || typeof entry != "object") return entry;
4668
+ const record = entry, value = walkDeclaredValue({
4669
+ type: record._type,
4670
+ fields: record.fields,
4671
+ of: record.of,
4672
+ value: record.value,
4673
+ visit: visit
4674
+ });
4675
+ return value === record.value ? entry : {
4676
+ ...record,
4677
+ value: value
4678
+ };
4679
+ }) : entries;
4680
+ }
4681
+
4682
+ function collectDeclaredGlobalIds(args) {
4683
+ const found = /* @__PURE__ */ new Set;
4684
+ return walkDeclaredValue({
4685
+ type: args.type,
4686
+ fields: args.fields,
4687
+ of: args.of,
4688
+ value: args.value,
4689
+ visit: id => {
4690
+ invariants.classifyPrincipalId(id).namespace === "global" && found.add(id);
4691
+ }
4692
+ }), found;
4693
+ }
4694
+
4695
+ function rewriteDeclaredPrincipalIds(args) {
4696
+ return walkDeclaredValue({
4697
+ type: args.type,
4698
+ fields: args.fields,
4699
+ of: args.of,
4700
+ value: args.value,
4701
+ visit: id => args.map.get(id)
4702
+ });
4703
+ }
4704
+
4705
+ function walkDeclaredValue(args) {
4706
+ const {type: type, value: value, visit: visit} = args;
4707
+ return type === "actor" || type === "assignee" ? visitPrincipalObject(value, visit) : type === "assignees" ? Array.isArray(value) ? shareMap(value, item => visitPrincipalObject(item, visit)) : value : type === "object" ? walkDeclaredObject({
4708
+ value: value,
4709
+ shapes: args.fields,
4710
+ visit: visit
4711
+ }) : type === "array" && Array.isArray(value) ? shareMap(value, row => walkDeclaredObject({
4712
+ value: row,
4713
+ shapes: args.of,
4714
+ visit: visit
4715
+ })) : value;
4716
+ }
4717
+
4718
+ function walkDeclaredObject(args) {
4719
+ const {value: value, shapes: shapes, visit: visit} = args;
4720
+ if (value === null || typeof value != "object" || Array.isArray(value) || !Array.isArray(shapes)) return value;
4721
+ const record = value, patch = {};
4722
+ for (const shape of shapes) {
4723
+ const step = walkDeclaredProperty({
4724
+ record: record,
4725
+ shape: shape,
4726
+ visit: visit
4727
+ });
4728
+ step !== void 0 && (patch[step.name] = step.value);
4729
+ }
4730
+ return Object.keys(patch).length === 0 ? value : {
4731
+ ...record,
4732
+ ...patch
4733
+ };
4734
+ }
4735
+
4736
+ function walkDeclaredProperty(args) {
4737
+ const {record: record, shape: shape, visit: visit} = args;
4738
+ if (shape === null || typeof shape != "object") return;
4739
+ const name = shape.name;
4740
+ if (typeof name != "string" || !Object.hasOwn(record, name)) return;
4741
+ const walked = walkDeclaredValue({
4742
+ type: shape.type,
4743
+ fields: shape.fields,
4744
+ of: shape.of,
4745
+ value: record[name],
4746
+ visit: visit
4747
+ });
4748
+ return walked === record[name] ? void 0 : {
4749
+ name: name,
4750
+ value: walked
4751
+ };
4752
+ }
4753
+
4754
+ function visitPrincipalObject(value, visit) {
4755
+ if (value === null || typeof value != "object" || Array.isArray(value)) return value;
4756
+ const record = value;
4757
+ if (typeof record.id != "string" || record.type !== "user" && !(typeof record.kind == "string" && ACTOR_KIND_SET.has(record.kind))) return value;
4758
+ const stamped = visit(record.id) ?? record.id;
4759
+ return stamped === record.id ? value : {
4760
+ ...record,
4761
+ id: stamped
4762
+ };
4763
+ }
4764
+
4765
+ function shareMap(items, fn) {
4766
+ let changed = !1;
4767
+ const next = items.map(item => {
4768
+ const out = fn(item);
4769
+ return out !== item && (changed = !0), out;
4770
+ });
4771
+ return changed ? next : items;
4772
+ }
4773
+
4774
+ const SAFE_ID = /^[A-Za-z0-9_-]+$/;
4775
+
4776
+ async function resolveThroughDirectory(args) {
4777
+ const {client: client, projectId: projectId, ids: ids} = args, cache = cacheFor(unwrapRequestTag(client)), out = /* @__PURE__ */ new Map, safeMisses = ids.filter(id => {
4778
+ const hit = cache.get(id);
4779
+ return typeof hit == "string" && out.set(id, hit), hit === void 0;
4780
+ }).filter(id => SAFE_ID.test(id) && SAFE_ID.test(projectId));
4781
+ if (safeMisses.length === 0 || client.request === void 0) return out;
4782
+ try {
4783
+ const response = await client.request({
4784
+ uri: `/projects/${encodeURIComponent(projectId)}/users/${safeMisses.map(encodeURIComponent).join(",")}`,
4785
+ tag: REQUEST_TAG.accessResolveActor
4786
+ });
4787
+ ingestDirectoryRows({
4788
+ response: response,
4789
+ requested: new Set(safeMisses),
4790
+ cache: cache,
4791
+ out: out
4792
+ });
4793
+ for (const id of safeMisses) out.has(id) || cache.set(id, null);
4794
+ } catch (err) {
4795
+ console.warn(`workflow: project-users directory lookup failed for project "${projectId}" — legacy principal ids stay unresolved this pass. Original error: ${invariants.errorMessage(err)}`);
4796
+ }
4797
+ return out;
4798
+ }
4799
+
4800
+ function cacheFor(client) {
4801
+ let cache = resolutionCache.get(client);
4802
+ return cache === void 0 && (cache = /* @__PURE__ */ new Map, resolutionCache.set(client, cache)),
4803
+ cache;
4804
+ }
4805
+
4806
+ function ingestDirectoryRows(args) {
4807
+ const records = Array.isArray(args.response) ? args.response : [ args.response ];
4808
+ for (const row of records) typeof row?.id != "string" || typeof row.sanityUserId != "string" || args.requested.has(row.id) && invariants.classifyPrincipalId(row.sanityUserId).namespace === "global" && (args.cache.set(row.id, row.sanityUserId),
4809
+ args.out.set(row.id, row.sanityUserId));
4810
+ }
4811
+
4812
+ async function getInstanceDocument(client, instanceId) {
4813
+ const doc = await client.getDocument(instanceId);
4814
+ if (doc) return normalizeInstanceIdentities({
4815
+ client: client,
4816
+ instance: readInstanceDoc(doc)
4817
+ });
4818
+ }
4819
+
4820
+ function readInstanceDoc(doc) {
4821
+ return parseInstanceDocument(invariants.assertReadableModel(doc));
4822
+ }
4823
+
4824
+ async function reload({client: client, instanceId: instanceId, tag: tag}) {
4825
+ const doc = await getInstanceDocument(client, instanceId);
4826
+ if (!doc) throw new invariants.InstanceNotFoundError({
4827
+ instanceId: instanceId
4828
+ });
4829
+ if (doc.tag !== tag) throw new invariants.InstanceNotFoundError({
4830
+ instanceId: instanceId,
4831
+ detail: "not visible to this engine: tag mismatch"
4832
+ });
4833
+ return doc;
4834
+ }
4835
+
4836
+ function contextEntry(name, value) {
4837
+ const _key = randomKey();
4838
+ return typeof value == "string" ? {
4839
+ _key: _key,
4840
+ _type: "context.string",
4841
+ name: name,
4842
+ value: value
4843
+ } : typeof value == "number" ? {
4844
+ _key: _key,
4845
+ _type: "context.number",
4846
+ name: name,
4847
+ value: value
4848
+ } : typeof value == "boolean" ? {
4849
+ _key: _key,
4850
+ _type: "context.boolean",
4851
+ name: name,
4852
+ value: value
4853
+ } : {
4854
+ _key: _key,
4855
+ _type: "context.ref",
4856
+ name: name,
4857
+ value: value
4858
+ };
4859
+ }
4860
+
4861
+ function contextJsonEntry(name, value) {
4862
+ return {
4863
+ _key: randomKey(),
4864
+ _type: "context.json",
4865
+ name: name,
4866
+ value: serializeContextValue(name, value)
4867
+ };
4868
+ }
4869
+
4870
+ function serializeContextValue(name, value) {
4871
+ let json;
4872
+ try {
4873
+ json = JSON.stringify(value);
4874
+ } catch (err) {
4875
+ invariants.rethrowWithContext(err, `context entry "${name}" holds unserializable JSON`);
4876
+ }
4877
+ if (json === void 0) throw new Error(`context entry "${name}" holds a non-JSON value (undefined, a function, or a symbol)`);
4878
+ return json;
4879
+ }
4880
+
4881
+ function buildInstanceBase(args) {
4882
+ const {id: id, now: now, actor: actor, perspective: perspective, executionContext: executionContext} = args, entries = [ {
4883
+ _key: randomKey(),
4884
+ _type: "stageEntered",
4885
+ at: now,
4886
+ stage: args.initialStage,
4887
+ ...actor !== void 0 ? {
4888
+ actor: actor
4889
+ } : {}
4890
+ }, ...args.extraHistory ?? [] ], history = executionContext !== void 0 ? stampHistoryEntries(entries, executionContext) : entries, body = {
4891
+ _id: id,
4892
+ _type: invariants.WORKFLOW_INSTANCE_TYPE,
4893
+ _rev: "",
4894
+ _createdAt: now,
4895
+ _updatedAt: now,
4896
+ tag: args.tag,
4897
+ workflowResource: args.workflowResource,
4898
+ definition: args.definitionName,
4899
+ pinnedVersion: args.pinnedVersion,
4900
+ ...args.pinnedContentHash !== void 0 ? {
4901
+ pinnedContentHash: args.pinnedContentHash
4902
+ } : {},
4903
+ definitionSnapshot: JSON.stringify(args.definition),
4904
+ fields: args.fields,
4905
+ context: args.context,
4906
+ ancestors: args.ancestors,
4907
+ ...perspective !== void 0 ? {
4908
+ perspective: perspective
4909
+ } : {},
4910
+ currentStage: args.initialStage,
4911
+ stages: [],
4912
+ subworkflows: [],
4913
+ pendingEffects: [],
4914
+ effectHistory: [],
4915
+ history: history,
4916
+ startedAt: now,
4917
+ lastChangedAt: now
4918
+ };
4919
+ return {
4920
+ ...body,
4921
+ ...invariants.modelStampFor({
4922
+ documentType: "instance",
4923
+ document: body
4924
+ })
4925
+ };
4926
+ }
4927
+
4928
+ async function hydrateSnapshot(args) {
4929
+ const {client: client, clientForGdr: clientForGdr, instance: instance, overlay: overlay} = args, loaded = [], visited = /* @__PURE__ */ new Set;
4930
+ loaded.push({
4931
+ doc: instance,
4932
+ resource: instance.workflowResource
4933
+ }), visited.add(invariants.selfGdr(instance));
4934
+ const {pending: pending, ordered: ordered} = planReads({
4935
+ client: client,
4936
+ clientForGdr: clientForGdr,
4937
+ instance: instance,
4938
+ overlay: overlay,
4939
+ visited: visited
4940
+ }), fetched = await readPending(pending);
4941
+ for (const entry of ordered) if (!isPendingRead(entry)) loaded.push(entry); else {
4942
+ const doc = fetched.get(entry);
4943
+ doc !== void 0 && loaded.push({
4944
+ doc: doc,
4945
+ resource: entry.resource
4946
+ });
4947
+ }
4948
+ return buildSnapshot({
4949
+ docs: loaded
4950
+ });
4951
+ }
4952
+
4953
+ function planReads(args) {
4954
+ const {client: client, clientForGdr: clientForGdr, instance: instance, overlay: overlay, visited: visited} = args, pending = [], ordered = [];
4955
+ for (const ref of collectWatchRefs(instance)) {
4956
+ if (visited.has(ref.id)) continue;
4957
+ visited.add(ref.id);
4958
+ const held = overlay?.get(ref.id);
4959
+ if (held !== void 0) ordered.push(held); else {
4960
+ const read = routeRead({
4961
+ defaultClient: client,
4962
+ clientForGdr: clientForGdr,
4963
+ defaultResource: instance.workflowResource,
4964
+ uri: ref.id,
4965
+ perspective: readsRaw(ref) ? "raw" : instance.perspective ?? DEFAULT_CONTENT_PERSPECTIVE
4966
+ });
4967
+ pending.push(read), ordered.push(read);
4968
+ }
4969
+ }
4970
+ return {
4971
+ pending: pending,
4972
+ ordered: ordered
4973
+ };
4974
+ }
4975
+
4976
+ function isPendingRead(entry) {
4977
+ return "client" in entry;
4978
+ }
4979
+
4980
+ const SNAPSHOT_READ_BATCH_SIZE = 100, SNAPSHOT_READ_CONCURRENCY = 4, snapshotDocsQuery = "*[_id in $ids]";
4547
4981
 
4548
4982
  function routeRead({defaultClient: defaultClient, clientForGdr: clientForGdr, defaultResource: defaultResource, uri: uri, perspective: perspective}) {
4549
4983
  const parsed = invariants.tryParseGdr(uri);
@@ -4660,29 +5094,31 @@ async function loadContext({client: client, instanceId: instanceId, options: opt
4660
5094
  if (!instance) throw new invariants.InstanceNotFoundError({
4661
5095
  instanceId: instanceId
4662
5096
  });
4663
- const definition = invariants.parseDefinitionSnapshot(instance), {clientForGdr: clientForGdr, refSurface: refSurface} = options, clock = options.clock ?? wallClock, snapshot = await hydrateSnapshot({
5097
+ return buildEngineContext({
4664
5098
  client: client,
4665
- clientForGdr: clientForGdr,
5099
+ clientForGdr: options.clientForGdr,
5100
+ refSurface: options.refSurface,
4666
5101
  instance: instance,
5102
+ definition: invariants.parseDefinitionSnapshot(instance),
5103
+ ...options.actor !== void 0 ? {
5104
+ actor: options.actor
5105
+ } : {},
5106
+ ...options.clock !== void 0 ? {
5107
+ clock: options.clock
5108
+ } : {},
5109
+ ...options.executionContext !== void 0 ? {
5110
+ executionContext: options.executionContext
5111
+ } : {},
5112
+ ...options.telemetry !== void 0 ? {
5113
+ telemetry: options.telemetry
5114
+ } : {},
4667
5115
  ...options.overlay !== void 0 ? {
4668
5116
  overlay: options.overlay
5117
+ } : {},
5118
+ ...options.settlingCohorts !== void 0 ? {
5119
+ settlingCohorts: options.settlingCohorts
4669
5120
  } : {}
4670
5121
  });
4671
- return {
4672
- client: client,
4673
- clientForGdr: clientForGdr,
4674
- refSurface: refSurface,
4675
- clock: clock,
4676
- now: clock(),
4677
- executionContext: resolveExecutionContext(options?.executionContext),
4678
- telemetry: resolveTelemetry(options.telemetry),
4679
- ...options?.actor !== void 0 ? {
4680
- actor: options.actor
4681
- } : {},
4682
- instance: instance,
4683
- definition: definition,
4684
- snapshot: snapshot
4685
- };
4686
5122
  }
4687
5123
 
4688
5124
  async function ctxConditionParams(ctx, opts) {
@@ -4720,6 +5156,9 @@ async function buildEngineContext(args) {
4720
5156
  now: clock(),
4721
5157
  executionContext: resolveExecutionContext(args.executionContext),
4722
5158
  telemetry: resolveTelemetry(args.telemetry),
5159
+ ...args.settlingCohorts !== void 0 ? {
5160
+ settlingCohorts: args.settlingCohorts
5161
+ } : {},
4723
5162
  ...args.actor !== void 0 ? {
4724
5163
  actor: args.actor
4725
5164
  } : {},
@@ -4728,7 +5167,10 @@ async function buildEngineContext(args) {
4728
5167
  snapshot: await hydrateSnapshot({
4729
5168
  client: client,
4730
5169
  clientForGdr: clientForGdr,
4731
- instance: instance
5170
+ instance: instance,
5171
+ ...args.overlay !== void 0 ? {
5172
+ overlay: args.overlay
5173
+ } : {}
4732
5174
  })
4733
5175
  };
4734
5176
  }
@@ -4851,10 +5293,6 @@ function recordProcessedRequest({mutation: mutation, record: record, now: now})
4851
5293
  } ];
4852
5294
  }
4853
5295
 
4854
- const SYNC_COMMIT = {
4855
- visibility: "sync"
4856
- }, ENGINE_API_VERSION = "2026-04-29";
4857
-
4858
5296
  function resolveGuardRead(args) {
4859
5297
  const {expr: expr, ctx: ctx, deref: deref} = args;
4860
5298
  if (expr === "$self") return invariants.selfGdr(ctx.instance);
@@ -4874,66 +5312,345 @@ function resolveGuardRead(args) {
4874
5312
  const outputs = effectOutputsMap(ctx.instance)[effectsRead[1]];
4875
5313
  return effectsRead[2] !== void 0 ? getPath(outputs, effectsRead[2]) : outputs;
4876
5314
  }
4877
- throw new Error(`Guard read "${expr}" is not a supported deploy-time value — use "$self", "$now", "$fields.<name>[.path]", or "$effects['<name>'][.path]" (guards store resolved values; the lake cannot see $fields or $effects)`);
5315
+ throw new Error(`Guard read "${expr}" is not a supported deploy-time value — use "$self", "$now", "$fields.<name>[.path]", or "$effects['<name>'][.path]" (guards store resolved values; the lake cannot see $fields or $effects)`);
5316
+ }
5317
+
5318
+ function resolveIdRefTarget(expr, ctx) {
5319
+ const value = resolveGuardRead({
5320
+ expr: expr,
5321
+ ctx: ctx,
5322
+ deref: !1
5323
+ });
5324
+ if (typeof value == "string" && invariants.isGdrUri(value)) return {
5325
+ parsed: invariants.parseGdr(value)
5326
+ };
5327
+ if (value && typeof value == "object") {
5328
+ const v2 = value;
5329
+ if (typeof v2.id == "string" && invariants.isGdrUri(v2.id)) return typeof v2.type == "string" ? {
5330
+ parsed: invariants.parseGdr(v2.id),
5331
+ type: v2.type
5332
+ } : {
5333
+ parsed: invariants.parseGdr(v2.id)
5334
+ };
5335
+ }
5336
+ return null;
5337
+ }
5338
+
5339
+ function resolveIdRefTargets(idRefs, ctx) {
5340
+ const targets = [];
5341
+ for (const expr of idRefs ?? []) {
5342
+ const target = resolveIdRefTarget(expr, ctx);
5343
+ if (target === null) return null;
5344
+ targets.push(target);
5345
+ }
5346
+ return targets.length === 0 ? null : targets;
5347
+ }
5348
+
5349
+ function assertSingleResource(targets) {
5350
+ const resource = invariants.resourceFromParsed(targets[0].parsed);
5351
+ for (const g of targets) {
5352
+ const r = invariants.resourceFromParsed(g.parsed);
5353
+ if (r.type !== resource.type || r.id !== resource.id) throw new Error(`Guard targets span multiple resources (${resource.type}:${resource.id} vs ${r.type}:${r.id}); a guard is single-resource.`);
5354
+ }
5355
+ return resource;
5356
+ }
5357
+
5358
+ function bareIdRefs(targets) {
5359
+ return targets.flatMap(g => [ g.parsed.documentId, `drafts.${g.parsed.documentId}` ]);
5360
+ }
5361
+
5362
+ function resolveMatchTypes(targets, authorTypes) {
5363
+ if (authorTypes !== void 0) return authorTypes;
5364
+ const inferred = [ ...new Set(targets.map(g => g.type).filter(t => !!t)) ];
5365
+ return inferred.length > 0 ? inferred : void 0;
5366
+ }
5367
+
5368
+ function resolveMetadata(metadata, ctx) {
5369
+ const out = {};
5370
+ for (const [k, expr] of Object.entries(metadata ?? {})) out[k] = resolveGuardRead({
5371
+ expr: expr,
5372
+ ctx: ctx,
5373
+ deref: !0
5374
+ });
5375
+ return out;
5376
+ }
5377
+
5378
+ function isRecord(value) {
5379
+ return typeof value == "object" && value !== null && !Array.isArray(value);
5380
+ }
5381
+
5382
+ function isClientProjectUser(value) {
5383
+ return isRecord(value) && typeof value.id == "string" && (value.sanityUserId === void 0 || typeof value.sanityUserId == "string") && (value.displayName === void 0 || typeof value.displayName == "string") && (value.email === void 0 || typeof value.email == "string") && (value.imageUrl === void 0 || value.imageUrl === null || typeof value.imageUrl == "string");
5384
+ }
5385
+
5386
+ function objectProperty(value, property) {
5387
+ if (!isRecord(value)) return;
5388
+ const propertyValue = value[property];
5389
+ return typeof propertyValue == "object" && propertyValue !== null ? propertyValue : void 0;
5390
+ }
5391
+
5392
+ function stringProperty(value, property) {
5393
+ const propertyValue = Reflect.get(value, property);
5394
+ return typeof propertyValue == "string" ? propertyValue : void 0;
5395
+ }
5396
+
5397
+ function apiErrorType(error) {
5398
+ const response = objectProperty(error, "response"), body = objectProperty(response, "body");
5399
+ if (!body) return;
5400
+ const nestedError = objectProperty(body, "error");
5401
+ return (nestedError ? stringProperty(nestedError, "type") : void 0) ?? stringProperty(body, "type");
5402
+ }
5403
+
5404
+ function isProjectUserNotFoundError(error) {
5405
+ return apiErrorType(error) === "projectUserNotFoundError";
5406
+ }
5407
+
5408
+ const memberJoinCache = /* @__PURE__ */ new WeakMap;
5409
+
5410
+ function joinCacheFor(client) {
5411
+ let cache = memberJoinCache.get(client);
5412
+ return cache === void 0 && (cache = /* @__PURE__ */ new Map, memberJoinCache.set(client, cache)),
5413
+ cache;
5414
+ }
5415
+
5416
+ async function projectMemberIds(request, projectId) {
5417
+ const project = await request({
5418
+ uri: `/projects/${encodeURIComponent(projectId)}`
5419
+ }), members = isRecord(project) ? project.members : void 0;
5420
+ return Array.isArray(members) ? members.map(member => isRecord(member) ? member.id : void 0).filter(id => typeof id == "string") : [];
5421
+ }
5422
+
5423
+ async function resolveGlobalProjectUser(args) {
5424
+ const {client: client, request: request, projectId: projectId, id: id} = args, cache = joinCacheFor(client), key = `${projectId}:${id}`, hit = cache.get(key);
5425
+ if (hit !== void 0) return hit === null ? {
5426
+ status: "missing"
5427
+ } : {
5428
+ status: "resolved",
5429
+ user: hit
5430
+ };
5431
+ try {
5432
+ await ingestMemberJoin({
5433
+ request: request,
5434
+ projectId: projectId,
5435
+ cache: cache
5436
+ });
5437
+ const found = cache.get(key);
5438
+ return found != null ? {
5439
+ status: "resolved",
5440
+ user: found
5441
+ } : (cache.set(key, null), {
5442
+ status: "missing"
5443
+ });
5444
+ } catch (cause) {
5445
+ return {
5446
+ status: "inaccessible",
5447
+ cause: cause
5448
+ };
5449
+ }
5450
+ }
5451
+
5452
+ async function ingestMemberJoin(args) {
5453
+ const {request: request, projectId: projectId, cache: cache} = args, memberIds = await projectMemberIds(request, projectId);
5454
+ if (memberIds.length === 0) return;
5455
+ const response = await request({
5456
+ uri: `/projects/${encodeURIComponent(projectId)}/users/${memberIds.map(encodeURIComponent).join(",")}`
5457
+ });
5458
+ for (const row of Array.isArray(response) ? response : [ response ]) isClientProjectUser(row) && typeof row.sanityUserId == "string" && cache.set(`${projectId}:${row.sanityUserId}`, row);
5459
+ }
5460
+
5461
+ function clientProjectUserDirectory(client, projectId) {
5462
+ return {
5463
+ findById: async id => {
5464
+ if (!client.request) return {
5465
+ status: "inaccessible",
5466
+ cause: new Error("Project-user resolution requires WorkflowClient.request")
5467
+ };
5468
+ if (invariants.classifyPrincipalId(id).namespace === "global") return resolveGlobalProjectUser({
5469
+ client: client,
5470
+ request: client.request,
5471
+ projectId: projectId,
5472
+ id: id
5473
+ });
5474
+ try {
5475
+ const response = await client.request({
5476
+ uri: `/projects/${encodeURIComponent(projectId)}/users/${encodeURIComponent(id)}`
5477
+ }), candidate = Array.isArray(response) ? response[0] : response;
5478
+ return candidate == null ? {
5479
+ status: "missing"
5480
+ } : isClientProjectUser(candidate) ? {
5481
+ status: "resolved",
5482
+ user: candidate
5483
+ } : {
5484
+ status: "inaccessible",
5485
+ cause: new Error("Project-user response had an invalid shape")
5486
+ };
5487
+ } catch (cause) {
5488
+ return isProjectUserNotFoundError(cause) ? {
5489
+ status: "missing"
5490
+ } : {
5491
+ status: "inaccessible",
5492
+ cause: cause
5493
+ };
5494
+ }
5495
+ }
5496
+ };
5497
+ }
5498
+
5499
+ function resolveClientActor(client, args) {
5500
+ return resolveActor(clientProjectUserDirectory(client, args.projectId), args.actor);
5501
+ }
5502
+
5503
+ async function resolveActor(directory, actor) {
5504
+ if (actor.kind !== "person") return {
5505
+ status: "not-person",
5506
+ actor: actor
5507
+ };
5508
+ const personActor = {
5509
+ ...actor,
5510
+ kind: "person"
5511
+ }, lookup = await directory.findById(personActor.id);
5512
+ return lookup.status === "resolved" ? {
5513
+ status: "resolved",
5514
+ actor: personActor,
5515
+ user: lookup.user
5516
+ } : lookup.status === "inaccessible" ? {
5517
+ status: "inaccessible",
5518
+ actor: personActor,
5519
+ ...lookup.cause === void 0 ? {} : {
5520
+ cause: lookup.cause
5521
+ }
5522
+ } : {
5523
+ status: "missing",
5524
+ actor: personActor
5525
+ };
5526
+ }
5527
+
5528
+ const IDENTITY_KINDS = /* @__PURE__ */ new Set([ "actor", "assignee", "assignees" ]);
5529
+
5530
+ async function localizeGuardMetadata(args) {
5531
+ const {doc: doc, guard: guard, client: client, instance: instance, definition: definition} = args;
5532
+ if (doc.resourceType !== "dataset" || client.request === void 0) return doc;
5533
+ const request = client.request, {projectId: projectId} = invariants.datasetResourceParts(doc.resourceId), shapes = metadataShapes({
5534
+ guard: guard,
5535
+ instance: instance,
5536
+ definition: definition
5537
+ }), globals = collectMetadataGlobals({
5538
+ metadata: doc.metadata,
5539
+ shapes: shapes
5540
+ });
5541
+ if (globals.size === 0) return doc;
5542
+ const map = /* @__PURE__ */ new Map;
5543
+ for (const id of globals) {
5544
+ const lookup = await resolveGlobalProjectUser({
5545
+ client: client,
5546
+ request: request,
5547
+ projectId: projectId,
5548
+ id: id
5549
+ });
5550
+ lookup.status === "resolved" && map.set(id, lookup.user.id);
5551
+ }
5552
+ return map.size === 0 ? doc : {
5553
+ ...doc,
5554
+ metadata: rewriteMetadata({
5555
+ metadata: doc.metadata,
5556
+ shapes: shapes,
5557
+ map: map
5558
+ })
5559
+ };
5560
+ }
5561
+
5562
+ function metadataShapes(args) {
5563
+ const out = /* @__PURE__ */ new Map;
5564
+ for (const [key, expr] of Object.entries(args.guard.metadata ?? {})) {
5565
+ const shape = shapeOfRead({
5566
+ expr: expr,
5567
+ instance: args.instance,
5568
+ definition: args.definition
5569
+ });
5570
+ shape !== void 0 && out.set(key, shape);
5571
+ }
5572
+ return out;
4878
5573
  }
4879
5574
 
4880
- function resolveIdRefTarget(expr, ctx) {
4881
- const value = resolveGuardRead({
4882
- expr: expr,
4883
- ctx: ctx,
4884
- deref: !1
4885
- });
4886
- if (typeof value == "string" && invariants.isGdrUri(value)) return {
4887
- parsed: invariants.parseGdr(value)
4888
- };
4889
- if (value && typeof value == "object") {
4890
- const v2 = value;
4891
- if (typeof v2.id == "string" && invariants.isGdrUri(v2.id)) return typeof v2.type == "string" ? {
4892
- parsed: invariants.parseGdr(v2.id),
4893
- type: v2.type
4894
- } : {
4895
- parsed: invariants.parseGdr(v2.id)
4896
- };
4897
- }
4898
- return null;
5575
+ function shapeOfRead(args) {
5576
+ const fieldRead = invariants.FIELD_READ.exec(args.expr);
5577
+ if (fieldRead !== null) return shapeOfFieldRead(args.instance, fieldRead);
5578
+ const effectsRead = invariants.EFFECTS_READ.exec(args.expr);
5579
+ if (effectsRead !== null) return shapeOfEffectsRead(args.definition, effectsRead);
4899
5580
  }
4900
5581
 
4901
- function resolveIdRefTargets(idRefs, ctx) {
4902
- const targets = [];
4903
- for (const expr of idRefs ?? []) {
4904
- const target = resolveIdRefTarget(expr, ctx);
4905
- if (target === null) return null;
4906
- targets.push(target);
4907
- }
4908
- return targets.length === 0 ? null : targets;
5582
+ function shapeOfFieldRead(instance, fieldRead) {
5583
+ const entry = (instance.fields ?? []).find(s => s.name === fieldRead[1]);
5584
+ if (entry !== void 0) return narrowByPath({
5585
+ type: entry._type,
5586
+ fields: Reflect.get(entry, "fields"),
5587
+ of: Reflect.get(entry, "of")
5588
+ }, fieldRead[2]);
4909
5589
  }
4910
5590
 
4911
- function assertSingleResource(targets) {
4912
- const resource = invariants.resourceFromParsed(targets[0].parsed);
4913
- for (const g of targets) {
4914
- const r = invariants.resourceFromParsed(g.parsed);
4915
- if (r.type !== resource.type || r.id !== resource.id) throw new Error(`Guard targets span multiple resources (${resource.type}:${resource.id} vs ${r.type}:${r.id}); a guard is single-resource.`);
4916
- }
4917
- return resource;
5591
+ function shapeOfEffectsRead(definition, effectsRead) {
5592
+ const outputs = findEffect(definition, effectsRead[1])?.outputs ?? [], path = effectsRead[2];
5593
+ if (path === void 0) return;
5594
+ const [head, ...rest] = path.split("."), output = outputs.find(shape => shape.name === head);
5595
+ if (output !== void 0) return narrowByPath({
5596
+ type: output.type,
5597
+ fields: output.fields,
5598
+ of: output.of
5599
+ }, rest.length > 0 ? rest.join(".") : void 0);
4918
5600
  }
4919
5601
 
4920
- function bareIdRefs(targets) {
4921
- return targets.flatMap(g => [ g.parsed.documentId, `drafts.${g.parsed.documentId}` ]);
5602
+ function narrowByPath(shape, path) {
5603
+ if (path === void 0) return shape;
5604
+ if (typeof shape.type != "string" || !IDENTITY_KINDS.has(shape.type)) return;
5605
+ const steps = identityPathSteps(shape.type, path);
5606
+ if (steps === void 0) return;
5607
+ const itemType = shape.type === "assignees" ? "assignee" : shape.type;
5608
+ if (steps.length === 0) return {
5609
+ type: itemType
5610
+ };
5611
+ if (steps.length === 1 && steps[0] === "id") return {
5612
+ type: itemType,
5613
+ idLeaf: !0
5614
+ };
4922
5615
  }
4923
5616
 
4924
- function resolveMatchTypes(targets, authorTypes) {
4925
- if (authorTypes !== void 0) return authorTypes;
4926
- const inferred = [ ...new Set(targets.map(g => g.type).filter(t => !!t)) ];
4927
- return inferred.length > 0 ? inferred : void 0;
5617
+ function identityPathSteps(kind, path) {
5618
+ const segments = path.split(".");
5619
+ return kind !== "assignees" ? segments : /^\d+$/.test(segments[0] ?? "") ? segments.slice(1) : void 0;
4928
5620
  }
4929
5621
 
4930
- function resolveMetadata(metadata, ctx) {
4931
- const out = {};
4932
- for (const [k, expr] of Object.entries(metadata ?? {})) out[k] = resolveGuardRead({
4933
- expr: expr,
4934
- ctx: ctx,
4935
- deref: !0
4936
- });
5622
+ function collectMetadataGlobals(args) {
5623
+ const found = /* @__PURE__ */ new Set;
5624
+ for (const [key, shape] of args.shapes) {
5625
+ const value = args.metadata[key];
5626
+ if (shape.idLeaf === !0) {
5627
+ typeof value == "string" && invariants.classifyPrincipalId(value).namespace === "global" && found.add(value);
5628
+ continue;
5629
+ }
5630
+ for (const id of collectDeclaredGlobalIds({
5631
+ ...shape,
5632
+ value: value
5633
+ })) found.add(id);
5634
+ }
5635
+ return found;
5636
+ }
5637
+
5638
+ function rewriteMetadata(args) {
5639
+ const out = {
5640
+ ...args.metadata
5641
+ };
5642
+ for (const [key, shape] of args.shapes) {
5643
+ const value = out[key];
5644
+ if (shape.idLeaf === !0) {
5645
+ typeof value == "string" && (out[key] = args.map.get(value) ?? value);
5646
+ continue;
5647
+ }
5648
+ out[key] = rewriteDeclaredPrincipalIds({
5649
+ ...shape,
5650
+ value: value,
5651
+ map: args.map
5652
+ });
5653
+ }
4937
5654
  return out;
4938
5655
  }
4939
5656
 
@@ -4969,189 +5686,6 @@ function parseGuardDocument(doc) {
4969
5686
  });
4970
5687
  }
4971
5688
 
4972
- const REQUEST_TAG = {
4973
- engine: "workflow",
4974
- deploy: "workflow.deploy",
4975
- deleteDefinition: "workflow.delete-definition",
4976
- start: "workflow.start",
4977
- fireAction: "workflow.fire-action",
4978
- editField: "workflow.edit-field",
4979
- completeEffect: "workflow.complete-effect",
4980
- commitEffectOps: "workflow.commit-effect-ops",
4981
- tick: "workflow.tick",
4982
- evaluate: "workflow.evaluate",
4983
- evaluateStart: "workflow.evaluate-start",
4984
- diagnose: "workflow.diagnose",
4985
- availableActions: "workflow.available-actions",
4986
- setStage: "workflow.set-stage",
4987
- abort: "workflow.abort",
4988
- getInstance: "workflow.get-instance",
4989
- children: "workflow.children",
4990
- instancesForDocument: "workflow.instances-for-document",
4991
- definitionsForDocument: "workflow.definitions-for-document",
4992
- query: "workflow.query",
4993
- discover: "workflow.discover",
4994
- guardQuery: "workflow.guard.query",
4995
- guardDeploy: "workflow.guard.deploy",
4996
- guardRefresh: "workflow.guard.refresh",
4997
- guardRetract: "workflow.guard.retract",
4998
- effectList: "workflow.effect.list",
4999
- effectFind: "workflow.effect.find",
5000
- drain: "workflow.drain",
5001
- effect: "workflow.effect",
5002
- verifyDefinitions: "workflow.verify-definitions",
5003
- accessResolveActor: "workflow.access.resolve-actor",
5004
- accessGrants: "workflow.access.grants"
5005
- }, RAW_PATCH = /* @__PURE__ */ Symbol("workflow-engine.raw-patch");
5006
-
5007
- function unwrapPatch(patch) {
5008
- return typeof patch == "object" && patch !== null && RAW_PATCH in patch ? patch[RAW_PATCH] : patch;
5009
- }
5010
-
5011
- const wrapperCache = /* @__PURE__ */ new WeakMap, effectHandlerClientCache = /* @__PURE__ */ new WeakMap, RAW_CLIENT = /* @__PURE__ */ Symbol("workflow-engine.raw-client");
5012
-
5013
- function unwrapRequestTag(client) {
5014
- let current = client;
5015
- for (;RAW_CLIENT in current; ) current = current[RAW_CLIENT];
5016
- return current;
5017
- }
5018
-
5019
- function withRequestTag(client, fallback) {
5020
- let byTag = wrapperCache.get(client);
5021
- byTag === void 0 && (byTag = /* @__PURE__ */ new Map, wrapperCache.set(client, byTag));
5022
- const cached = byTag.get(fallback);
5023
- if (cached !== void 0) return cached;
5024
- const wrapped = buildTaggedClient(client, fallback);
5025
- return byTag.set(fallback, wrapped), wrapped;
5026
- }
5027
-
5028
- function effectHandlerClient(client) {
5029
- const cached = effectHandlerClientCache.get(client);
5030
- if (cached !== void 0) return cached;
5031
- let tagged;
5032
- if (client.withConfig === void 0) tagged = withRequestTag(client, REQUEST_TAG.effect); else {
5033
- const prefix = clientRequestTagPrefix(client), effectTag = composeRequestTag(prefix, REQUEST_TAG.effect);
5034
- tagged = client.withConfig({
5035
- requestTagPrefix: effectTag
5036
- });
5037
- }
5038
- return effectHandlerClientCache.set(client, tagged), tagged;
5039
- }
5040
-
5041
- function effectHandlerResolver(resolver) {
5042
- return mapResourceClientResolver(resolver, effectHandlerClient);
5043
- }
5044
-
5045
- function mapResourceClientResolver(resolver, mapClient) {
5046
- if (resolver !== void 0) return parsed => {
5047
- const client = resolver(parsed);
5048
- return client === void 0 ? void 0 : mapClient(client);
5049
- };
5050
- }
5051
-
5052
- function isWorkflowsFamilyPrefix(prefix) {
5053
- return prefix === void 0 ? !1 : prefix === "sanity.workflows" || prefix.startsWith("sanity.workflows.") || prefix === "sanity.workflows-mcp";
5054
- }
5055
-
5056
- function clientRequestTagPrefix(client) {
5057
- const probe = client;
5058
- return typeof probe.config == "function" ? probe.config().requestTagPrefix : void 0;
5059
- }
5060
-
5061
- function composeRequestTag(prefix, tag) {
5062
- if (prefix === void 0) return tag;
5063
- const relative = isWorkflowsFamilyPrefix(prefix) ? stripWorkflowRoot(tag) : tag;
5064
- return `${prefix}.${relative}`;
5065
- }
5066
-
5067
- function stripWorkflowRoot(tag) {
5068
- return tag.startsWith("workflow.") ? tag.slice(9) : tag;
5069
- }
5070
-
5071
- function buildTaggedClient(client, fallback) {
5072
- const strip = isWorkflowsFamilyPrefix(clientRequestTagPrefix(unwrapRequestTag(client))), normalize = tag => strip ? stripWorkflowRoot(tag) : tag, stamp = options => options === void 0 ? {
5073
- tag: normalize(fallback)
5074
- } : options.tag === void 0 ? {
5075
- ...options,
5076
- tag: normalize(fallback)
5077
- } : typeof options.tag == "string" && options.tag !== normalize(options.tag) ? {
5078
- ...options,
5079
- tag: normalize(options.tag)
5080
- } : options, wrapPatch = patch => {
5081
- let target = patch;
5082
- const wrapped = {
5083
- get [RAW_PATCH]() {
5084
- return target;
5085
- },
5086
- set: props => (target = target.set(props), wrapped),
5087
- setIfMissing: props => (target = target.setIfMissing(props), wrapped),
5088
- unset: paths => (target = target.unset(paths), wrapped),
5089
- ifRevisionId: rev => (target = target.ifRevisionId(rev), wrapped),
5090
- commit: options => target.commit(stamp(options))
5091
- };
5092
- return wrapped;
5093
- }, wrapTransaction = tx => {
5094
- let target = tx;
5095
- const wrapped = {
5096
- create: doc => (target = target.create(doc), wrapped),
5097
- patch: patch => (target = target.patch(unwrapPatch(patch)), wrapped),
5098
- delete: id => (target = target.delete(id), wrapped),
5099
- commit: options => target.commit(stamp(options))
5100
- };
5101
- return wrapped;
5102
- }, overrides = {
5103
- [RAW_CLIENT]: unwrapRequestTag(client),
5104
- fetch: (query, params, options) => client.fetch(query, params, stamp(options)),
5105
- getDocument: (id, options) => client.getDocument(id, stamp(options)),
5106
- patch: documentId => wrapPatch(client.patch(documentId)),
5107
- create: (doc, options) => client.create(doc, stamp(options)),
5108
- transaction: () => wrapTransaction(client.transaction()),
5109
- ...client.withConfig !== void 0 ? {
5110
- withConfig: config => withRequestTag(client.withConfig(config), fallback)
5111
- } : {},
5112
- ...client.action !== void 0 ? {
5113
- action: (action, options) => client.action(action, stamp(options))
5114
- } : {},
5115
- ...client.request !== void 0 ? {
5116
- request: opts => client.request(stamp(opts))
5117
- } : {}
5118
- };
5119
- return new Proxy(client, {
5120
- has: (target, property) => Object.hasOwn(overrides, property) || property in target,
5121
- get: (target, property) => {
5122
- if (Object.hasOwn(overrides, property)) return Reflect.get(overrides, property, overrides);
5123
- const value = Reflect.get(target, property, target);
5124
- return typeof value == "function" ? value.bind(target) : value;
5125
- }
5126
- });
5127
- }
5128
-
5129
- const pinCache = /* @__PURE__ */ new WeakMap, enginePinned = /* @__PURE__ */ new WeakSet;
5130
-
5131
- function pinApiVersion(client) {
5132
- const raw = unwrapRequestTag(client);
5133
- if (enginePinned.has(raw) || raw.withConfig === void 0) return client;
5134
- let sibling = pinCache.get(raw);
5135
- return sibling === void 0 && (sibling = raw.withConfig({
5136
- apiVersion: ENGINE_API_VERSION
5137
- }), pinCache.set(raw, sibling), enginePinned.add(unwrapRequestTag(sibling))), sibling;
5138
- }
5139
-
5140
- function taggedResolver(resolver, fallback) {
5141
- return mapResourceClientResolver(resolver, client => withRequestTag(pinApiVersion(client), fallback));
5142
- }
5143
-
5144
- function taggedScope(args, tag) {
5145
- const resourceClients = taggedResolver(args.resourceClients, tag);
5146
- return {
5147
- ...args,
5148
- client: withRequestTag(pinApiVersion(args.client), tag),
5149
- ...resourceClients !== void 0 ? {
5150
- resourceClients: resourceClients
5151
- } : {}
5152
- };
5153
- }
5154
-
5155
5689
  async function fetchGuards(args) {
5156
5690
  return (await args.client.fetch(args.query, args.params, {
5157
5691
  tag: REQUEST_TAG.guardQuery
@@ -5365,7 +5899,8 @@ function resolvedStageGuards(args) {
5365
5899
  resolved !== null && out.push({
5366
5900
  client: args.clientForGdr(resolved.routeGdr),
5367
5901
  resourceKey: invariants.resourceGdr(invariants.resourceFromParsed(resolved.routeGdr)),
5368
- value: resolved.doc
5902
+ value: resolved.doc,
5903
+ guard: guard
5369
5904
  });
5370
5905
  }
5371
5906
  return out;
@@ -5439,11 +5974,18 @@ async function deployStageGuards(args) {
5439
5974
  if (live === void 0 || live.currentStage !== args.stageName || live.abortedAt !== void 0) return;
5440
5975
  const routed = resolvedStageGuards(args), existingByResource = await existingGuardIds(groupByResource(routed));
5441
5976
  let deployed = 0;
5442
- for (const {client: client, resourceKey: resourceKey, value: doc} of routed) {
5977
+ for (const {client: client, resourceKey: resourceKey, value: doc, guard: guard} of routed) {
5443
5978
  try {
5979
+ const localized = await localizeGuardMetadata({
5980
+ doc: doc,
5981
+ guard: guard,
5982
+ client: client,
5983
+ instance: args.instance,
5984
+ definition: args.definition
5985
+ });
5444
5986
  await upsertGuard({
5445
5987
  client: client,
5446
- doc: doc,
5988
+ doc: localized,
5447
5989
  exists: existingByResource.get(resourceKey)?.has(doc._id) ?? !1
5448
5990
  });
5449
5991
  } catch (cause) {
@@ -5563,7 +6105,8 @@ async function commitAbort({ctx: ctx, reason: reason, requestRecord: requestReco
5563
6105
  ...actor !== void 0 ? {
5564
6106
  actor: actor
5565
6107
  } : {}
5566
- }), mutation.completedAt = at, mutation.abortedAt = at, await persist(ctx, mutation),
6108
+ }), mutation.completedAt = at, mutation.abortedAt = at;
6109
+ const instance = readInstanceDoc(await persist(ctx, mutation));
5567
6110
  await retractStageGuards({
5568
6111
  client: ctx.client,
5569
6112
  clientForGdr: ctx.clientForGdr,
@@ -5583,7 +6126,8 @@ async function commitAbort({ctx: ctx, reason: reason, requestRecord: requestReco
5583
6126
  });
5584
6127
  return {
5585
6128
  fired: !0,
5586
- stage: stage.name
6129
+ stage: stage.name,
6130
+ instance: instance
5587
6131
  };
5588
6132
  }
5589
6133
 
@@ -6335,18 +6879,42 @@ async function fetchGrants(args) {
6335
6879
  });
6336
6880
  }
6337
6881
 
6338
- async function advisoryCan({instance: instance, actor: actor, grants: grants}) {
6882
+ async function advisoryCanForCall(args) {
6883
+ const actor = args.options?.actor;
6884
+ if (!(args.options?.grants === void 0 || actor === void 0)) return advisoryCan({
6885
+ instance: args.instance,
6886
+ identity: invariants.lakePrincipalId({
6887
+ actor: actor,
6888
+ localPrincipalId: args.options.localPrincipalId
6889
+ }),
6890
+ grants: args.options.grants
6891
+ });
6892
+ }
6893
+
6894
+ async function advisoryCan({instance: instance, identity: identity, grants: grants}) {
6339
6895
  if (grants === void 0) return;
6340
6896
  const can = {};
6341
6897
  for (const permission of invariants.DOCUMENT_VALUE_PERMISSIONS) can[permission] = await grantsPermissionOn({
6342
6898
  document: instance,
6343
6899
  grants: grants,
6344
6900
  permission: permission,
6345
- userId: actor.id
6901
+ userId: identity
6346
6902
  });
6347
6903
  return can;
6348
6904
  }
6349
6905
 
6906
+ function requirementDescriptor(requirement) {
6907
+ return {
6908
+ name: requirement.name,
6909
+ ...requirement.title !== void 0 ? {
6910
+ title: requirement.title
6911
+ } : {},
6912
+ ...requirement.description !== void 0 ? {
6913
+ description: requirement.description
6914
+ } : {}
6915
+ };
6916
+ }
6917
+
6350
6918
  function subjectDenialLabels(denied) {
6351
6919
  return denied.map(d => `${d.permission} on ${d.subject} (${d.resource})`);
6352
6920
  }
@@ -6367,10 +6935,10 @@ class ActionDisabledError extends invariants.WorkflowError {
6367
6935
 
6368
6936
  class StartNotAllowedError extends invariants.WorkflowError {
6369
6937
  definition;
6370
- insight;
6938
+ unmetRequirements;
6371
6939
  constructor(args) {
6372
- super("start-not-allowed", `startInstance refused: start.allowed on definition "${args.definition}" evaluated ` + (args.insight.outcome === "unevaluable" ? `GROQ null ("can't decide" — fail-closed)` : "false") + " for the supplied initialFields. Pre-flight the verdict with evaluateStart."),
6373
- this.name = "StartNotAllowedError", this.definition = args.definition, this.insight = args.insight;
6940
+ super("start-not-allowed", `startInstance refused definition "${args.definition}": ${args.unmetRequirements.map(requirement => requirement.title ?? requirement.name).join(", ")}. Pre-flight the verdict with evaluateStart.`),
6941
+ this.name = "StartNotAllowedError", this.definition = args.definition, this.unmetRequirements = args.unmetRequirements;
6374
6942
  }
6375
6943
  }
6376
6944
 
@@ -6386,7 +6954,7 @@ const disabledReasonDetail = {
6386
6954
  "stage-terminal": r => `stage "${r.stage}" is terminal`,
6387
6955
  "instance-completed": r => `instance completed at ${r.completedAt}`,
6388
6956
  "instance-aborted": r => `instance aborted at ${r.abortedAt}`,
6389
- "requirements-unmet": r => `unmet requirement(s): ${r.unmetRequirements.join(", ")}`,
6957
+ "requirements-unmet": r => `unmet requirement(s): ${r.unmetRequirements.map(requirement => requirement.name).join(", ")}`,
6390
6958
  "subject-permission-denied": r => `missing subject permission(s): ${subjectDenialLabels(r.denied).join(", ")}`
6391
6959
  };
6392
6960
 
@@ -6455,11 +7023,10 @@ async function resolveActionCommit({ctx: ctx, activityName: activityName, action
6455
7023
  }
6456
7024
  });
6457
7025
  if (action.filter !== void 0) {
6458
- const can = options?.grants !== void 0 && actor !== void 0 ? await advisoryCan({
7026
+ const can = await advisoryCanForCall({
6459
7027
  instance: ctx.instance,
6460
- actor: actor,
6461
- grants: options.grants
6462
- }) : void 0;
7028
+ options: options
7029
+ });
6463
7030
  if (!await ctxEvaluateCondition({
6464
7031
  ctx: ctx,
6465
7032
  condition: action.filter,
@@ -6712,30 +7279,12 @@ async function fireTriggeredAction({ctx: ctx, mutation: mutation, activity: acti
6712
7279
  };
6713
7280
  }
6714
7281
 
6715
- async function primeInitialStage({client: client, instanceId: instanceId, actor: actor, clientForGdr: clientForGdr, refSurface: refSurface, clock: clock, executionContext: executionContext, telemetry: telemetry}) {
6716
- const instance = await getInstanceDocument(client, instanceId);
7282
+ async function primeInitialStage(args) {
7283
+ const {client: client, instanceId: instanceId, refSurface: refSurface, clientForGdr: clientForGdr} = args, instance = await getInstanceDocument(client, instanceId);
6717
7284
  if (!instance || instance.stages.length > 0) return;
6718
- const definition = invariants.parseDefinitionSnapshot(instance), stage = definition.stages.find(s => s.name === instance.currentStage);
7285
+ const ctx = await buildCascadeStepContext(args, instance), {definition: definition} = ctx, stage = definition.stages.find(s => s.name === instance.currentStage);
6719
7286
  if (stage === void 0) return;
6720
- const ctx = await buildEngineContext({
6721
- client: client,
6722
- clientForGdr: clientForGdr,
6723
- refSurface: refSurface,
6724
- instance: instance,
6725
- definition: definition,
6726
- ...clock ? {
6727
- clock: clock
6728
- } : {},
6729
- ...actor ? {
6730
- actor: actor
6731
- } : {},
6732
- ...executionContext ? {
6733
- executionContext: executionContext
6734
- } : {},
6735
- ...telemetry ? {
6736
- telemetry: telemetry
6737
- } : {}
6738
- }), now = ctx.now, discards = [], initialStageEntry = {
7287
+ const now = ctx.now, discards = [], initialStageEntry = {
6739
7288
  _key: randomKey(),
6740
7289
  name: stage.name,
6741
7290
  enteredAt: now,
@@ -6804,29 +7353,37 @@ async function primeInitialStage({client: client, instanceId: instanceId, actor:
6804
7353
 
6805
7354
  const CASCADE_LIMIT = 100;
6806
7355
 
6807
- async function runCascadeHop({client: client, instanceId: instanceId, actor: actor, clientForGdr: clientForGdr, refSurface: refSurface, clock: clock, executionContext: executionContext, telemetry: telemetry, overlay: overlay}) {
6808
- const ctx = await loadContext({
7356
+ async function runCascadeHop({client: client, instanceId: instanceId, actor: actor, clientForGdr: clientForGdr, refSurface: refSurface, clock: clock, executionContext: executionContext, telemetry: telemetry, overlay: overlay, settlingCohorts: settlingCohorts, instance: instance}) {
7357
+ const contextOptions = {
7358
+ clientForGdr: clientForGdr,
7359
+ refSurface: refSurface,
7360
+ ...actor ? {
7361
+ actor: actor
7362
+ } : {},
7363
+ ...clock ? {
7364
+ clock: clock
7365
+ } : {},
7366
+ ...executionContext ? {
7367
+ executionContext: executionContext
7368
+ } : {},
7369
+ ...telemetry ? {
7370
+ telemetry: telemetry
7371
+ } : {},
7372
+ ...overlay ? {
7373
+ overlay: overlay
7374
+ } : {},
7375
+ ...settlingCohorts ? {
7376
+ settlingCohorts: settlingCohorts
7377
+ } : {}
7378
+ }, ctx = instance === void 0 ? await loadContext({
6809
7379
  client: client,
6810
7380
  instanceId: instanceId,
6811
- options: {
6812
- clientForGdr: clientForGdr,
6813
- refSurface: refSurface,
6814
- ...actor ? {
6815
- actor: actor
6816
- } : {},
6817
- ...clock ? {
6818
- clock: clock
6819
- } : {},
6820
- ...executionContext ? {
6821
- executionContext: executionContext
6822
- } : {},
6823
- ...telemetry ? {
6824
- telemetry: telemetry
6825
- } : {},
6826
- ...overlay ? {
6827
- overlay: overlay
6828
- } : {}
6829
- }
7381
+ options: contextOptions
7382
+ }) : await buildEngineContext({
7383
+ client: client,
7384
+ instance: instance,
7385
+ definition: invariants.parseDefinitionSnapshot(instance),
7386
+ ...contextOptions
6830
7387
  });
6831
7388
  if (isTerminal(ctx)) return {
6832
7389
  moved: !1
@@ -6856,10 +7413,10 @@ async function runCascadeHop({client: client, instanceId: instanceId, actor: act
6856
7413
  });
6857
7414
  }
6858
7415
 
6859
- async function cascadeAutoTransitions({client: client, instanceId: instanceId, actor: actor, clientForGdr: clientForGdr, refSurface: refSurface, clock: clock, executionContext: executionContext, telemetry: telemetry, overlay: overlay}) {
7416
+ async function cascadeAutoTransitions({client: client, instanceId: instanceId, actor: actor, clientForGdr: clientForGdr, refSurface: refSurface, clock: clock, executionContext: executionContext, telemetry: telemetry, overlay: overlay, settlingCohorts: settlingCohorts}) {
6860
7417
  let count = 0;
6861
7418
  for (;;) {
6862
- if (await drainCondemnedChildren({
7419
+ const drained = await drainCondemnedChildren({
6863
7420
  client: client,
6864
7421
  instanceId: instanceId,
6865
7422
  actor: actor,
@@ -6868,7 +7425,8 @@ async function cascadeAutoTransitions({client: client, instanceId: instanceId, a
6868
7425
  clock: clock,
6869
7426
  executionContext: executionContext,
6870
7427
  telemetry: telemetry
6871
- }), !(await runCascadeHop({
7428
+ });
7429
+ if (!(await runCascadeHop({
6872
7430
  client: client,
6873
7431
  instanceId: instanceId,
6874
7432
  actor: actor,
@@ -6877,7 +7435,11 @@ async function cascadeAutoTransitions({client: client, instanceId: instanceId, a
6877
7435
  clock: clock,
6878
7436
  executionContext: executionContext,
6879
7437
  telemetry: telemetry,
6880
- overlay: overlay
7438
+ overlay: overlay,
7439
+ settlingCohorts: settlingCohorts,
7440
+ ...drained.drained ? {} : {
7441
+ instance: drained.instance
7442
+ }
6881
7443
  })).moved) return count;
6882
7444
  if (count++, count >= CASCADE_LIMIT) throw new CascadeLimitError({
6883
7445
  instanceId: instanceId,
@@ -6886,39 +7448,50 @@ async function cascadeAutoTransitions({client: client, instanceId: instanceId, a
6886
7448
  }
6887
7449
  }
6888
7450
 
6889
- async function drainCondemnedChildren({client: client, instanceId: instanceId, actor: actor, clientForGdr: clientForGdr, refSurface: refSurface, clock: clock, executionContext: executionContext, telemetry: telemetry, draining: draining = /* @__PURE__ */ new Set}) {
6890
- if (draining.has(instanceId)) return;
7451
+ async function drainCondemnedChildren({client: client, instanceId: instanceId, actor: actor, clientForGdr: clientForGdr, refSurface: refSurface, clock: clock, executionContext: executionContext, telemetry: telemetry, draining: draining = /* @__PURE__ */ new Set, instance: preloadedInstance}) {
7452
+ if (draining.has(instanceId)) return {
7453
+ instance: preloadedInstance,
7454
+ drained: !1
7455
+ };
6891
7456
  draining.add(instanceId);
6892
- const instance = await getInstanceDocument(client, instanceId);
6893
- if (!instance) return;
7457
+ const instance = preloadedInstance ?? await getInstanceDocument(client, instanceId);
7458
+ if (!instance) return {
7459
+ instance: void 0,
7460
+ drained: !1
7461
+ };
6894
7462
  const condemned = condemnedSubworkflows(instance);
6895
- if (condemned.length !== 0) {
6896
- for (const row of condemned) await settleCondemnedRow({
6897
- client: client,
6898
- ownerId: instanceId,
6899
- row: row,
6900
- actor: actor,
6901
- clientForGdr: clientForGdr,
6902
- refSurface: refSurface,
6903
- clock: clock,
6904
- executionContext: executionContext,
6905
- telemetry: telemetry,
6906
- draining: draining
6907
- });
6908
- await stampDrainedRows({
6909
- client: client,
6910
- instance: instance,
6911
- condemned: condemned,
6912
- clock: clock,
6913
- executionContext: executionContext
6914
- });
6915
- }
7463
+ if (condemned.length === 0) return {
7464
+ instance: instance,
7465
+ drained: !1
7466
+ };
7467
+ for (const row of condemned) await settleCondemnedRow({
7468
+ client: client,
7469
+ ownerId: instanceId,
7470
+ row: row,
7471
+ actor: actor,
7472
+ clientForGdr: clientForGdr,
7473
+ refSurface: refSurface,
7474
+ clock: clock,
7475
+ executionContext: executionContext,
7476
+ telemetry: telemetry,
7477
+ draining: draining
7478
+ });
7479
+ return await stampDrainedRows({
7480
+ client: client,
7481
+ instance: instance,
7482
+ condemned: condemned,
7483
+ clock: clock,
7484
+ executionContext: executionContext
7485
+ }), {
7486
+ instance: instance,
7487
+ drained: !0
7488
+ };
6916
7489
  }
6917
7490
 
6918
7491
  async function settleCondemnedRow({client: client, ownerId: ownerId, row: row, actor: actor, clientForGdr: clientForGdr, refSurface: refSurface, clock: clock, executionContext: executionContext, telemetry: telemetry, draining: draining}) {
6919
7492
  const childId = invariants.toBareId(row.ref.id);
6920
7493
  try {
6921
- await abortInstance({
7494
+ const result = await abortInstance({
6922
7495
  client: client,
6923
7496
  instanceId: childId,
6924
7497
  reason: row.abortPending?.reason ?? "condemned by parent",
@@ -6938,7 +7511,8 @@ async function settleCondemnedRow({client: client, ownerId: ownerId, row: row, a
6938
7511
  telemetry: telemetry
6939
7512
  } : {}
6940
7513
  }
6941
- }), await drainCondemnedChildren({
7514
+ });
7515
+ await drainCondemnedChildren({
6942
7516
  client: client,
6943
7517
  instanceId: childId,
6944
7518
  actor: actor,
@@ -6947,7 +7521,10 @@ async function settleCondemnedRow({client: client, ownerId: ownerId, row: row, a
6947
7521
  clock: clock,
6948
7522
  executionContext: executionContext,
6949
7523
  telemetry: telemetry,
6950
- draining: draining
7524
+ draining: draining,
7525
+ ...result.fired ? {
7526
+ instance: result.instance
7527
+ } : {}
6951
7528
  });
6952
7529
  } catch (cause) {
6953
7530
  if (cause instanceof invariants.InstanceNotFoundError) return;
@@ -6960,9 +7537,7 @@ async function settleCondemnedRow({client: client, ownerId: ownerId, row: row, a
6960
7537
  }
6961
7538
 
6962
7539
  async function stampDrainedRows({client: client, instance: instance, condemned: condemned, clock: clock, executionContext: executionContext}) {
6963
- const now = (clock ?? wallClock)(), stamp = resolveExecutionContext(executionContext), ids = condemned.map(row => invariants.toBareId(row.ref.id)), children = await client.fetch("*[_id in $ids]{_id, currentStage, completedAt, abortedAt, modelVersion, minReaderModel}", {
6964
- ids: ids
6965
- }), byId = new Map(children.map(c => [ invariants.assertReadableModel(c)._id, c ])), condemnedKeys = new Set(condemned.map(row => row._key)), history = [ ...instance.history ], subworkflows = (instance.subworkflows ?? []).map(row => {
7540
+ const now = (clock ?? wallClock)(), stamp = resolveExecutionContext(executionContext), ids = condemned.map(row => invariants.toBareId(row.ref.id)), byId = await loadInstancesById(client, ids), condemnedKeys = new Set(condemned.map(row => row._key)), history = [ ...instance.history ], subworkflows = (instance.subworkflows ?? []).map(row => {
6966
7541
  if (row.resolved !== void 0 || !condemnedKeys.has(row._key)) return row;
6967
7542
  const child = byId.get(invariants.toBareId(row.ref.id)), resolved = child !== void 0 ? terminalResolution(child) : {
6968
7543
  at: now,
@@ -6984,6 +7559,16 @@ async function stampDrainedRows({client: client, instance: instance, condemned:
6984
7559
  }).ifRevisionId(instance._rev).commit(SYNC_COMMIT);
6985
7560
  }
6986
7561
 
7562
+ async function loadInstancesById(client, ids) {
7563
+ const children = await client.fetch("*[_id in $ids]", {
7564
+ ids: ids
7565
+ });
7566
+ return new Map(children.filter(child => child._type === invariants.WORKFLOW_INSTANCE_TYPE).map(child => {
7567
+ const instance = readInstanceDoc(child);
7568
+ return [ instance._id, instance ];
7569
+ }));
7570
+ }
7571
+
6987
7572
  function terminalResolution(child) {
6988
7573
  const status = resolvedChildStatus(child);
6989
7574
  if (!(status === void 0 || child.completedAt === void 0 || child.completedAt === null)) return {
@@ -7006,28 +7591,18 @@ function subworkflowResolvedEntry({row: row, at: at, status: status}) {
7006
7591
  };
7007
7592
  }
7008
7593
 
7009
- async function propagateToAncestors({client: client, instanceId: instanceId, actor: actor, clientForGdr: clientForGdr, refSurface: refSurface, clock: clock, executionContext: executionContext, telemetry: telemetry}) {
7010
- const loaded = await loadPropagationPair(client, instanceId);
7011
- if (loaded === void 0) return;
7012
- const {child: child, parent: parent} = loaded, definition = invariants.parseDefinitionSnapshot(parent), ctx = await buildEngineContext({
7594
+ async function propagateToAncestors(args) {
7595
+ const {instance: instance, ...stepArgs} = args, {client: client, instanceId: instanceId} = stepArgs, loaded = await loadPropagationPair({
7013
7596
  client: client,
7014
- clientForGdr: clientForGdr,
7015
- refSurface: refSurface,
7016
- instance: parent,
7017
- definition: definition,
7018
- ...clock ? {
7019
- clock: clock
7020
- } : {},
7021
- ...actor ? {
7022
- actor: actor
7023
- } : {},
7024
- ...executionContext ? {
7025
- executionContext: executionContext
7026
- } : {},
7027
- ...telemetry ? {
7028
- telemetry: telemetry
7597
+ instanceId: instanceId,
7598
+ ...instance !== void 0 ? {
7599
+ instance: instance
7029
7600
  } : {}
7030
- }), mutation = startMutation(parent), row = mutation.subworkflows.find(r => invariants.toBareId(r.ref.id) === child._id);
7601
+ });
7602
+ if (loaded === void 0) return;
7603
+ const {child: child, parent: parent} = loaded;
7604
+ if (stepArgs.settlingCohorts?.has(parent._id)) return;
7605
+ const ctx = await buildCascadeStepContext(stepArgs, parent), mutation = startMutation(parent), row = mutation.subworkflows.find(r => invariants.toBareId(r.ref.id) === child._id);
7031
7606
  if (row === void 0) {
7032
7607
  await recordOrphanedPropagation({
7033
7608
  ctx: ctx,
@@ -7042,29 +7617,11 @@ async function propagateToAncestors({client: client, instanceId: instanceId, act
7042
7617
  child: child,
7043
7618
  now: ctx.now
7044
7619
  }), parentTerminal = parent.completedAt !== void 0;
7045
- changed && await persist(ctx, mutation), !parentTerminal && (await cascadeAutoTransitions({
7046
- client: client,
7047
- instanceId: parent._id,
7048
- actor: actor,
7049
- clientForGdr: clientForGdr,
7050
- refSurface: refSurface,
7051
- clock: clock,
7052
- executionContext: executionContext,
7053
- telemetry: telemetry
7054
- }), await propagateToAncestors({
7055
- client: client,
7056
- instanceId: parent._id,
7057
- actor: actor,
7058
- clientForGdr: clientForGdr,
7059
- refSurface: refSurface,
7060
- clock: clock,
7061
- executionContext: executionContext,
7062
- telemetry: telemetry
7063
- }));
7620
+ changed && await persist(ctx, mutation), !parentTerminal && await cascadeAndPropagateParent(stepArgs, parent);
7064
7621
  }
7065
7622
 
7066
- async function loadPropagationPair(client, instanceId) {
7067
- const child = await getInstanceDocument(client, instanceId);
7623
+ async function loadPropagationPair({client: client, instanceId: instanceId, instance: instance}) {
7624
+ const child = instance ?? await getInstanceDocument(client, instanceId);
7068
7625
  if (!child) return;
7069
7626
  const parentGdr = invariants.parentRef(child);
7070
7627
  if (parentGdr === void 0) return;
@@ -7075,6 +7632,83 @@ async function loadPropagationPair(client, instanceId) {
7075
7632
  };
7076
7633
  }
7077
7634
 
7635
+ async function propagateSpawnBatch(args) {
7636
+ const {childIds: childIds, ...stepArgs} = args, {client: client, instanceId: instanceId} = stepArgs, parent = await getInstanceDocument(client, instanceId);
7637
+ if (parent === void 0) return;
7638
+ const children = await loadInstancesById(client, childIds);
7639
+ if (children.size !== childIds.length) throw new Error(`Spawn batch for ${instanceId} could not reload every child`);
7640
+ const ctx = await buildCascadeStepContext(stepArgs, parent), mutation = startMutation(parent);
7641
+ stampSpawnBatch({
7642
+ mutation: mutation,
7643
+ parent: parent,
7644
+ children: children,
7645
+ childIds: childIds,
7646
+ now: ctx.now
7647
+ }) && await persist(ctx, mutation), parent.completedAt === void 0 && await cascadeAndPropagateParent(stepArgs, parent);
7648
+ }
7649
+
7650
+ async function buildCascadeStepContext(args, instance) {
7651
+ return buildEngineContext({
7652
+ client: args.client,
7653
+ clientForGdr: args.clientForGdr,
7654
+ refSurface: args.refSurface,
7655
+ instance: instance,
7656
+ definition: invariants.parseDefinitionSnapshot(instance),
7657
+ ...args.clock ? {
7658
+ clock: args.clock
7659
+ } : {},
7660
+ ...args.actor ? {
7661
+ actor: args.actor
7662
+ } : {},
7663
+ ...args.executionContext ? {
7664
+ executionContext: args.executionContext
7665
+ } : {},
7666
+ ...args.telemetry ? {
7667
+ telemetry: args.telemetry
7668
+ } : {},
7669
+ ...args.settlingCohorts ? {
7670
+ settlingCohorts: args.settlingCohorts
7671
+ } : {}
7672
+ });
7673
+ }
7674
+
7675
+ async function cascadeAndPropagateParent(args, parent) {
7676
+ await cascadeAutoTransitions({
7677
+ ...args,
7678
+ instanceId: parent._id
7679
+ }), await propagateToAncestors({
7680
+ ...args,
7681
+ instanceId: parent._id
7682
+ });
7683
+ }
7684
+
7685
+ function stampSpawnBatch({mutation: mutation, parent: parent, children: children, childIds: childIds, now: now}) {
7686
+ let changed = !1;
7687
+ for (const childId of childIds) {
7688
+ const child = requireSpawnBatchChild({
7689
+ parent: parent,
7690
+ children: children,
7691
+ childId: childId
7692
+ }), row = mutation.subworkflows.find(entry => invariants.toBareId(entry.ref.id) === childId);
7693
+ if (row === void 0) throw new Error(`Spawn batch child ${childId} has no registry row on parent ${parent._id}`);
7694
+ changed = stampResolvedChild({
7695
+ mutation: mutation,
7696
+ row: row,
7697
+ child: child,
7698
+ now: now
7699
+ }) || changed;
7700
+ }
7701
+ return changed;
7702
+ }
7703
+
7704
+ function requireSpawnBatchChild({parent: parent, children: children, childId: childId}) {
7705
+ const child = children.get(childId);
7706
+ if (child === void 0) throw new Error(`Spawn batch child ${childId} disappeared`);
7707
+ const expectedParent = invariants.parentRef(child);
7708
+ if (expectedParent === void 0 || invariants.toBareId(expectedParent.id) !== parent._id) throw new Error(`Spawn batch child ${childId} does not belong to parent ${parent._id}`);
7709
+ return child;
7710
+ }
7711
+
7078
7712
  function stampResolvedChild({mutation: mutation, row: row, child: child, now: now}) {
7079
7713
  if (row.resolved !== void 0) return !1;
7080
7714
  const resolved = terminalResolution(child);
@@ -7210,36 +7844,14 @@ async function persist(ctx, mutation) {
7210
7844
  for (const {body: body} of pendingCreates) tx.create(body);
7211
7845
  tx.patch(ctx.client.patch(ctx.instance._id).set(set).ifRevisionId(ctx.instance._rev)),
7212
7846
  await tx.commit(), mutation.pendingCreates = [];
7213
- const actorForPriming = ctx.actor;
7214
- for (const {body: body, started: started} of pendingCreates) try {
7215
- await primeInitialStage({
7216
- client: ctx.client,
7217
- instanceId: body._id,
7218
- actor: actorForPriming,
7219
- clientForGdr: ctx.clientForGdr,
7220
- refSurface: ctx.refSurface,
7221
- clock: ctx.clock,
7222
- executionContext: ctx.executionContext,
7223
- telemetry: ctx.telemetry
7224
- }), await cascadeAutoTransitions({
7225
- client: ctx.client,
7226
- instanceId: body._id,
7227
- actor: actorForPriming,
7228
- clientForGdr: ctx.clientForGdr,
7229
- refSurface: ctx.refSurface,
7230
- clock: ctx.clock,
7231
- executionContext: ctx.executionContext,
7232
- telemetry: ctx.telemetry
7233
- }), await propagateToAncestors({
7234
- client: ctx.client,
7847
+ const actorForPriming = ctx.actor, settlingCohorts = new Set(ctx.settlingCohorts).add(ctx.instance._id);
7848
+ for (const {body: body} of pendingCreates) try {
7849
+ const stepArgs = spawnStepArgs(ctx, {
7235
7850
  instanceId: body._id,
7236
7851
  actor: actorForPriming,
7237
- clientForGdr: ctx.clientForGdr,
7238
- refSurface: ctx.refSurface,
7239
- clock: ctx.clock,
7240
- executionContext: ctx.executionContext,
7241
- telemetry: ctx.telemetry
7242
- }), ctx.telemetry.log(WorkflowInstanceStarted, started);
7852
+ settlingCohorts: settlingCohorts
7853
+ });
7854
+ await primeInitialStage(stepArgs), await cascadeAutoTransitions(stepArgs);
7243
7855
  } catch (cause) {
7244
7856
  throw cause instanceof WorkflowStateDivergedError ? cause : new WorkflowStateDivergedError({
7245
7857
  instanceId: ctx.instance._id,
@@ -7247,11 +7859,50 @@ async function persist(ctx, mutation) {
7247
7859
  reason: `spawned child "${body._id}" failed to settle after the spawn transaction committed`
7248
7860
  });
7249
7861
  }
7862
+ await settleSpawnBatch(ctx, {
7863
+ pendingCreates: pendingCreates,
7864
+ actor: actorForPriming,
7865
+ settlingCohorts: settlingCohorts
7866
+ });
7867
+ for (const {started: started} of pendingCreates) ctx.telemetry.log(WorkflowInstanceStarted, started);
7250
7868
  const reloaded = await getInstanceDocument(ctx.client, ctx.instance._id);
7251
7869
  if (!reloaded) throw new Error(`Instance ${ctx.instance._id} disappeared after transaction commit`);
7252
7870
  return reloaded;
7253
7871
  }
7254
7872
 
7873
+ async function settleSpawnBatch(ctx, args) {
7874
+ try {
7875
+ await propagateSpawnBatch({
7876
+ ...spawnStepArgs(ctx, {
7877
+ instanceId: ctx.instance._id,
7878
+ actor: args.actor,
7879
+ settlingCohorts: args.settlingCohorts
7880
+ }),
7881
+ childIds: args.pendingCreates.map(({body: body}) => body._id)
7882
+ });
7883
+ } catch (cause) {
7884
+ throw cause instanceof WorkflowStateDivergedError ? cause : new WorkflowStateDivergedError({
7885
+ instanceId: ctx.instance._id,
7886
+ guardError: cause,
7887
+ reason: "spawned children failed to propagate after the spawn transaction committed"
7888
+ });
7889
+ }
7890
+ }
7891
+
7892
+ function spawnStepArgs(ctx, args) {
7893
+ return {
7894
+ client: ctx.client,
7895
+ instanceId: args.instanceId,
7896
+ actor: args.actor,
7897
+ clientForGdr: ctx.clientForGdr,
7898
+ refSurface: ctx.refSurface,
7899
+ clock: ctx.clock,
7900
+ executionContext: ctx.executionContext,
7901
+ telemetry: ctx.telemetry,
7902
+ settlingCohorts: args.settlingCohorts ?? ctx.settlingCohorts
7903
+ };
7904
+ }
7905
+
7255
7906
  function stampExecutionContext(ctx, mutation) {
7256
7907
  const stamp = ctx.executionContext, appended = mutation.history.slice(ctx.instance.history.length);
7257
7908
  mutation.history = [ ...mutation.history.slice(0, ctx.instance.history.length), ...stampHistoryEntries(appended, stamp) ];
@@ -7379,24 +8030,25 @@ function buildEffectSettlement(pending, outcome) {
7379
8030
  }
7380
8031
 
7381
8032
  function validateEffectOutputs(args) {
7382
- const {outputs: outputs, declared: declared, effectName: effectName} = args, byName = new Map(declared.map(shape => [ shape.name, shape ])), issues = [];
8033
+ const {outputs: outputs, declared: declared, effectName: effectName} = args, byName = new Map(declared.map(shape => [ shape.name, shape ])), issues = [], normalized = {};
7383
8034
  for (const [key, value] of Object.entries(outputs)) {
7384
8035
  const shape = byName.get(key);
7385
8036
  if (shape === void 0) {
7386
8037
  issues.push(`"${key}" is not a declared output`);
7387
8038
  continue;
7388
8039
  }
7389
- const shapeIssues = effectOutputIssues(shape, value);
7390
- shapeIssues !== void 0 && issues.push(...shapeIssues.map(i => `"${key}": ${i}`));
8040
+ const check = effectOutputCheck(shape, value);
8041
+ "issues" in check ? issues.push(...check.issues.map(i => `"${key}": ${i}`)) : normalized[key] = check.output;
7391
8042
  }
7392
8043
  if (issues.length > 0) throw new EffectOutputsInvalidError({
7393
8044
  effect: effectName,
7394
8045
  issues: issues
7395
8046
  });
8047
+ return normalized;
7396
8048
  }
7397
8049
 
7398
- function effectOutputIssues(shape, value) {
7399
- return invariants.checkFieldValue({
8050
+ function effectOutputCheck(shape, value) {
8051
+ return invariants.parseFieldValue({
7400
8052
  entryType: shape.type,
7401
8053
  value: value,
7402
8054
  ...shape.fields !== void 0 ? {
@@ -7442,15 +8094,15 @@ function validateCompletionInput({pending: pending, definition: definition, stat
7442
8094
  effect: pending.name,
7443
8095
  issues: [ "outputs cannot accompany a failed completion — report outputs on a done completion instead" ]
7444
8096
  });
7445
- if (outputs !== void 0) {
7446
- const declared = findEffect(definition, pending.name)?.outputs ?? [];
7447
- validateEffectOutputs({
7448
- outputs: outputs,
7449
- declared: declared,
7450
- effectName: pending.name
7451
- });
7452
- }
7453
- return ops !== void 0 ? validateEffectOps(ops, pending.name) : [];
8097
+ const normalizedOutputs = outputs !== void 0 ? validateEffectOutputs({
8098
+ outputs: outputs,
8099
+ declared: findEffect(definition, pending.name)?.outputs ?? [],
8100
+ effectName: pending.name
8101
+ }) : void 0;
8102
+ return {
8103
+ ops: ops !== void 0 ? validateEffectOps(ops, pending.name) : [],
8104
+ outputs: normalizedOutputs
8105
+ };
7454
8106
  }
7455
8107
 
7456
8108
  async function commitCompleteEffect({ctx: ctx, effectKey: effectKey, status: status, outputs: outputs, ops: ops, detail: detail, error: error, durationMs: durationMs, requestRecord: requestRecord, actor: actor}) {
@@ -7459,7 +8111,7 @@ async function commitCompleteEffect({ctx: ctx, effectKey: effectKey, status: sta
7459
8111
  record: requestRecord,
7460
8112
  now: ctx.now
7461
8113
  });
7462
- const pending = requirePendingEffect(ctx.instance, effectKey), validatedOps = validateCompletionInput({
8114
+ const pending = requirePendingEffect(ctx.instance, effectKey), {ops: validatedOps, outputs: validatedOutputs} = validateCompletionInput({
7463
8115
  pending: pending,
7464
8116
  definition: ctx.definition,
7465
8117
  status: status,
@@ -7478,7 +8130,7 @@ async function commitCompleteEffect({ctx: ctx, effectKey: effectKey, status: sta
7478
8130
  detail: detail,
7479
8131
  error: error,
7480
8132
  durationMs: durationMs,
7481
- outputs: outputs
8133
+ outputs: validatedOutputs
7482
8134
  });
7483
8135
  mutation.effectHistory.push(settlement.run);
7484
8136
  const wroteEffectOutputs = status === "done" && outputs !== void 0;
@@ -7676,6 +8328,64 @@ async function commitReport({ctx: ctx, effectKey: effectKey, claimToken: claimTo
7676
8328
  };
7677
8329
  }
7678
8330
 
8331
+ const RESET_ACTIVITY_TARGETS = [ "active", "skipped" ];
8332
+
8333
+ function isResetActivityTarget(value) {
8334
+ return RESET_ACTIVITY_TARGETS.includes(value);
8335
+ }
8336
+
8337
+ async function resetActivity(args) {
8338
+ const {client: client, instanceId: instanceId, activity: activity, to: to, requestRecord: requestRecord, options: options} = args, ctx = await loadCallContext({
8339
+ client: client,
8340
+ instanceId: instanceId,
8341
+ options: options
8342
+ });
8343
+ return commitResetActivity({
8344
+ ctx: ctx,
8345
+ activity: activity,
8346
+ to: to,
8347
+ requestRecord: requestRecord,
8348
+ actor: options?.actor
8349
+ });
8350
+ }
8351
+
8352
+ async function commitResetActivity({ctx: ctx, activity: activity, to: to, requestRecord: requestRecord, actor: actor}) {
8353
+ if (assertRequestUnprocessed({
8354
+ instance: ctx.instance,
8355
+ record: requestRecord,
8356
+ now: ctx.now
8357
+ }), isTerminal(ctx)) return {
8358
+ fired: !1
8359
+ };
8360
+ const mutation = startMutation(ctx.instance), openStage2 = findOpenStageEntry(mutation), entry = findCurrentActivityEntry(mutation, activity);
8361
+ if (openStage2 === void 0 || entry === void 0) throw new invariants.ContractViolationError(`resetActivity: activity "${activity}" is not in the current stage of instance "${ctx.instance._id}"`);
8362
+ const from = entry.status;
8363
+ if (from === to) return {
8364
+ fired: !1
8365
+ };
8366
+ if (!invariants.isTerminalActivityStatus(from)) throw new invariants.ContractViolationError(`resetActivity: activity "${activity}" is "${from}", not a terminal status — a reset only recovers a resolved (typically failed) activity. Use setStage to force past a live stage.`);
8367
+ return recordProcessedRequest({
8368
+ mutation: mutation,
8369
+ record: requestRecord,
8370
+ now: ctx.now
8371
+ }), applyActivityStatusChange({
8372
+ entry: entry,
8373
+ history: mutation.history,
8374
+ stage: openStage2.name,
8375
+ to: to,
8376
+ at: ctx.now,
8377
+ ...actor !== void 0 ? {
8378
+ actor: actor
8379
+ } : {}
8380
+ }), await persist(ctx, mutation), {
8381
+ fired: !0,
8382
+ stage: openStage2.name,
8383
+ activity: activity,
8384
+ from: from,
8385
+ to: to
8386
+ };
8387
+ }
8388
+
7679
8389
  const actorCache = /* @__PURE__ */ new WeakMap, grantsCache = /* @__PURE__ */ new WeakMap;
7680
8390
 
7681
8391
  async function resolveAccess(taggedClient, args = {}) {
@@ -7685,10 +8395,13 @@ async function resolveAccess(taggedClient, args = {}) {
7685
8395
  client: client,
7686
8396
  requestFn: requestFn,
7687
8397
  resourcePath: args.grantsFromPath
7688
- }) : Promise.resolve(void 0), [actor, grants] = await Promise.all([ cachedActor(client, requestFn), grantsPromise ]);
7689
- if (actor === void 0) throw new invariants.ContractViolationError("workflow: failed to resolve actor from `/users/me`. The client is configured but the endpoint returned no usable identity — check the token.");
8398
+ }) : Promise.resolve(void 0), [identity, grants] = await Promise.all([ cachedActor(client, requestFn), grantsPromise ]);
8399
+ if (identity === void 0) throw new invariants.ContractViolationError("workflow: failed to resolve actor from `/users/me`. The client is configured but the endpoint returned no usable identity — check the token.");
7690
8400
  return {
7691
- actor: actor,
8401
+ actor: identity.actor,
8402
+ ...identity.localPrincipalId !== void 0 ? {
8403
+ localPrincipalId: identity.localPrincipalId
8404
+ } : {},
7692
8405
  ...grants !== void 0 ? {
7693
8406
  grants: grants
7694
8407
  } : {}
@@ -7698,7 +8411,7 @@ async function resolveAccess(taggedClient, args = {}) {
7698
8411
  function cachedActor(client, requestFn) {
7699
8412
  const cached = actorCache.get(client);
7700
8413
  if (cached !== void 0) return cached;
7701
- const pending = fetchActor(requestFn).catch(err => {
8414
+ const pending = fetchActor(client, requestFn).catch(err => {
7702
8415
  throw actorCache.get(client) === pending && actorCache.delete(client), err;
7703
8416
  });
7704
8417
  return actorCache.set(client, pending), pending;
@@ -7725,27 +8438,90 @@ function cachedGrants({client: client, requestFn: requestFn, resourcePath: resou
7725
8438
  byPath.set(resourcePath, cached)), cached;
7726
8439
  }
7727
8440
 
7728
- async function fetchActor(requestFn) {
7729
- let user;
8441
+ async function fetchActor(client, requestFn) {
8442
+ const [resourceUser, globalUser] = await Promise.all([ fetchCurrentUser(requestFn, "the workflow resource host"), fetchGlobalUser(client) ]), resourceId = usableId(resourceUser), globalId = usableId(globalUser.user), id = globalId ?? resourceId;
8443
+ if (id === void 0) return;
8444
+ refuseProjectPrincipalWithoutGlobal({
8445
+ resourceId: resourceId,
8446
+ globalId: globalId,
8447
+ globalUser: globalUser
8448
+ });
8449
+ const roleNames = (resourceUser?.roles?.length ? resourceUser : globalUser.user)?.roles?.map(r => r.name).filter(n => !!n) ?? [];
8450
+ return {
8451
+ actor: {
8452
+ kind: "person",
8453
+ id: id,
8454
+ ...roleNames.length > 0 ? {
8455
+ roles: roleNames
8456
+ } : {}
8457
+ },
8458
+ ...resourceId !== void 0 && resourceId !== id ? {
8459
+ localPrincipalId: resourceId
8460
+ } : {}
8461
+ };
8462
+ }
8463
+
8464
+ function refuseProjectPrincipalWithoutGlobal(args) {
8465
+ const {resourceId: resourceId, globalId: globalId, globalUser: globalUser} = args;
8466
+ if (globalId !== void 0 || resourceId === void 0 || invariants.classifyPrincipalId(resourceId).namespace !== "project") return;
8467
+ const reason = "reason" in globalUser ? globalUser.reason : "no record";
8468
+ throw new Error(`workflow: the caller's identity on the workflow resource host is project-scoped ("${resourceId}") and the account-global record could not be resolved (${reason}). The engine speaks account-global user ids only and never acts as a project-scoped principal.`, "cause" in globalUser ? {
8469
+ cause: globalUser.cause
8470
+ } : void 0);
8471
+ }
8472
+
8473
+ function usableId(user) {
8474
+ if (!(!user || typeof user.id != "string" || user.id.length === 0)) return user.id;
8475
+ }
8476
+
8477
+ async function fetchCurrentUser(requestFn, hostDescription) {
7730
8478
  try {
7731
- user = await requestFn({
8479
+ return await requestFn({
7732
8480
  uri: "/users/me",
7733
8481
  tag: REQUEST_TAG.accessResolveActor
7734
8482
  });
7735
8483
  } catch (err) {
7736
- throw new Error('workflow: /users/me request failed. The engine resolves the actor from the client\'s token via `client.request({ uri: "/users/me" })`. Check the token/connectivity.', {
8484
+ throw new Error(`workflow: /users/me request against ${hostDescription} failed. The engine resolves the actor from the client's token via \`client.request({ uri: '/users/me' })\`. Check the token/connectivity.`, {
7737
8485
  cause: err
7738
8486
  });
7739
8487
  }
7740
- if (!user || typeof user.id != "string" || user.id.length === 0) return;
7741
- const roleNames = user.roles?.map(r => r.name).filter(n => !!n) ?? [];
7742
- return {
7743
- kind: "person",
7744
- id: user.id,
7745
- ...roleNames.length > 0 ? {
7746
- roles: roleNames
7747
- } : {}
8488
+ }
8489
+
8490
+ async function fetchGlobalUser(client) {
8491
+ if (typeof client.withConfig != "function") return {
8492
+ user: void 0,
8493
+ reason: "the client cannot reach the global API host (no withConfig)"
8494
+ };
8495
+ let globalRequest, globalClient;
8496
+ try {
8497
+ globalClient = client.withConfig({
8498
+ useProjectHostname: !1
8499
+ }), globalRequest = lazyRequest(globalClient);
8500
+ } catch (err) {
8501
+ return {
8502
+ user: void 0,
8503
+ reason: `building the global-host sibling client failed: ${invariants.errorMessage(err)}`,
8504
+ cause: err
8505
+ };
8506
+ }
8507
+ if (globalRequest === void 0) return {
8508
+ user: void 0,
8509
+ reason: "the global-host sibling client cannot issue requests"
7748
8510
  };
8511
+ try {
8512
+ return {
8513
+ user: await globalRequest({
8514
+ uri: "/users/me",
8515
+ tag: REQUEST_TAG.accessResolveActor
8516
+ })
8517
+ };
8518
+ } catch (err) {
8519
+ return {
8520
+ user: void 0,
8521
+ reason: `global-host /users/me failed: ${invariants.errorMessage(err)}`,
8522
+ cause: err
8523
+ };
8524
+ }
7749
8525
  }
7750
8526
 
7751
8527
  async function fetchGrantsCached(requestFn, resourcePath) {
@@ -7921,12 +8697,25 @@ async function subjectResourceGrants(args) {
7921
8697
  const resolved = await Promise.all([ ...clients.entries() ].map(async ([key, entry]) => {
7922
8698
  const path = aclPathForResource(entry.resource);
7923
8699
  if (path === void 0) return;
7924
- const grants = await grantsForClientPath(entry.client, path);
7925
- return grants === void 0 ? void 0 : [ key, grants ];
8700
+ const [grants, actorId] = await Promise.all([ grantsForClientPath(entry.client, path), resourceActorId(entry.client) ]);
8701
+ if (!(grants === void 0 || actorId === void 0)) return [ key, {
8702
+ grants: grants,
8703
+ actorId: actorId
8704
+ } ];
7926
8705
  }));
7927
8706
  return new Map(resolved.filter(entry => entry !== void 0));
7928
8707
  }
7929
8708
 
8709
+ async function resourceActorId(client) {
8710
+ try {
8711
+ const access = await resolveAccess(client);
8712
+ return invariants.lakePrincipalId(access);
8713
+ } catch (err) {
8714
+ console.warn(`workflow: failed to resolve the actor identity on a subject resource; the subject-write forecast omits this resource (degrade open — the lake still enforces writes). Original error: ${invariants.errorMessage(err)}`);
8715
+ return;
8716
+ }
8717
+ }
8718
+
7930
8719
  async function evaluateInstance(args) {
7931
8720
  const {client: client, tag: tag, workflowResource: workflowResource, instanceId: instanceId, resourceClients: resourceClients} = args, now = (args.clock ?? wallClock)();
7932
8721
  invariants.validateTag(tag);
@@ -7938,7 +8727,7 @@ async function evaluateInstance(args) {
7938
8727
  client: client,
7939
8728
  instanceId: instanceId,
7940
8729
  tag: tag
7941
- }) ]), {actor: actor, grants: grants} = access, definition = invariants.parseDefinitionSnapshot(instance), clientForGdr = buildClientForGdr({
8730
+ }) ]), {actor: actor, grants: grants, localPrincipalId: localPrincipalId} = access, definition = invariants.parseDefinitionSnapshot(instance), clientForGdr = buildClientForGdr({
7942
8731
  client: client,
7943
8732
  workflowResource: workflowResource,
7944
8733
  resourceClients: resourceClients
@@ -7958,6 +8747,9 @@ async function evaluateInstance(args) {
7958
8747
  guards: guards,
7959
8748
  now: now,
7960
8749
  resourceGrants: resourceGrants,
8750
+ ...localPrincipalId !== void 0 ? {
8751
+ localPrincipalId: localPrincipalId
8752
+ } : {},
7961
8753
  ...grants !== void 0 ? {
7962
8754
  grants: grants
7963
8755
  } : {}
@@ -8013,9 +8805,12 @@ async function evaluateFromSnapshot(args) {
8013
8805
  definition: definition,
8014
8806
  snapshot: snapshot,
8015
8807
  now: now
8016
- }, can = await advisoryCan({
8017
- instance: instance,
8808
+ }, anchorIdentity = invariants.lakePrincipalId({
8018
8809
  actor: actor,
8810
+ localPrincipalId: args.localPrincipalId
8811
+ }), can = await advisoryCan({
8812
+ instance: instance,
8813
+ identity: anchorIdentity,
8019
8814
  grants: grants
8020
8815
  }), scope = await renderConditionScope(scopeSource, {
8021
8816
  actor: actor,
@@ -8032,11 +8827,10 @@ async function evaluateFromSnapshot(args) {
8032
8827
  activityName: activityName
8033
8828
  })), currentActivityEntries = findOpenStageEntry(instance)?.activities ?? [], guardDenial = await instanceGuardReason({
8034
8829
  instance: instance,
8035
- actor: actor,
8830
+ identity: anchorIdentity,
8036
8831
  guards: args.guards
8037
8832
  }), subjectDenials = await forecastSubjectDenials({
8038
8833
  instance: instance,
8039
- actor: actor,
8040
8834
  snapshot: snapshot,
8041
8835
  resourceGrants: args.resourceGrants
8042
8836
  }), subjectPermissionReason = subjectDenials.length > 0 ? {
@@ -8180,20 +8974,20 @@ async function editPredicateInsight(args) {
8180
8974
  }
8181
8975
 
8182
8976
  async function forecastSubjectDenials(args) {
8183
- const {instance: instance, actor: actor, snapshot: snapshot, resourceGrants: resourceGrants} = args;
8977
+ const {instance: instance, snapshot: snapshot, resourceGrants: resourceGrants} = args;
8184
8978
  if (resourceGrants === void 0 || resourceGrants.size === 0) return [];
8185
8979
  const denials = [], seen = /* @__PURE__ */ new Set;
8186
8980
  for (const {ref: ref, parsed: parsed, resource: resource} of foreignSubjectRefs(instance)) {
8187
8981
  if (seen.has(ref.id)) continue;
8188
8982
  seen.add(ref.id);
8189
- const grants = resourceGrants.get(invariants.resourceGdr(resource));
8190
- if (grants === void 0) continue;
8983
+ const access = resourceGrants.get(invariants.resourceGdr(resource));
8984
+ if (access === void 0) continue;
8191
8985
  const doc = snapshot.docs.find(d => d._id === ref.id);
8192
8986
  doc !== void 0 && await subjectUpdateAllowed({
8193
8987
  doc: doc,
8194
8988
  parsed: parsed,
8195
- grants: grants,
8196
- actorId: actor.id
8989
+ grants: access.grants,
8990
+ actorId: access.actorId
8197
8991
  }) === !1 && denials.push({
8198
8992
  subject: ref.id,
8199
8993
  resource: invariants.resourceGdr(resource),
@@ -8274,12 +9068,12 @@ async function explainActivityConditions({activity: activity, activityScope: act
8274
9068
  snapshot: snapshot,
8275
9069
  sites: sites
8276
9070
  }), requirementEntries = [];
8277
- for (const [name, condition] of Object.entries(activity.requirements ?? {})) requirementEntries.push([ name, await explainAt({
9071
+ for (const requirement of activity.requirements ?? []) requirementEntries.push([ requirement, await explainAt({
8278
9072
  kind: "requirement",
8279
9073
  activity: activity.name,
8280
- requirement: name
8281
- }, condition) ]);
8282
- const requirementInsights = Object.fromEntries(requirementEntries), unmetRequirements = requirementEntries.filter(([, insight]) => insight.outcome !== "satisfied").map(([name]) => name), filterInsight = activity.filter !== void 0 ? await explainSite({
9074
+ requirement: requirement.name
9075
+ }, requirement.query) ]);
9076
+ const requirementInsights = Object.fromEntries(requirementEntries.map(([requirement, insight]) => [ requirement.name, insight ])), unmetRequirements = requirementEntries.filter(([, insight]) => insight.outcome !== "satisfied").map(([requirement]) => requirementDescriptor(requirement)), filterInsight = activity.filter !== void 0 ? await explainSite({
8283
9077
  site: {
8284
9078
  kind: "activity-filter",
8285
9079
  activity: activity.name
@@ -8425,12 +9219,12 @@ function actionEvaluationIdentity(action) {
8425
9219
  };
8426
9220
  }
8427
9221
 
8428
- async function instanceGuardReason({instance: instance, actor: actor, guards: guards}) {
9222
+ async function instanceGuardReason({instance: instance, identity: identity, guards: guards}) {
8429
9223
  if (guards === void 0 || guards.length === 0) return;
8430
9224
  const denied = await instanceWriteDenials({
8431
9225
  instance: instance,
8432
9226
  guards: guards,
8433
- identity: actor.id
9227
+ identity: identity
8434
9228
  });
8435
9229
  if (denied.length !== 0) return {
8436
9230
  kind: "mutation-guard-denied",
@@ -8469,12 +9263,12 @@ function inFlightFilter() {
8469
9263
  return "!defined(completedAt)";
8470
9264
  }
8471
9265
 
8472
- const FIELD_REFS_DOC = "count(fields[value.id in $documents]) > 0 || count(fields[count(value[id in $documents]) > 0]) > 0", ACTIVITY_REFS_DOC = `count(stages[count(activities[${FIELD_REFS_DOC}]) > 0]) > 0`;
9266
+ const FIELD_REFS_DOC = "count(fields[value.id in $documents]) > 0 || count(fields[count(value[id in $documents]) > 0]) > 0", OPEN_STAGE_REFS_DOC = `count(stages[!defined(exitedAt) && (${FIELD_REFS_DOC} || count(activities[${FIELD_REFS_DOC}]) > 0)]) > 0`, LIVE_SUBWORKFLOW_REFS_DOC = "count(subworkflows[!defined(resolved) && ref.id in $documents]) > 0";
8473
9267
 
8474
9268
  function documentPrefilter(documents, params) {
8475
9269
  for (const document of documents) if (!invariants.isGdrUri(document)) throw new invariants.ContractViolationError(`every document must be a resource-qualified GDR URI (e.g. "dataset:project:dataset:doc-id"); got: ${JSON.stringify(document)}`);
8476
9270
  return params.documents = [ ...documents ], params.bareIds = documents.map(invariants.extractDocumentId),
8477
- `_id in $bareIds || count(ancestors[id in $documents]) > 0 || ${FIELD_REFS_DOC} || count(stages[${FIELD_REFS_DOC}]) > 0 || ${ACTIVITY_REFS_DOC}`;
9271
+ `_id in $bareIds || count(ancestors[id in $documents]) > 0 || ${LIVE_SUBWORKFLOW_REFS_DOC} || ${FIELD_REFS_DOC} || ${OPEN_STAGE_REFS_DOC}`;
8478
9272
  }
8479
9273
 
8480
9274
  function documentArm(filter, params) {
@@ -8900,11 +9694,10 @@ async function commitEdit({ctx: ctx, target: target, mode: mode, value: value, r
8900
9694
  }
8901
9695
 
8902
9696
  async function assertFieldEditable({ctx: ctx, site: site, options: options}) {
8903
- const actor = options?.actor, window = fieldWindowOpen(ctx.instance, site), can = options?.grants !== void 0 && actor !== void 0 ? await advisoryCan({
9697
+ const actor = options?.actor, window = fieldWindowOpen(ctx.instance, site), can = await advisoryCanForCall({
8904
9698
  instance: ctx.instance,
8905
- actor: actor,
8906
- grants: options.grants
8907
- }) : void 0, predicateSatisfied = window.open && site.effective !== !0 && site.effective !== void 0 ? await ctxEvaluateCondition({
9699
+ options: options
9700
+ }), predicateSatisfied = window.open && site.effective !== !0 && site.effective !== void 0 ? await ctxEvaluateCondition({
8908
9701
  ctx: ctx,
8909
9702
  condition: site.effective,
8910
9703
  opts: {
@@ -9262,8 +10055,7 @@ async function abortAndPropagate(args) {
9262
10055
  executionContext: executionContext,
9263
10056
  telemetry: telemetry
9264
10057
  })
9265
- });
9266
- return await drainCondemnedChildren({
10058
+ }), drained = await drainCondemnedChildren({
9267
10059
  client: client,
9268
10060
  instanceId: instanceId,
9269
10061
  actor: actor,
@@ -9275,8 +10067,12 @@ async function abortAndPropagate(args) {
9275
10067
  } : {},
9276
10068
  ...telemetry !== void 0 ? {
9277
10069
  telemetry: telemetry
10070
+ } : {},
10071
+ ...result.fired ? {
10072
+ instance: result.instance
9278
10073
  } : {}
9279
- }), await propagateToAncestors({
10074
+ });
10075
+ return await propagateToAncestors({
9280
10076
  client: client,
9281
10077
  instanceId: instanceId,
9282
10078
  actor: actor,
@@ -9288,6 +10084,9 @@ async function abortAndPropagate(args) {
9288
10084
  } : {},
9289
10085
  ...telemetry !== void 0 ? {
9290
10086
  telemetry: telemetry
10087
+ } : {},
10088
+ ...result.fired && !drained.drained ? {
10089
+ instance: drained.instance
9291
10090
  } : {}
9292
10091
  }), result.fired;
9293
10092
  }
@@ -9395,6 +10194,9 @@ function buildEngineCallOptions(args) {
9395
10194
  actor: args.actor,
9396
10195
  clientForGdr: args.clientForGdr,
9397
10196
  refSurface: args.refSurface,
10197
+ ...args.localPrincipalId !== void 0 ? {
10198
+ localPrincipalId: args.localPrincipalId
10199
+ } : {},
9398
10200
  ...args.grants !== void 0 ? {
9399
10201
  grants: args.grants
9400
10202
  } : {},
@@ -9536,6 +10338,15 @@ async function abortInstances(args) {
9536
10338
  return aborted;
9537
10339
  }
9538
10340
 
10341
+ function projectStartSliceRow(instance) {
10342
+ const subject = (instance.fields ?? []).find(field => field._type === "subject")?.value;
10343
+ return {
10344
+ definition: instance.definition,
10345
+ subject: typeof subject == "object" && subject !== null && "id" in subject && invariants.isGdrUri(subject.id) ? subject.id : null,
10346
+ completedAt: instance.completedAt ?? null
10347
+ };
10348
+ }
10349
+
9539
10350
  async function fetchStartSlice(args) {
9540
10351
  const {client: client, tag: tag} = args, {query: query, params: params} = instancesQuery({
9541
10352
  tag: tag,
@@ -9543,7 +10354,7 @@ async function fetchStartSlice(args) {
9543
10354
  includeCompleted: !0
9544
10355
  }
9545
10356
  });
9546
- return (await client.fetch(query, params)).map(invariants.assertReadableModel);
10357
+ return (await client.fetch(query, params)).map(invariants.assertReadableModel).map(projectStartSliceRow);
9547
10358
  }
9548
10359
 
9549
10360
  const workflow = {
@@ -9692,6 +10503,9 @@ const workflow = {
9692
10503
  ...access.grants !== void 0 ? {
9693
10504
  grants: access.grants
9694
10505
  } : {},
10506
+ ...access.localPrincipalId !== void 0 ? {
10507
+ localPrincipalId: access.localPrincipalId
10508
+ } : {},
9695
10509
  clock: clock,
9696
10510
  clientForGdr: clientForGdr,
9697
10511
  refSurface: refSurface,
@@ -9760,6 +10574,9 @@ const workflow = {
9760
10574
  ...access.grants !== void 0 ? {
9761
10575
  grants: access.grants
9762
10576
  } : {},
10577
+ ...access.localPrincipalId !== void 0 ? {
10578
+ localPrincipalId: access.localPrincipalId
10579
+ } : {},
9763
10580
  clock: clock,
9764
10581
  clientForGdr: clientForGdr,
9765
10582
  refSurface: refSurface,
@@ -9919,7 +10736,7 @@ const workflow = {
9919
10736
  });
9920
10737
  },
9921
10738
  tick: async rawArgs => {
9922
- const args = taggedScope(rawArgs, REQUEST_TAG.tick), {client: client, tag: tag, instanceId: instanceId, executionContext: executionContext} = args, {actor: actor, clientForGdr: clientForGdr, refSurface: refSurface} = await resolveOperationContext(args), clock = args.clock ?? wallClock, current = await reload({
10739
+ const args = taggedScope(rawArgs, REQUEST_TAG.tick), {client: client, tag: tag, instanceId: instanceId, executionContext: executionContext} = args, {access: access, actor: actor, clientForGdr: clientForGdr, refSurface: refSurface} = await resolveOperationContext(args), clock = args.clock ?? wallClock, current = await reload({
9923
10740
  client: client,
9924
10741
  instanceId: instanceId,
9925
10742
  tag: tag
@@ -9927,7 +10744,7 @@ const workflow = {
9927
10744
  await assertInstanceWriteAllowed({
9928
10745
  instance: current,
9929
10746
  guards: guards,
9930
- identity: actor.id
10747
+ identity: invariants.lakePrincipalId(access)
9931
10748
  });
9932
10749
  const {cascaded: cascaded, instance: instance} = await cascadeAndReload({
9933
10750
  client: client,
@@ -10044,6 +10861,59 @@ const workflow = {
10044
10861
  }
10045
10862
  });
10046
10863
  },
10864
+ resetActivity: async rawArgs => {
10865
+ const args = taggedScope(rawArgs, REQUEST_TAG.resetActivity), {client: client, tag: tag, instanceId: instanceId, activity: activity, executionContext: executionContext} = args, to = args.to ?? "active";
10866
+ if (!isResetActivityTarget(to)) throw new invariants.ContractViolationError(`resetActivity: "to" must be "active" or "skipped"; got ${JSON.stringify(args.to)}`);
10867
+ return runCommitVerb({
10868
+ args: args,
10869
+ op: "resetActivity",
10870
+ run: async ({actor: actor, clientForGdr: clientForGdr, refSurface: refSurface, clock: clock, record: record, before: before}) => {
10871
+ const result = await resetActivity({
10872
+ client: client,
10873
+ instanceId: instanceId,
10874
+ activity: activity,
10875
+ to: to,
10876
+ ...record !== void 0 ? {
10877
+ requestRecord: record
10878
+ } : {},
10879
+ options: engineOptionsForActor({
10880
+ actor: actor,
10881
+ clock: clock,
10882
+ clientForGdr: clientForGdr,
10883
+ refSurface: refSurface,
10884
+ executionContext: executionContext,
10885
+ telemetry: args.telemetry
10886
+ })
10887
+ }), cascaded = result.fired ? await cascade({
10888
+ client: client,
10889
+ instanceId: instanceId,
10890
+ actor: actor,
10891
+ clientForGdr: clientForGdr,
10892
+ refSurface: refSurface,
10893
+ clock: clock,
10894
+ ...executionContext !== void 0 ? {
10895
+ executionContext: executionContext
10896
+ } : {},
10897
+ ...args.telemetry !== void 0 ? {
10898
+ telemetry: args.telemetry
10899
+ } : {}
10900
+ }) : 0;
10901
+ return resolveTelemetry(args.telemetry).log(WorkflowActivityReset, {
10902
+ ...definitionHashFragment(before.pinnedContentHash),
10903
+ instanceId: instanceId,
10904
+ changed: result.fired
10905
+ }), {
10906
+ instance: await reload({
10907
+ client: client,
10908
+ instanceId: instanceId,
10909
+ tag: tag
10910
+ }),
10911
+ cascaded: cascaded,
10912
+ changed: result.fired
10913
+ };
10914
+ }
10915
+ });
10916
+ },
10047
10917
  getInstance: async rawArgs => {
10048
10918
  const args = taggedScope(rawArgs, REQUEST_TAG.getInstance), {client: client, tag: tag, instanceId: instanceId} = args;
10049
10919
  return invariants.validateTag(tag), reload({
@@ -10190,21 +11060,18 @@ const workflow = {
10190
11060
  return (await client.fetch(query, params)).map(readInstanceDoc).filter(instance => instanceWatchesDocument(instance, document));
10191
11061
  },
10192
11062
  definitionsForDocument: async rawArgs => {
10193
- const args = taggedScope(rawArgs, REQUEST_TAG.definitionsForDocument), {client: client, tag: tag, document: document, subject: subject} = args;
11063
+ const args = taggedScope(rawArgs, REQUEST_TAG.definitionsForDocument), {client: client, tag: tag, document: document} = args;
10194
11064
  invariants.validateTag(tag);
10195
- const clock = args.clock ?? wallClock, deployed = (await client.fetch(definitionsListGroq("desc"), {
11065
+ const clock = args.clock ?? wallClock, deployed = (await client.fetch(latestDefinitionsGroq(), {
10196
11066
  tag: tag
10197
- })).map(invariants.assertReadableModel), latest = latestDeployedDefinitions(deployed);
11067
+ })).map(invariants.assertReadableModel);
10198
11068
  let slice;
10199
11069
  return applicableDefinitions({
10200
- definitions: latest,
11070
+ definitions: deployed,
10201
11071
  document: document,
10202
11072
  scope: {
10203
11073
  tag: tag,
10204
11074
  now: clock(),
10205
- ...subject !== void 0 ? {
10206
- subject: subject
10207
- } : {},
10208
11075
  fetchDataset: () => slice ??= fetchStartSlice({
10209
11076
  client: client,
10210
11077
  tag: tag
@@ -10227,34 +11094,17 @@ const workflow = {
10227
11094
  }), missingRequired = missingRequiredInputs({
10228
11095
  entryDefs: definition.fields ?? [],
10229
11096
  initialFields: initialFields ?? []
10230
- }), allowed = definition.start?.allowed;
10231
- if (allowed === void 0) return {
10232
- allowed: invalidInitialFields.length === 0,
10233
- outcome: "satisfied",
10234
- unboundReads: [],
10235
- missingRequired: missingRequired,
10236
- invalidInitialFields: invalidInitialFields
10237
- };
10238
- const unboundReads = unboundAllowedReadsWithSubject({
10239
- allowed: allowed,
10240
- fields: startFieldsParam({
10241
- entryDefs: definition.fields ?? [],
10242
- initialFields: initialFields ?? []
10243
- }),
10244
- definition: definition
10245
- }), insight = await startAllowedInsight({
11097
+ }), verdict = await startRequirementVerdict({
10246
11098
  client: client,
10247
11099
  tag: tag,
10248
11100
  definition: definition,
10249
- allowed: allowed,
10250
11101
  initialFields: initialFields ?? [],
10251
- now: clock()
10252
- }), provisional = unboundReads.length > 0;
11102
+ now: clock(),
11103
+ preflight: !0
11104
+ });
10253
11105
  return {
10254
- allowed: invalidInitialFields.length === 0 && !provisional && insight.outcome === "satisfied",
10255
- outcome: provisional ? "unevaluable" : insight.outcome,
10256
- insight: insight,
10257
- unboundReads: unboundReads,
11106
+ ...verdict,
11107
+ allowed: invalidInitialFields.length === 0 && verdict.allowed,
10258
11108
  missingRequired: missingRequired,
10259
11109
  invalidInitialFields: invalidInitialFields
10260
11110
  };
@@ -10266,11 +11116,10 @@ const workflow = {
10266
11116
  }
10267
11117
  };
10268
11118
 
10269
- async function startAllowedInsight(args) {
10270
- const {client: client, tag: tag, definition: definition, allowed: allowed, initialFields: initialFields, now: now} = args;
10271
- return explainStartAllowed({
10272
- allowed: allowed,
10273
- definition: definition,
11119
+ function startPredicateContext(args) {
11120
+ const {client: client, tag: tag, definition: definition, initialFields: initialFields, now: now} = args;
11121
+ let slice;
11122
+ return {
10274
11123
  fields: startFieldsParam({
10275
11124
  entryDefs: definition.fields ?? [],
10276
11125
  initialFields: initialFields
@@ -10278,12 +11127,71 @@ async function startAllowedInsight(args) {
10278
11127
  scope: {
10279
11128
  tag: tag,
10280
11129
  now: now,
10281
- fetchDataset: () => fetchStartSlice({
11130
+ fetchDataset: () => slice ??= fetchStartSlice({
10282
11131
  client: client,
10283
11132
  tag: tag
10284
11133
  })
10285
11134
  }
10286
- });
11135
+ };
11136
+ }
11137
+
11138
+ async function startRequirementVerdict(args) {
11139
+ const {client: client, tag: tag, definition: definition, initialFields: initialFields, now: now, preflight: preflight = !1} = args, declared = definition.start?.requirements ?? [];
11140
+ if (declared.length === 0) return {
11141
+ allowed: !0,
11142
+ outcome: "satisfied",
11143
+ requirements: [],
11144
+ unboundReads: []
11145
+ };
11146
+ const {fields: fields, scope: scope} = startPredicateContext({
11147
+ client: client,
11148
+ tag: tag,
11149
+ definition: definition,
11150
+ initialFields: initialFields,
11151
+ now: now
11152
+ }), subjectEntry = (definition.fields ?? []).find(invariants.isSubjectEntry)?.name, requirements = [], unbound = /* @__PURE__ */ new Set;
11153
+ for (const requirement of declared) {
11154
+ const descriptor = requirementDescriptor(requirement);
11155
+ if (requirement.type === "singleSubject") {
11156
+ if (preflight && subjectEntry !== void 0 && !Object.hasOwn(fields, subjectEntry)) unbound.add(subjectEntry),
11157
+ requirements.push({
11158
+ ...descriptor,
11159
+ outcome: "unevaluable"
11160
+ }); else {
11161
+ const refused = await singleSubjectRequirementRefused({
11162
+ definition: definition,
11163
+ fields: fields,
11164
+ scope: scope
11165
+ });
11166
+ requirements.push({
11167
+ ...descriptor,
11168
+ outcome: refused ? "unsatisfied" : "satisfied"
11169
+ });
11170
+ }
11171
+ continue;
11172
+ }
11173
+ const missing = unboundRequirementReads(requirement.query, fields);
11174
+ missing.forEach(name => unbound.add(name));
11175
+ const insight = await explainStartRequirement({
11176
+ query: requirement.query,
11177
+ definition: definition,
11178
+ fields: fields,
11179
+ scope: scope
11180
+ });
11181
+ requirements.push({
11182
+ ...descriptor,
11183
+ outcome: preflight && missing.length > 0 ? "unevaluable" : insight.outcome,
11184
+ insight: insight
11185
+ });
11186
+ }
11187
+ let outcome = "satisfied";
11188
+ return requirements.some(requirement => requirement.outcome === "unsatisfied") ? outcome = "unsatisfied" : requirements.some(requirement => requirement.outcome === "unevaluable") && (outcome = "unevaluable"),
11189
+ {
11190
+ allowed: outcome === "satisfied",
11191
+ outcome: outcome,
11192
+ requirements: requirements,
11193
+ unboundReads: [ ...unbound ]
11194
+ };
10287
11195
  }
10288
11196
 
10289
11197
  async function startFreshInstance(args) {
@@ -10383,19 +11291,16 @@ async function assertStartInputs(args) {
10383
11291
  initialFields: initialFields,
10384
11292
  definitionName: definition.name
10385
11293
  });
10386
- const allowed = definition.start?.allowed;
10387
- if (allowed === void 0) return;
10388
- const insight = await startAllowedInsight({
11294
+ const unmetRequirements = (await startRequirementVerdict({
10389
11295
  client: client,
10390
11296
  tag: tag,
10391
11297
  definition: definition,
10392
- allowed: allowed,
10393
11298
  initialFields: initialFields,
10394
11299
  now: now
10395
- });
10396
- if (insight.outcome !== "satisfied") throw new StartNotAllowedError({
11300
+ })).requirements.filter(requirement => requirement.outcome !== "satisfied").map(requirementDescriptor);
11301
+ if (unmetRequirements.length > 0) throw new StartNotAllowedError({
10397
11302
  definition: definition.name,
10398
- insight: insight
11303
+ unmetRequirements: unmetRequirements
10399
11304
  });
10400
11305
  }
10401
11306
 
@@ -10428,97 +11333,6 @@ async function resolveStartFields(args) {
10428
11333
  };
10429
11334
  }
10430
11335
 
10431
- function isRecord(value) {
10432
- return typeof value == "object" && value !== null && !Array.isArray(value);
10433
- }
10434
-
10435
- function isClientProjectUser(value) {
10436
- return isRecord(value) && typeof value.id == "string" && (value.displayName === void 0 || typeof value.displayName == "string") && (value.email === void 0 || typeof value.email == "string") && (value.imageUrl === void 0 || value.imageUrl === null || typeof value.imageUrl == "string");
10437
- }
10438
-
10439
- function objectProperty(value, property) {
10440
- if (!isRecord(value)) return;
10441
- const propertyValue = value[property];
10442
- return typeof propertyValue == "object" && propertyValue !== null ? propertyValue : void 0;
10443
- }
10444
-
10445
- function stringProperty(value, property) {
10446
- const propertyValue = Reflect.get(value, property);
10447
- return typeof propertyValue == "string" ? propertyValue : void 0;
10448
- }
10449
-
10450
- function apiErrorType(error) {
10451
- const response = objectProperty(error, "response"), body = objectProperty(response, "body");
10452
- if (!body) return;
10453
- const nestedError = objectProperty(body, "error");
10454
- return (nestedError ? stringProperty(nestedError, "type") : void 0) ?? stringProperty(body, "type");
10455
- }
10456
-
10457
- function isProjectUserNotFoundError(error) {
10458
- return apiErrorType(error) === "projectUserNotFoundError";
10459
- }
10460
-
10461
- function clientProjectUserDirectory(client, projectId) {
10462
- return {
10463
- findById: async id => {
10464
- if (!client.request) return {
10465
- status: "inaccessible",
10466
- cause: new Error("Project-user resolution requires WorkflowClient.request")
10467
- };
10468
- try {
10469
- const response = await client.request({
10470
- uri: `/projects/${encodeURIComponent(projectId)}/users/${encodeURIComponent(id)}`
10471
- }), candidate = Array.isArray(response) ? response[0] : response;
10472
- return candidate == null ? {
10473
- status: "missing"
10474
- } : isClientProjectUser(candidate) ? {
10475
- status: "resolved",
10476
- user: candidate
10477
- } : {
10478
- status: "inaccessible",
10479
- cause: new Error("Project-user response had an invalid shape")
10480
- };
10481
- } catch (cause) {
10482
- return isProjectUserNotFoundError(cause) ? {
10483
- status: "missing"
10484
- } : {
10485
- status: "inaccessible",
10486
- cause: cause
10487
- };
10488
- }
10489
- }
10490
- };
10491
- }
10492
-
10493
- function resolveClientActor(client, args) {
10494
- return resolveActor(clientProjectUserDirectory(client, args.projectId), args.actor);
10495
- }
10496
-
10497
- async function resolveActor(directory, actor) {
10498
- if (actor.kind !== "person") return {
10499
- status: "not-person",
10500
- actor: actor
10501
- };
10502
- const personActor = {
10503
- ...actor,
10504
- kind: "person"
10505
- }, lookup = await directory.findById(personActor.id);
10506
- return lookup.status === "resolved" ? {
10507
- status: "resolved",
10508
- actor: personActor,
10509
- user: lookup.user
10510
- } : lookup.status === "inaccessible" ? {
10511
- status: "inaccessible",
10512
- actor: personActor,
10513
- ...lookup.cause === void 0 ? {} : {
10514
- cause: lookup.cause
10515
- }
10516
- } : {
10517
- status: "missing",
10518
- actor: personActor
10519
- };
10520
- }
10521
-
10522
11336
  const EFFECT_COMMIT_QUEUE_DEPTH = 32, EFFECT_COMMIT_DISPATCH_CAP = 200;
10523
11337
 
10524
11338
  class EffectCommitQueueOverflowError extends invariants.WorkflowError {
@@ -11144,17 +11958,23 @@ function createInstanceSession(args) {
11144
11958
  refSurface: evalScope.refSurface
11145
11959
  });
11146
11960
  }, evaluateWith = async ({held: held, guards: guards, self: self}) => {
11147
- const {actor: actor, grants: grants} = await access(), resourceGrants = await subjectResourceGrants({
11961
+ const {actor: actor, localPrincipalId: localPrincipalId, grants: grants} = await access(), resourceGrants = await subjectResourceGrants({
11148
11962
  clientForGdr: evalScope.clientForGdr,
11149
11963
  instance: instance
11964
+ }), normalizedSelf = await normalizeInstanceIdentities({
11965
+ client: evalScope.client,
11966
+ instance: self
11150
11967
  });
11151
11968
  return evaluateFromSnapshot({
11152
- instance: self,
11969
+ instance: normalizedSelf,
11153
11970
  definition: definitionOf(),
11154
11971
  actor: actor,
11155
- snapshot: snapshotFrom(held, self),
11972
+ snapshot: snapshotFrom(held, normalizedSelf),
11156
11973
  guards: guards,
11157
11974
  resourceGrants: resourceGrants,
11975
+ ...localPrincipalId !== void 0 ? {
11976
+ localPrincipalId: localPrincipalId
11977
+ } : {},
11158
11978
  ...clock !== void 0 ? {
11159
11979
  now: clock()
11160
11980
  } : {},
@@ -11200,8 +12020,13 @@ function createInstanceSession(args) {
11200
12020
  committing = !0;
11201
12021
  const held = new Map(overlay);
11202
12022
  try {
11203
- const {actor: actor} = await access();
11204
- return await run(actor, held);
12023
+ const {actor: actor, localPrincipalId: localPrincipalId} = await access();
12024
+ return await run({
12025
+ actor: actor,
12026
+ ...localPrincipalId !== void 0 ? {
12027
+ localPrincipalId: localPrincipalId
12028
+ } : {}
12029
+ }, held);
11205
12030
  } finally {
11206
12031
  if (committing = !1, buffered !== void 0) {
11207
12032
  const next = buffered;
@@ -11276,11 +12101,14 @@ function createInstanceSession(args) {
11276
12101
  site !== void 0 && previews.delete(siteKey(site));
11277
12102
  },
11278
12103
  tick() {
11279
- return commit(async (actor, held) => {
12104
+ return commit(async ({actor: actor, localPrincipalId: localPrincipalId}, held) => {
11280
12105
  await assertInstanceWriteAllowed({
11281
12106
  instance: instance,
11282
12107
  guards: heldGuards,
11283
- identity: actor.id
12108
+ identity: invariants.lakePrincipalId({
12109
+ actor: actor,
12110
+ localPrincipalId: localPrincipalId
12111
+ })
11284
12112
  });
11285
12113
  const before = await reload({
11286
12114
  client: tickScope.client,
@@ -11307,7 +12135,7 @@ function createInstanceSession(args) {
11307
12135
  });
11308
12136
  },
11309
12137
  fireAction({activity: activity, action: action, params: params}) {
11310
- return commit(async (actor, held) => {
12138
+ return commit(async ({actor: actor, localPrincipalId: localPrincipalId}, held) => {
11311
12139
  assertActionAllowed({
11312
12140
  evaluation: await evaluateWith({
11313
12141
  held: held,
@@ -11323,6 +12151,9 @@ function createInstanceSession(args) {
11323
12151
  activity: activity,
11324
12152
  action: action,
11325
12153
  actor: actor,
12154
+ ...localPrincipalId !== void 0 ? {
12155
+ localPrincipalId: localPrincipalId
12156
+ } : {},
11326
12157
  clientForGdr: fireScope.clientForGdr,
11327
12158
  refSurface: fireScope.refSurface,
11328
12159
  ...grants !== void 0 ? {
@@ -11365,7 +12196,7 @@ function createInstanceSession(args) {
11365
12196
  } catch (err) {
11366
12197
  return Promise.reject(err);
11367
12198
  }
11368
- return commit(async (actor, held) => {
12199
+ return commit(async ({actor: actor, localPrincipalId: localPrincipalId}, held) => {
11369
12200
  assertEditAllowed(await evaluateWith({
11370
12201
  held: held,
11371
12202
  guards: heldGuards,
@@ -11382,6 +12213,9 @@ function createInstanceSession(args) {
11382
12213
  value: value
11383
12214
  } : {},
11384
12215
  actor: actor,
12216
+ ...localPrincipalId !== void 0 ? {
12217
+ localPrincipalId: localPrincipalId
12218
+ } : {},
11385
12219
  clientForGdr: editScope.clientForGdr,
11386
12220
  refSurface: editScope.refSurface,
11387
12221
  ...grants !== void 0 ? {
@@ -11492,6 +12326,7 @@ function createEngine(args) {
11492
12326
  availableActions: rest => workflow.availableActions(withScope(rest)),
11493
12327
  setStage: rest => workflow.setStage(withScope(rest)),
11494
12328
  abortInstance: rest => workflow.abortInstance(withScope(rest)),
12329
+ resetActivity: rest => workflow.resetActivity(withScope(rest)),
11495
12330
  deleteDefinition: rest => workflow.deleteDefinition(withScope(rest)),
11496
12331
  getInstance: rest => workflow.getInstance(withScope(rest)),
11497
12332
  subscriptionDocumentsForInstance: rest => workflow.getInstance(withScope(rest)).then(subscriptionDocumentsForInstance),
@@ -12064,6 +12899,8 @@ exports.ACTIVITY_KINDS = invariants.ACTIVITY_KINDS;
12064
12899
 
12065
12900
  exports.ACTOR_KINDS = invariants.ACTOR_KINDS;
12066
12901
 
12902
+ exports.ANONYMOUS_IDENTITY = invariants.ANONYMOUS_IDENTITY;
12903
+
12067
12904
  exports.CONDITION_VARS = invariants.CONDITION_VARS;
12068
12905
 
12069
12906
  exports.ContractViolationError = invariants.ContractViolationError;
@@ -12106,10 +12943,12 @@ exports.RESERVED_CONDITION_VARS = invariants.RESERVED_CONDITION_VARS;
12106
12943
 
12107
12944
  exports.ReaderModelAcknowledgementError = invariants.ReaderModelAcknowledgementError;
12108
12945
 
12109
- exports.START_ALLOWED_VARS = invariants.START_ALLOWED_VARS;
12110
-
12111
12946
  exports.START_FILTER_VARS = invariants.START_FILTER_VARS;
12112
12947
 
12948
+ exports.START_REQUIREMENT_VARS = invariants.START_REQUIREMENT_VARS;
12949
+
12950
+ exports.SYSTEM_IDENTITY = invariants.SYSTEM_IDENTITY;
12951
+
12113
12952
  exports.SpawnContractsInvalidError = invariants.SpawnContractsInvalidError;
12114
12953
 
12115
12954
  exports.WORKFLOW_DEFINITION_TYPE = invariants.WORKFLOW_DEFINITION_TYPE;
@@ -12122,6 +12961,8 @@ exports.assertReadableModel = invariants.assertReadableModel;
12122
12961
 
12123
12962
  exports.assertReaderModelAcknowledgement = invariants.assertReaderModelAcknowledgement;
12124
12963
 
12964
+ exports.classifyPrincipalId = invariants.classifyPrincipalId;
12965
+
12125
12966
  exports.clientConfigFromResource = invariants.clientConfigFromResource;
12126
12967
 
12127
12968
  exports.conditionFieldReadNames = invariants.conditionFieldReadNames;
@@ -12172,6 +13013,8 @@ exports.isTodoListItem = invariants.isTodoListItem;
12172
13013
 
12173
13014
  exports.isUnprimed = invariants.isUnprimed;
12174
13015
 
13016
+ exports.lakePrincipalId = invariants.lakePrincipalId;
13017
+
12175
13018
  exports.minReaderModelOf = invariants.minReaderModelOf;
12176
13019
 
12177
13020
  exports.modelVersionOf = invariants.modelVersionOf;
@@ -12398,6 +13241,8 @@ exports.StartNotSettledError = StartNotSettledError;
12398
13241
 
12399
13242
  exports.WorkflowActionFired = WorkflowActionFired;
12400
13243
 
13244
+ exports.WorkflowActivityReset = WorkflowActivityReset;
13245
+
12401
13246
  exports.WorkflowDefinitionDeleted = WorkflowDefinitionDeleted;
12402
13247
 
12403
13248
  exports.WorkflowDefinitionDeployed = WorkflowDefinitionDeployed;
@@ -12530,7 +13375,7 @@ exports.evaluateStartFilter = evaluateStartFilter;
12530
13375
 
12531
13376
  exports.expandResourceAliases = expandResourceAliases;
12532
13377
 
12533
- exports.explainStartAllowed = explainStartAllowed;
13378
+ exports.explainStartRequirement = explainStartRequirement;
12534
13379
 
12535
13380
  exports.findCurrentActivityEntry = findCurrentActivityEntry;
12536
13381
 
@@ -12546,6 +13391,8 @@ exports.guardsForInstance = guardsForInstance;
12546
13391
 
12547
13392
  exports.guardsForResource = guardsForResource;
12548
13393
 
13394
+ exports.hasSingleSubjectRequirement = hasSingleSubjectRequirement;
13395
+
12549
13396
  exports.hashDefinitionContent = hashDefinitionContent;
12550
13397
 
12551
13398
  exports.inFlightFilter = inFlightFilter;
@@ -12578,6 +13425,8 @@ exports.isTerminalStage = isTerminalStage;
12578
13425
 
12579
13426
  exports.lakeGuardId = lakeGuardId;
12580
13427
 
13428
+ exports.latestDefinitionsGroq = latestDefinitionsGroq;
13429
+
12581
13430
  exports.latestDeployedDefinitions = latestDeployedDefinitions;
12582
13431
 
12583
13432
  exports.lintEffectOutputs = lintEffectOutputs;
@@ -12596,6 +13445,8 @@ exports.parseInstanceDocument = parseInstanceDocument;
12596
13445
 
12597
13446
  exports.processShellUserProperties = processShellUserProperties;
12598
13447
 
13448
+ exports.projectStartSliceRow = projectStartSliceRow;
13449
+
12599
13450
  exports.projectToWatchRef = projectToWatchRef;
12600
13451
 
12601
13452
  exports.readInstanceDoc = readInstanceDoc;
@@ -12618,6 +13469,8 @@ exports.retractStageGuards = retractStageGuards;
12618
13469
 
12619
13470
  exports.silentLogger = silentLogger;
12620
13471
 
13472
+ exports.singleSubjectRequirementRefused = singleSubjectRequirementRefused;
13473
+
12621
13474
  exports.stageAutonomyOf = stageAutonomyOf;
12622
13475
 
12623
13476
  exports.startFieldsParam = startFieldsParam;
@@ -12634,7 +13487,7 @@ exports.subscriptionDocumentsForInstance = subscriptionDocumentsForInstance;
12634
13487
 
12635
13488
  exports.sweepStaleClaims = sweepStaleClaims;
12636
13489
 
12637
- exports.unboundAllowedReads = unboundAllowedReads;
13490
+ exports.unboundRequirementReads = unboundRequirementReads;
12638
13491
 
12639
13492
  exports.unsatisfiedTransitionSummaries = unsatisfiedTransitionSummaries;
12640
13493