App release manifests
Validate the immutable release and permitted ontology resources of an operational app.
App release manifests
An app definition identifies its owner, organization, workspace, environment, audience, and published or withdrawn status. Its release records an immutable source digest, dependency artifact digest, runtime image digest, widget digest, and exact ontology schema revisions. The app release ID is distinct from an ontology revision ID.
New releases also bind runtime.dependencyDigest: the verified environment intent
under the pinned image. This differs from dependencies.sha256, which identifies
the resolved package archive. Runtime startup needs both; it restores the archive
without resolving packages again or consulting the author's preparation session.
Older manifests remain readable with their original hashes, but a release missing
this binding requires fresh validation and publication before it can run or become
a rollback target. Reconciliation of an already committed publication still works.
The browser-safe schemas are exported by @scrydon/ontology-sdk/client and
@scrydon/sdk-authoring/ontologies/manifest:
import {
AppPayloadSchema,
AppReleaseSchema,
AppPermitSchema,
} from "@scrydon/ontology-sdk/client";
const definition = AppPayloadSchema.parse(receivedDefinition);
const release = AppReleaseSchema.parse(definition.release);
const permit = AppPermitSchema.parse(release.permit);Parsing validates the contract. It does not publish the app, validate the stored artifact bytes, or authorize a viewer. App definitions require the app lifecycle workflow; generic schema declarations, branch edits, and schema proposals cannot publish or withdraw them.
Lifecycle inputs are validated with AppPublishInputSchema,
AppRollbackInputSchema, and AppWithdrawInputSchema. Publication takes a saved
candidate, release notes, validation evidence from the trusted control plane,
and expectedStateId (null only for the first publication). The server derives
the owner, publisher, release ID, timestamp, and tenant. A parsed candidate or a
client-generated digest cannot replace validation evidence.
expectedStateId identifies the current lifecycle fact, rather than only its
release: rolling back to an earlier release still creates a new state. A stale
state returns a conflict. Retrying the same action with its original idempotency
key returns its original result; changing that request requires a new key.
Rollback requires fresh validation of a retained release. It preserves the
current audience, ownership, and app metadata. Withdrawal retains immutable
artifacts and increments revocationEpoch; republishing preserves that counter
so previously revoked sessions cannot become valid again.
The permit contains these explicit declarations:
For a marimo-authored app, write the requested access in the saved notebook
with the Python SDK's apps.declare(...) and apps.ontology, apps.query,
apps.link, apps.allow_action, and apps.allow_watch helpers. The publisher
statically compiles literal calls, resolves accessible published ontology pins,
and shows the resulting permit for review. Runtime values and arbitrary Python
expressions are not publication declarations. The helpers themselves perform
no data reads, grants, action submissions, or watch installation. See the
marimo authoring guide for an example.
| Field | Contents |
|---|---|
ontologies | Local alias, ontology name, exact revision ID, and content hash |
queries | Query ID, ontology alias, object type, visible properties, base filters, allowed dynamic filter properties, result limit, live/required flags, and freshness bounds |
links | Link type and named source/target queries in the same declared ontology |
actions | Action reference, allowed input property names, input byte limit, and required flag |
watches | Watch references and required flags |
Property wildcards and undeclared ontology aliases are rejected. Base filters are mandatory constraints; additional viewer filters may only narrow them. Runtime operations must intersect this permit with the viewer's current permissions and the source's current policy. Schema pins do not freeze live data or preserve revoked permissions.
Authority identifiers, resource references, and base filter values must use Unicode NFC. Noncanonical values are rejected so manifest sealing cannot silently select a different user, tenant, resource, or source value.
Action declarations refer to executable authored ontology actions, not kernel
management operations. Inputs are limited to declared names, the action's typed
field contract, and maxInputBytes (at most 16 KiB). Existing human approval
requirements still apply. Declaring an action does not execute it or authorize it.
Action strings must be valid PostgreSQL UTF-8 text: NUL and unpaired Unicode
surrogates are rejected before submission or intent storage. SDK integrators can
reuse the browser-safe postgresTextIssue helper from @scrydon/common/postgres-text;
it returns null for accepted text and an issue description otherwise. It does
not normalize or change the supplied text.
AppActionInputSchema and AppActionResultSchema describe the private control-plane
contract. KernelClient.apps.submitAction and actionResult are restricted to
Analytics forwarding an authenticated viewer; they are not notebook or browser
APIs. The result contains only unknown, committed with an action ID, or
rejected with a kernel code. Reconciliation is read-only: a timeout or unknown
result must never trigger automatic resubmission. The private viewer-session
commands persist each request before a submission attempt; repeating that request
only reconciles its result. At most 256 action requests are retained per viewer
session, and reaching that limit returns 429 without erasing earlier requests.
The notebook apps.action and apps.alerts controls use Horizon's trusted
confirmation journey. For watch detections, use the
acknowledgement behavior to record
the authenticated operator and time without replacing detection evidence.
Audience selectors are workspace or users with an explicit list of user IDs.
Separate discover and run selectors describe intended access within the app's
tenant. Neither selector grants permissions to underlying data or actions.
Artifact references contain sha256 and sizeBytes. Storage locations are
derived by the platform rather than supplied as arbitrary URLs. Source artifacts
are limited to 1 MiB; dependency artifacts to 512 MiB. Each permit supports up to
32 ontology dependencies and 64 declarations per query, link, action, or watch
category. Queries have explicit result limits of at most 10,000 objects.
Ontology revision manifests carry app definitions in the optional apps bucket
and watches in watches. Older manifests omit these fields; callers should read
an omitted bucket as an empty list without adding fields to the stored document
or recomputing its hash.