Transitions the aggregate ACTIVE → SUSPENDED and cascades to the owned Cryptographic Actor, which is what actually stops the workload: the actor moves to SUSPENDED and its signed effective-status envelope is published, so core-api answers 403 actor-suspended on the next crypto call — including one presented with an already-issued, still-valid JWT — and auth-api answers 401 invalid_client for a new token request.
Nothing is revoked. The Capability Grants, the Actor Credential, the owned Exchange Context and every constraint counter survive the transition untouched, so PATCH /resume restores the same workload rather than provisioning a new one.
The cascade runs inside this request's transaction: if the actor transition is refused, the aggregate is not written. An actor already SUSPENDED is a satisfied step (200, no second write); an actor DISABLED is refused 422 under its OWN problem type, .../terminal-actor-state, so a client can tell “retrying is pointless, revoke instead” from “you sent the wrong verb” without string-matching the detail. The exit is still named in the detail for a human reader.
Idempotent on an already-SUSPENDED aggregate → 422. A concurrent transition answers 422 as well, never 409: the aggregate row is taken under PESSIMISTIC_WRITE, so the second caller blocks and then reads COMMITTED state — an already-SUSPENDED aggregate — and is refused as an invalid transition. The 409 optimistic-lock arm exists on this service but is unreachable from this path.
A body is now REQUIRED, and it carries a mandatory justification (PRD §231, operation 1). reason is recorded verbatim at canonical position 21 of the signed AdminAuditEvent, so an audit row can no longer say that a workload was stopped without saying why. It is bounded at AuditFieldBounds.MAX_REASON_LENGTH (1,000 UTF-8 BYTES, not characters) — the same bound applied before signing, so no accepted value is silently truncated on its way into the preimage — and it is NEVER written to a log line.
Accepting a body introduces two arms this operation did not have: 400 for a blank, absent or over-long reason, and 415 for a request whose Content-Type is not application/json. Every refusal on this path — 404, the two state refusals, the DISABLED-actor refusal and both new ones — records the submitted justification NOWHERE, because the act did not happen. Scope: admin.tenant.internal-use-case.suspend
| Time | Status | User Agent | |
|---|---|---|---|
Retrieving recent requests… | |||