The store seam's one write primitive: make the document exist in the
representations the engine's field hydration reads (drafts-over-published,
or the release's version docs when releaseId is set — the matrix lives
on the shared ensureDocumentExists implementation). Resolves once the
write is committed, so a start flow can call it and then startInstance
without racing the lake. Addresses the adapter's own content dataset
(Studio: the mounted workspace; SDK: the instance's configured dataset).
One-shot page fetch for the engine's instancePreviewsQuery reads, returning
raw results; the react layer parses per row. One-shot by design: hydrated
pages are kept fresh by WorkflowObserver.listenInstanceChanges
refetches, never by re-running page queries.
Subscribe to the engine dataset's instance-change feed (the engine's
instanceChangesQuery). The adapter holds one upstream listener per
feed however many stores subscribe. A listener error never throws: the
adapter reconnects with backoff and then emits a reset event, on which
a consumer resynchronizes whatever the gap missed. Returns the
unsubscribe.
The instance's live mutation guards (temp.system.guard docs keyed by
sourceInstanceId). A standalone stream — the engine excludes guards from
the session's SubscriptionDocument set, so the adapter watches them
separately; the hook surfaces the list and feeds it to the session
(updateGuards) so evaluation re-runs as guards are deployed / deleted. Use
the engine's instancesGuardQuery to build the per-resource query.
Must start in loading, like observeDocs, and leave it on a value,
validation failure, or read error, so the hook can distinguish a pending
read from resolved-no-guards and gate readiness. A resolved-empty snapshot should be the shared
NO_GUARDS identity.
Guards co-locate with the subjects they lock, so they're spread across the
resources the instance's currently-observed GDRs name; resources holds
that set (engine dataset ∪ each open-stage/workflow-scope subject dataset,
from guardResourcesFor, which is where guards that can deny right
now live). The adapter subscribes one guard stream per resource and merges
them (combineGuardStores); a dataset resource foreign to the
store's own binding is reached the same way observeDocs reaches a foreign
content ref.
sharedIds is the consolidation seam: the id-set of every co-mounted
session, handed identically to each one, so an adapter can subscribe one
set-shaped live query per resource (the engine's instancesGuardQuery)
instead of one per instance, fanning results back out per
sourceInstanceId. The returned stream still holds only this
instance's guards. The set must include instanceId — its rows could
never arrive otherwise, so adapters reject the call rather than resolve
a vacuously empty stream. Omitted, the adapter subscribes for this
instance alone.
A live instance-list read against the engine's workflow resource. The
CompiledQuery comes from the engine's instancesQuery, so the
stateless and reactive paths see the same rows. Single-resource by
definition — instances live only in the engine's own dataset. The snapshot
starts in loading ("still discovering" and
"confirmed none" must be distinguishable), then becomes the matching
ObservedInstances snapshot (readable rows in instances,
refused rows flagged per row in unreadable), an invalid result, or a
read error, and remains reactive.
Store-specific observation, supplied by an adapter (
@sanity/workflow-sdk/@sanity/workflow-studio). The engine session is store-agnostic; only these two reads differ between the App SDK and Studio document stores. Both start inloadingand leave it on a value, validation failure, or read error, so the session is never fed a half-synced set, and resolve content docs to the perspective's release form (instance / ancestor /system.releasedocs read raw). Adapters typically buildobserveDocsfrom combineDocStores over a per-doc primitive.