#AI#大模型#DevOps

AI Runtime Safety Decision Receipts: Binding the Policy Decision to Actual Execution

A policy engine returning allow doesn't mean downstream executes with the same input and obligations. This article defines a verifiable decision receipt, a one-time acceptance point, and execution confirmation to block stale policy, parameter substitution, and fail-open bypass.

Key Points

  • Topic Focus: AI、大模型、DevOps
  • Suitable for: indie hackers, full-stack engineers, AI application developers
  • Core value: quickly understand background, practical paths, common pitfalls, and engineering advice
Author @admin·Published July 26, 2026·Updated July 26, 2026

A content classifier saying "low risk" or a policy service returning allow=true does not prove the system ultimately executed on that conclusion. Downstream may have swapped the Prompt, ignored the "must not call external tools" obligation, or carried forward stale cache after policy expiry. AI Content Moderation Systems explains how to produce risk signals, and LLM Gateway Routing Policy selects providers and models; this article only closes the gap after both: the bytes the decision was based on must match the execution that is actually accepted.

Receipts bind facts, they don't restate logs

OPA's decision log can carry the decision ID, bundle revision, input, and result, but log delivery is an observation pipeline, not an execution transaction. The platform should have a trusted decider sign ai.safetyDecisionReceipt.v1, including at minimum decisionId, tenant and subject references, normalized action, target resource digest and version, executor audience, executionPlanDigest, inputDigest, risk signal set digest, policy bundle ID and content digest, data snapshot, result, obligations, authz epoch, validity period, a one-time enforcementNonce, issuer key ID, and time. Raw Prompts, user identities, and secrets do not enter the receipt.

yaml
schema: ai.safetyDecisionReceipt.v1
decisionId: dec_01JZ8Y
action: model.generate.v3
executorAudience: inference-executor-prod
target: { digest: sha256:ef4..., version: "37" }
executionPlanDigest: sha256:902...
inputDigest: sha256:31c...
signalSetDigest: sha256:81a...
policyBundle: { id: safety-prod, digest: sha256:72e... }
dataSnapshot: sha256:6df...
authzEpoch: 1842
decision: ALLOW
obligations:
  - { id: tools.disable, parametersDigest: sha256:b12... }
validUntil: 2026-07-19T10:02:00Z
enforcementNonce: 9ec1...
issuerKid: safety-decision-2026-07

Input normalization must freeze field types, Unicode, and numeric representations, so the decider and executor can't serialize separately. executionPlanDigest covers model routing, Prompt bundle, tool permissions, and side-effect targets; a mismatched target version or audience must not allow swapping in another executor. The bundle revision is only a label; you must also record the verified content digest. Dynamic lists, tenant tiers, and regional rules belong in dataSnapshot, otherwise the same policy could still recompute to different answers. The safety receipt also does not replace Cloud Control Plane Audit Integrity: the former proves a single data-plane acceptance, the latter proves high-value configuration changes were not lost.

Connect execution with a one-time acceptance point

The state machine is fixed to RECEIVED -> EVALUATED -> ISSUED -> CLAIMED -> EXECUTING -> OUTPUT_QUARANTINED -> OBLIGATIONS_APPLIED -> RELEASED, plus DENIED/DEFERRED/EXPIRED/REJECTED. ALLOW can only become CLAIMED after an executor at the specified audience atomically compares tenant, action, target, execution plan, authz, and policy floor, and consumes the nonce via CAS. The same transaction creates execution/outbox; redelivery only queries that execution.

Each obligation declares a PRE_DISPATCH, POST_GENERATION_PRE_RELEASE, or PERSISTENCE phase; an unknown version is rejected. Tool disabling takes effect before the call; model output and tool results first enter a quarantine zone and must not be returned or persisted until redaction and retention obligations are complete. The executor transitions to OBLIGATIONS_APPLIED via CAS with the bound execution, the original output digest, the obligations digest, and the current generation; only then can it release the redacted result and write enforcementConfirmation.v1. A crash or lost confirmation keeps blocking/reconciliation; it must not bypass-send or re-request a decision.

DENY can directly become terminal; DEFERRED means insufficient evidence, routed to a product-defined safe path, not an implicit allow. When the policy service is unreachable, attributes are missing, the signing key is unknown, the time source is skewed, or the bundle is below the policy floor, high-risk actions must be DEFERRED/DENIED. Low-risk may only use a last-known-good bundle that the manifest explicitly permits and is still within its term; "fail open on error" scattered in code is forbidden. Agent Approval Replay Prevention binds a one-time action the user approved; here, even without human approval, it binds the machine safety decision and execution — the two credentials are not interchangeable.

Verify bypass paths, not the happy path

The failure matrix replaces input digest, falls back the bundle, forges the decision ID, reuses the nonce, elevates the authz epoch, injects unknown obligations, and simulates a redactor crash after model success, a side-channel response attempting to send, a lost confirmation, and an actual model generation error. The expectation is rejection, release blocking, or reconciliation against the original execution; late logs and a shadow ALLOW must not change execution. MCP Audit Logging Design can collect evidence, but tests must still directly assert release and side-effect counts.

The release gate may require: 100% valid receipt coverage for high-risk executions; zero input/model/obligation inconsistency; zero raw result release or persistence before obligations complete; at most one execution per nonce; zero unknown-policy, missing-attribute, or authz fail-open; link p99 increment no more than 20 ms; less than 0.1% non-terminal within two minutes, all going to reconciliation. Thresholds are frozen in advance.

Release first lets the new bundle do shadow decisions only on at least 50,000 desensitized representative requests, comparing old/new results, missing attributes, and obligation support rate by risk category. Then expand real acceptance at 1%, 5%, 25%, keeping the old decider hot-standby. On anomaly, point the policy alias back to the last signed bundle; if the rollback version is below the emergency policy floor, stay denied — do not resurrect revoked rules for availability's sake. All old receipts and confirmations stay immutable; what rolls back is the subsequent issuance path, not history. AI Feature Grayscale and Feature Flags handles traffic switching; here, the nonce, policy floor, and execution binding must still hold independently.

Related

Related Content