@sanity/workflow-engine 0.29.0 → 0.30.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -1,5 +1,56 @@
1
1
  # @sanity/workflow-engine
2
2
 
3
+ ## 0.30.0
4
+
5
+ ### Minor Changes
6
+
7
+ - a3a8dc0: The engine gains a list-projection read for instance dashboards. `instancePreviewsQuery` compiles the same filter arms as `instancesQuery` into a `WorkflowInstancePreview` projection — the open stage alone, field lists reduced to identity, date, document-reference, and release-reference kinds, and `claimedEffects`/`failedEffects` facts in place of the unbounded audit trails — kilobytes lighter per row than the full document. `readInstancePreviewDoc` is the matching gate-then-parse funnel (`WorkflowInstancePreviewSchema`/`parseInstancePreviewDocument` underneath), and the internal identity normalizer accepts any host carrying the identity slots, rows included. `InstancesQueryFilter` adds a keyset `before` cursor (requires `limit`) for paging the newest-first order without skipping or repeating rows across pages; both list orders now break `startedAt` ties on `_id`. **No upgrade action required** — existing reads are unchanged apart from the deterministic tie order.
8
+
9
+ **Docs impact:** The engine reference's instance-query section documents `instancePreviewsQuery`, `WorkflowInstancePreview`, and the `before` cursor in this release's pass — the Workflows tool ships reading them in the same release.
10
+
11
+ - a3a8dc0: **BREAKING:** the exported `WorkflowObserver` contract (workflow-react) gains two required members, `fetchInstancePreviews` and `listenInstanceChanges` — a custom observer no longer compiles until it implements both; the shipped SDK and Studio adapters already do, so their consumers need no action.
12
+
13
+ The reactive layer gains a progressively-hydrated preview list. `useInstancePreviews` (workflow-react) drains the engine's preview projection page by page until the whole filtered set is held — `drained: true` means counts over it are totals — then keeps every row fresh from ONE shared change listener per engine tag: an event refetches the touched previews alone, so update cost is per commit, never per list size. Page size is caller-supplied. The engine adds `instanceChangesQuery` (the tag partition as a listen filter), and the `WorkflowObserver` contract adds `fetchInstancePreviews` and `listenInstanceChanges`, implemented by the SDK observer (the Studio adapter inherits them). A change-feed failure never silently freezes a list: the SDK observer reconnects with exponential backoff and then emits a `reset` event, on which `useInstancePreviews` re-drains the whole partition — gap-missed additions, edits, and deletions all land.
14
+
15
+ **Docs impact:** The reactive-core reference documents `useInstancePreviews` and the observer contract's two new required members in this release's pass — the Workflows tool ships reading them in the same release, and the custom-adapter guidance must name both members beside the BREAKING note.
16
+
17
+ - 90207dc: **BREAKING:** `assertReaderModelAcknowledgement` now requires `{requiredMinReaderModel, context?}` instead of a context string, and `ReaderModelAcknowledgementError` accepts its optional context through `{context}`. The Blueprint package's `AcknowledgedDeployment` type moves to the engine as `AcknowledgedWorkflowDeployment`; update imports and use that shared name. Assignment-valued fields can now declare a non-empty `roles` list that limits newly written assignees. Existing fields without `roles` stay unconstrained, retain reader floor 4, and continue deploying with `expectedMinReaderModel: 4`; installing this release requires no coordinated rollout or configuration change.
18
+
19
+ Before adding `roles`, upgrade every Studio, CLI, MCP server, Function, and other runtime that shares the affected workflow resource, then change that deployment's literal `expectedMinReaderModel` to `8`. MCP deployments pass the same reviewed literal as the optional `expectedMinReaderModel` tool argument. Definitions and instances carrying the facet require reader model 8. User assignees qualify through direct roles or the definition's role aliases, while collective role assignees must literally match one configured role. Studio assignment controls, including manual start, auto-start, and assignees nested in to-do rows, offer only eligible choices while retaining stale current values so editors can remove or replace them. Constrained pickers name the active eligible roles and distinguish an empty eligible set from a search with no matches. Top-level plural and composite edits retain no more occurrences of a stale assignment at each declared assignment location than the previous value contained; removal and reordering therefore work, while an added copy is a new assignment and must qualify. Direct singular replacements and every assignment present in an `updateWhere` fragment remain strict. Each engine verb uses one member-directory snapshot across retries, cascade hops, and spawned children, then the next verb reads current membership.
20
+
21
+ Malformed project-member and project-user directory responses now fail loudly instead of treating bad rows or role records as missing users, and actor resolution reports those failures as `inaccessible`, so integrations can distinguish directory failures from absent membership.
22
+
23
+ CLI `start` and `definition delete` no longer apply the definition-submission acknowledgement gate; deploy, check, dry-run, definition diff, Blueprint provision, and engine definition APIs still validate the selected definitions' required floor.
24
+
25
+ No reader-fleet rollout or deployment-literal change is required for existing definitions that do not use `roles`.
26
+
27
+ **Docs impact:** Update the assignment field reference and authoring examples for `roles`, distinguish eligibility from editability, action permission, and literal queue ownership, and add the model-8 conditional adoption sequence to the prerelease rollout guide.
28
+
29
+ - b0b1550: **BREAKING:** Product-prefixed telemetry events now use `Workflows <event>` instead of `Editorial Workflows <event>`; `EditorialWorkflowsResource` is replaced by `WorkflowsResource`; and `defineWorkflows` now generates `workflows-<deployment name>` resource names instead of `editorial-workflows-<deployment name>`. Telemetry consumers matching the previous literals stop receiving events until updated, TypeScript consumers importing the previous Blueprint interface no longer compile, and an existing Blueprint stack that relies on the generated name treats the new default as a different resource identity.
30
+
31
+ Update telemetry dashboards, schemas, alerts, and queries to match the `Workflows` prefix; event suffixes, payloads, and versions are unchanged. Replace Blueprint imports with `WorkflowsResource`. Before deploying an existing Blueprint stack, either pass its recorded resource name explicitly or plan the detach-and-create migration to the new default. Workflows request-tag families and billing classification are unchanged.
32
+
33
+ Other user-facing package copy now uses the Workflows product name. No upgrade action is required for consumers that do not match telemetry event names or use the Blueprint package.
34
+
35
+ **Docs impact:** Rename the product throughout the public documentation, move the docs section to `/docs/workflows/*` with permanent redirects from every `/docs/editorial-workflows/*` path, and document the telemetry-prefix, `WorkflowsResource`, and Blueprint resource-name migrations in the telemetry reference, Blueprint guide, and release notes.
36
+
37
+ ### Patch Changes
38
+
39
+ - 210ca63: The API documentation shipped in every package's `.d.ts` files is rewritten to be substantially terser: multi-paragraph doc comments are cut to the facts a consumer needs, and internal narration no longer appears in editor hover text. Runtime behavior, exports, and type signatures are unchanged across the whole package group.
40
+
41
+ **No upgrade action required.**
42
+
43
+ **Docs impact: None** — the published documentation site is authored separately; only in-editor `.d.ts` hover text changes.
44
+
45
+ - a3a8dc0: `readInstancePreviewDoc` now takes an untyped lake row. A preview page slot without a string `_id` fails as a shape error named `(unknown id)` instead of being assumed to have an id for the model gate.
46
+
47
+ **No upgrade action required.** Callers that already passed `{_id: string}` continue to type-check.
48
+
49
+ **Docs impact:** None. The preview-row funnel is unchanged for well-formed rows; only the untyped input is honest.
50
+
51
+ - Updated dependencies [210ca63]
52
+ - @sanity/groq-condition-describe@0.4.1
53
+
3
54
  ## 0.29.0
