Release Seal Aggregate API
POST /api/v1/release-orchestrator/releases/seal creates or re-reads a sealed release in one deterministic call for operator and fixture harnesses that should not manage the create, ready, approval-truth, and deploy-dispatch calls separately.
Authorization
Requires ReleaseOrchestratorPolicies.ReleaseApprove (release:publish). The aggregate uses the strictest scope from the composed release lifecycle operations and does not accept release:read or release:write alone.
The route is tenant-scoped through the standard Release Orchestrator tenant filter. Tenant resolution follows the shared auth integration tenant resolver and accepts the normal Stella Ops tenant headers/claims.
Request
{
"releaseRequest": {
"name": "tier4-golden-001",
"version": "v0.0.1-golden",
"targetEnvironment": "tenant-tier4-w1-run-a",
"deploymentStrategy": "rolling",
"components": [
{
"name": "checkout-api",
"imageRef": "registry.local/stellaops/checkout-api",
"digest": "sha256:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
"tag": "v0.0.1-golden",
"version": "v0.0.1-golden",
"type": "image"
}
]
},
"evidenceBundleId": "bundle-golden-001",
"fixtureId": "tier4-golden"
}
releaseRequest is create-release compatible, with components added for the aggregate because the canonical ready transition rejects componentless releases.
The idempotency key is the SHA-256 hash of normalized (name, version, tenant). Reposting the same release name/version for the same tenant returns the previously sealed release without dispatching a second deployment.
Response
First seal returns 202 Accepted; an idempotent re-seal returns 200 OK.
{
"status": "release-seal-accepted",
"releaseId": "rel-...",
"sealedAt": "2026-05-18T10:30:00Z",
"deploymentId": "dep-...",
"evidenceBundleId": "bundle-golden-001",
"dsseDigest": "sha256:...",
"tenant": "tenant-release-seal",
"fixtureId": "tier4-golden",
"ledgerStatus": "deployed"
}
status is a stable contract string. dsseDigest is the SHA-256 digest of the canonical release-seal evidence packet persisted as recorded, integrity-checked release evidence and bound to evidenceBundleId. The aggregate does not sign the packet, so it is not verified evidence.
Errors
| Status | Condition |
|---|---|
400 | Missing request body, releaseRequest, releaseRequest.name, releaseRequest.version, releaseRequest.targetEnvironment, evidenceBundleId, or required component fields. |
403 | Caller lacks release:publish. |
409 | Existing release truth, approval truth, gate truth, or evidence truth blocks deployment dispatch. |
State Effects
On first seal the endpoint:
- creates or resumes the release row,
- upserts deterministic component rows,
- drives the existing Draft -> Ready validator,
- writes recorded
release-sealevidence (canonical SHA-256 integrity, no signature and therefore not verified), - writes approved approval and passing gate-decision truth for the publish-authorized aggregate,
- dispatches deployment through the same deploy-engine/fallback boundary as release deploy,
- records the release as
deployedand appends asealedrelease event.
The existing rollback endpoint remains unchanged: POST /api/v1/release-orchestrator/releases/{id}/rollback.
