Promotion and release
What promotion decides, why it has to be bound to an assembly, and what a release digest is actually claiming.
Promotion turns a validated document into a signed release. It is where a granted capability://
reference becomes a concrete action id and version, which makes it the moment worth being careful
about.
Promotion must name its assembly
Routes are compiled from usage contracts. Those contracts decide which action a granted reference resolves to, so they cannot be supplied on trust.
await promoteExperienceRelease({
application,
release,
contracts,
assembly, // the lockfile the release was validated against
issuer,
signer,
});Every contract digest is checked against what that assembly approved. Without it, a substituted
contract could remap an already-granted reference onto a different installed action while the release
kept its original assembly digest. PlatformHost would still authorize that action, which makes it
an integrity failure of what the release exposes rather than an authorization bypass — and the kind
that is invisible downstream.
What the digest claims
A release digest covers the document, its variants, the resolved token set, the locked packs and their remotes, the grants including per-fragment narrowing, and the assembly digest. Two releases differing in any of those cannot share a digest.
It is canonical: reference lists are sorted, variants are ordered by id, and fields absent from a release are omitted rather than hashed as empty. A document that declares no variants digests exactly as it did before variants existed, so earlier releases keep verifying.
The digest identifies what a viewer received. Every design decision above protects that property, which is why multi-brand is several releases rather than several token sets in one.
Signing keys are not configuration
fabric-gen promote-experience --config fabric.promotion.json --key ./signing.pemThe key is a command-line argument, and a promotion configuration carrying one is refused. A configuration file is the kind of thing that ends up committed.
Verify before deploy
fabric-gen check-application --config fabric.application.jsonChecks that every release is intact and belongs to the assembly the runtime will load, and that the runtime's capability versions match what the lockfile resolved. Run it in the deploy pipeline, not only at build.