4
55
 
5
56
  ### Minor Changes
package/DATAMODEL.md CHANGED
@@ -72,10 +72,12 @@ never matches the new type).
72
72
  the shape, so restamping there would lie.
73
73
  - **`minReaderModel` — the document's reader floor.** The oldest engine model
74
74
  that can safely _interpret this particular document_. Writers derive it
75
- from compatibility-bearing features present in the canonical stored tree.
76
- `DATA_MODEL_MIN_READER` is the maximum floor the current writer can emit,
77
- not a value stamped on every document. Additive features contribute floor
78
- 0; only an incompatible feature fences older readers out of that document.
75
+ from compatibility-bearing features present in the canonical stored tree,
76
+ while retaining the unconditional `DATA_MODEL_MIN_READER` baseline of 4.
77
+ `DATA_MODEL_MAX_READER` is the maximum floor the current writer can emit.
78
+ A deployment acknowledges the highest reader model verified
79
+ for its shared runtimes, and the writer compares it with the submitted
80
+ definitions' required floor.
79
81
  - **Missing stamp = model 0** (floor 0) — the document was last written
80
82
  before the stamp existed. A `modelVersion` with no `minReaderModel` is
81
83
  malformed foreign data and gates conservatively: the stamp is the floor.
@@ -138,13 +140,12 @@ never matches the new type).
138
140
  requirement may still require it. (The failure mode this fences off is
139
141
  documented across the industry: a rewriter that drops the compatibility
140
142
  gate it doesn't understand silently reopens the door the floor closed.)
141
- - **Raising the floor is an availability decision, sequenced readers-first.**
142
- Before any writer that raises `DATA_MODEL_MIN_READER` deploys, every
143
- reader in the fleet — customer-deployed Functions foremost — must already
144
- run an engine at or above the new floor (the BACKWARD deployment order:
145
- upgrade consumers before producers). And like every engine-side check the
146
- floor is advisory — it gates our own clients; the Content Lake stays the
147
- sole enforcement point.
143
+ - **Persisting a floor-bearing feature is an availability decision.** Before a
144
+ definition using that feature deploys, every reader sharing its workflow
145
+ resource — customer-deployed Functions foremost — must run an engine at or
146
+ above the feature's floor. Increasing the writer's maximum alone requires no
147
+ coordinated rollout. Like every engine-side check, the floor is advisory —
148
+ it gates our own clients; the Content Lake stays the sole enforcement point.
148
149
  - **The gate ships from the engine.** `assertReadableModel`, the parse
149
150
  functions, and the error classes are exported from
150
151
  `@sanity/workflow-engine`, so every consumer surface composes the same
@@ -224,8 +225,9 @@ floor only when its stable marker is present in the canonical stored tree. An
224
225
  of its declared type when no reliable marker exists. Readers trust the
225
226
  persisted floor; they do not recompute features they may be too old to know.
226
227
  Every reader-floor increase is represented as a manifest feature and classified
227
- this way; raising the package maximum never by itself raises every document's
228
- floor.
228
+ this way. Raising `DATA_MODEL_MAX_READER` expands what the writer may emit; a
229
+ detectable feature raises only documents carrying its stable marker above the
230
+ retained model-4 baseline.
229
231
 
230
232
  1. **Any change to a persisted field tree is a model change** and must be
231
233
  declared: update the model-surface snapshot, add an entry to the model
@@ -233,16 +235,16 @@ floor.
233
235
  moves **and whether the reader floor moves with it**. Nothing lands
234
236
  "incidentally".
235
237
  2. **Additive optional fields are allowed** without machinery: bump
236
- `DATA_MODEL_VERSION`, leave `DATA_MODEL_MIN_READER` untouched, and
238
+ `DATA_MODEL_VERSION`, leave the reader constants untouched, and
237
239
  declare the tolerant read (what an absent value means on docs written
238
240
  before the field existed) plus why the field survives an old writer's
239
241
  round-trip.
240
242
  3. **Renames, removals, and semantic changes are not allowed yet.** They
241
243
  require versioned upgrade machinery (per-model normalization steps applied
242
244
  on read) that does not exist; until it does, the model may only grow
243
- additively. When such a change eventually lands, it raises
244
- `DATA_MODEL_MIN_READER` a declared fence against older readers, shipped
245
- only after the fleet story is written.
245
+ additively. When such a change eventually lands, it raises the affected
246
+ documents' reader floor through `DATA_MODEL_MIN_READER` when no reliable
247
+ marker exists — and ships only after the fleet story is written.
246
248
  4. **`DATA_MODEL_VERSION` moves when compatibility reasoning changes** — when
247
249
  a reader would need to know which shape it is looking at. A purely
248
250
  internal refactor that provably writes an identical tree does not bump.
@@ -251,7 +253,7 @@ floor.
251
253
  change the MEANING of existing fields — old readers parse it fine and
252
254
  silently misinterpret. That judgment (would an old reader misread, not
253
255
  just fail to parse?) is exactly what decides whether
254
- `DATA_MODEL_MIN_READER` moves, and no snapshot can make it — each model
256
+ a feature floor moves, and no snapshot can make it — each model
255
257
  log entry states it explicitly.
256
258
  6. **Manifest and prose move together.** Every structural model change adds a
257
259
  manifest entry and matching model-log declaration. The ledger snapshots
@@ -619,7 +621,7 @@ older engine's project-scoped actor silently evaluates false (and the
619
621
  mirror-image for legacy values under a new actor). Misinterpretation, not
