Skip to main content
Version: 0.1.0-alpha.5 (alpha)

Publication selection in management APIs

The publication API implements the public identity separation in RFC-0002. A component digest still identifies executable bytes. A package digest identifies immutable package content, and a publication reference identifies its catalog association. None of these identifiers is an execution grant.

Release requests and results​

PublicationRef contains an exact publication:sha256: ID and its tenant. Public release-management requests require an exact publication whose tenant matches the authenticated scope before lookup. Missing or invalid references are rejected. The obsolete component-only digest input is removed; field 1 and its name are reserved in the four release query/mutation request messages.

Get, lifecycle inspection, revoke, retire and evidence renewal accept the exact reference. Release descriptors, lifecycle records and operation receipts report their captured publication. Descriptors also expose a package digest when the source is an actual package; a trusted-local upload does not invent one. Operation lookup and replay retain the original association after coexistence.

The CLI accepts latent release get --publication PUBLICATION_ID, and the same selector on lifecycle, revoke, retire and renew-evidence. Tenant comes from the selected client profile. Positional component digests are rejected before network dispatch. Mutation operation IDs and generation comparisons remain explicit. JSON output keeps publication, package and component identities separate and preserves counters as decimal strings.

Retain the publication ID returned by admission or choose an exact entry from the authenticated release list. A component checksum cannot identify an association, even when the current catalog happens to contain only one match. Foreign and missing publication IDs both return NotFound within the authorized scope; errors do not enumerate candidates.

Deployment requests and results​

On Apply input, Deployment.publication is required and Deployment.release_digest must be empty. Optional ApplyDeploymentRequest.expected_component_digest asserts which executable that publication must contain. Missing publication references and component-only requests fail before lookup or mutation, even when only one publication exists. The server resolves the exact reference before mutation; the catalog rechecks current eligibility at commit.

On output, Deployment.publication reports the captured tenant publication, while release_digest reports its component. Output-only requested_publication preserves the caller's original manifest selector. To reapply a response, retain its publication, clear release_digest, omit requested_publication, and pass the component as expected_component_digest when that assertion is wanted.

CLI apply and rollout candidate manifests require both spec.release and spec.publication. Select the publication returned by admission; the CLI converts spec.release into a checksum assertion and rejects a missing publication before network dispatch. It also rejects a reply that substitutes another publication with the same executable component.

Get, bounded lists, managed Apply replies and operation lookup use the captured association. Managed replay preserves the original manifest, publication, receipt and generations even after deletion or revocation. Replay does not install the historical deployment again. An unscoped local publication cannot be submitted as a tenant publication or selected through a component fallback.

Recovery and current contracts​

Deployment operation table format 2 stores the full captured publication reference alongside each unchanged format-1 receipt. The enclosing catalog checksum covers that association. Receipt canonical bytes and receipt_digest retain their previous meaning; they do not alone authenticate the additive publication reference. Protected catalog ownership remains required.

Startup requires operation table format 2. Obsolete format-1 tables are rejected without inventing publication associations or rewriting catalog bytes. Receipt format 1 remains the current receipt encoding; it is independent of the table version. Current tables preserve request hashes, receipt bytes, CAS versions and object generations across restart. See the deployment storage contract for accepted catalog and rollout-plan versions.

The publication schema, release lifecycle schema, Protobuf descriptor contract and conformance fixtures cover presence and exact publication identity. Generated Rust bindings are built from the authoritative Protobuf files. All six executable SDK clients use the same current management profile. The artifact catalog API takes PublicationRef directly; the obsolete component-or-publication selector has been removed.

RequestCurrent behavior
Missing publication or component-only selectorRejected before lookup or mutation.
Exact publication with optional component assertionSelects the authenticated tenant publication; an assertion must match.
Exact operation replayReturns captured history without applying it again.
Unsupported stored catalog formatRejected without implicit catalog admission; use fresh alpha state.

Obsolete release-root formats are unsupported. Follow the fresh-state procedure for a new installation. A nonempty obsolete root cannot become a newly admitted publication catalog. Current deployment operation-table validation remains separate from retired release-root formats.

Rollout and invocation receipts​

StartRollout requires the same exact selector in its candidate Deployment. Its optional expected_candidate_component_digest is a checksum assertion, with an empty candidate release_digest, just as on Apply. CLI candidate manifests retain spec.release and spec.publication; the CLI constructs that request. Get, list, operation lookup and rollback preserve the captured base and candidate publication IDs, including when both have the same component digest. Revoking the candidate does not revoke the base. Historical replay returns its original receipt without installing that candidate again. Status objects contains the currently surviving objects in the authenticated tenant, from zero to two. The historical base/candidate remain visible after completion, rollback or deletion; reusing an old object ID in another tenant does not disclose its generation.

Rollout status and receipts expose publication_id, base_publication_id and candidate_publication_id as applicable. These are source identities, including a possible internal unscoped source; they do not assert tenant admission. Tenant scope on the enclosing operation still controls access. Rollout receipt canonical bytes remain unchanged. Their retained version-2 plan digest binds both captured IDs; recovery hydrates additive receipt fields from that bounded retained plan. Audit records also carry the captured pair. Pre-upgrade audit attempts retain their original bytes and can reconcile without invented historical fields.

InvokeResponse field 10, optional publication_id, reports the actual source captured by route resolution. Its existing release_digest field still means component bytes. Publication selection happens through the deployed revision and route; an ID in a receipt grants no direct execution permission. Currentness is checked at activation start. A failure before route resolution has no publication or revision pin. An old response may omit the publication; a present empty or malformed ID fails validation. CLI JSON reports resolvedRevision.publicationId without converting 64-bit generations or consumption into floating point.

Six-language models and operator verification​

The SDK models expose PublicationRef, PublicationIdentity and optional invocation publication IDs. The obsolete component-or-publication ReleaseSelector has been removed from all six facades and generated common profiles. Requests use the method's exact publication reference. This does not add a direct Invoke selector. Executable clients reuse the authoritative Protobuf identities.

The bounded publication workflow runs real CLI and node processes against fresh signed test packages. Its fixture exporter corrects an embedded SBOM while retaining identical Wasm and capsule metadata. It publishes both packages independently in two tenants, deploys every exact publication, invokes it, restarts and inspects/replays original operations, revokes one candidate, rolls back to its eligible captured base, renews another tenant's evidence, and restarts again. It also checks component-only request rejection, foreign versus missing references, audit identities and clean process reaping.

CI runs this against its existing built binaries and an explicit fresh fixture:

LSF_OPERATOR_FIXTURE_ROOT="$FIXTURE" python3 tools/ci_rust_artifacts.py \
--inventory "$INVENTORY" --suite publication-fixture
python3 tools/run_publication_workflow.py --cli target/debug/latent \
--node target/debug/latentd --fixture-root "$FIXTURE" --source-commit "$GITHUB_SHA"

$FIXTURE must be a nonexistent child of an owned private temporary directory. The runner requires Linux and Python 3.13, caps itself at 180 seconds and 160 CLI processes, removes temporary node data and emits a receipt of at most 64 KiB. The fresh exporter supplies synthetic signed test observations, not production build provenance. No registry or 100,000-request load is involved. For an upgrade, stop the node, back up catalogs and protected trust/configuration files, inspect the listed publication/package/component associations, migrate manifests to the exact desired IDs and restart after the enforced admission clock floor (up to five seconds after stopping the prior owner). Keep original operation IDs for recovery; do not retry an uncertain mutation under a new ID merely because a response was lost.