620
622
  parse failure — exactly the case the floor exists for. `minReaderModel: 4`
621
623
  makes pre-classifier engines refuse the document loudly instead. The writer
622
- maximum (`DATA_MODEL_MIN_READER`) rises to 4; deployment acknowledgements
624
+ baseline (`DATA_MODEL_MIN_READER`) rises to 4; deployment acknowledgements
623
625
  follow the readers-first rollout (`docs/reader-model-rollout.md`).
624
626
 
625
627
  Manifest feature: `classified-principal-ids` (instance, reader-floor,
@@ -702,7 +704,7 @@ its base `date` / `datetime`, so no older code path can write it while skipping
702
704
  validation — there is no silent bypass to fence, and the kinds leave the floor
703
705
  at 0.
704
706
 
705
- ### Model 6 — node semantics and field patch operations (reader floor: 4)
707
+ ### Model 6 — node semantics and field patch operations
706
708
 
707
709
  #### Semantics at every definition level
708
710
 
@@ -751,8 +753,8 @@ execution with different semantics. Definition documents are create-only,
751
753
  instance persists preserve the opaque `definitionSnapshot` string, and history
752
754
  readers already treat `opType` as an opaque audit label, so the discriminator
753
755
  survives an old writer's round trip. Rule 5 fences silent misinterpretation,
754
- not loud refusal, therefore this detectable feature contributes floor 0 and the
755
- writer maximum remains 4. The floor does not protect these definitions from
756
+ not loud refusal, therefore this detectable feature contributes floor 0 and does
757
+ not raise the writer maximum. The floor does not protect these definitions from
756
758
  older runtimes: upgrade every runtime that can process shared workflow data
757
759
  before adopting the new ops.
758
760
 
@@ -809,6 +811,49 @@ predicate” to “the synthetic User Attributes bag” with no redeploy. Likely
809
811
  zero real instances; no migration. Authors who hit it rename the predicate
810
812
  and redeploy.
811
813
 
814
+ ### Model 8 — role-constrained assignment fields (reader floor: 8)
815
+
816
+ Assignment-valued field shapes may carry a non-empty `roles` list. The facet
817
+ limits newly written user assignees to project members who fulfil at least one
818
+ listed role, including the definition's role aliases. A collective role
819
+ assignee remains ownership rather than capability and is eligible only when
820
+ its literal role is listed. An absent facet preserves the historical
821
+ unconstrained meaning.
822
+
823
+ Freshly resolved values and singular replacements validate the complete
824
+ assignment. For plural and composite replacements, stale retention is
825
+ count-bounded per declared assignment location: a candidate may retain no more
826
+ occurrences of one assignment identity than the previous value held at that
827
+ location. Array indices are not part of the location, so removal and reordering
828
+ do not make surviving assignments new; an added copy exceeds the previous count
829
+ and must qualify. An `updateWhere` merge validates every assignment location
830
+ present in its incoming fragment strictly, so a fragment must omit rather than
831
+ restate a stale assignment. Each top-level engine verb uses one project-directory
832
+ snapshot across retries, cascade hops, and spawned children; a later verb reads
833
+ a fresh snapshot.
834
+
835
+ The property is valid on `assignee` and `assignees` wherever field shapes are
836
+ declared: scope fields, nested object/array shapes, and effect outputs. This
837
+ follows the definition language's existing facet vocabulary: as `types` says
838
+ which documents may occupy a reference slot, `roles` says which people or
839
+ collective roles may occupy an assignment slot. The existing vocabulary could
840
+ not carry this behavior because `editable` governs who may mutate a field,
841
+ while action `roles` governs who may act; neither describes eligible field
842
+ values.
843
+
844
+ Both stamped trees grow the property: definitions persist it on field shapes,
845
+ and instances copy it onto resolved assignment entries so later writes remain
846
+ self-describing. Model-6 and model-7 writers shipped without this behavior. An
847
+ older reader would preserve the unknown property but silently accept an
848
+ assignee the declaration excludes, so the facet is appended at model 8 rather
849
+ than backfilled into either shipped ledger.
850
+
851
+ Manifest feature: `role-constrained-assignment-fields` (definition + instance,
852
+ reader-floor, detectable, floor 8). A submitted definition set carrying the
853
+ facet requires acknowledgement 8; a set without it may retain acknowledgement 4. Documents without the facet retain the model-4 floor; only definitions and
854
+ instances whose canonical field tree carries a non-empty `roles` list stamp
855
+ floor 8.
856
+
812
857
  ## Pending governed changes
813
858
 
814
859
  - **`temp.system.guard` → `system.guard`** — the guard doc type's `temp.`