> ## Documentation Index
> Fetch the complete documentation index at: https://docs.phosra.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Submit a signed §8.3.8 enforcement-result receipt

> The enforcing app (gatekeeper) POSTs its OWN signed enforcement_result receipt attesting that it applied a rule. The census VERIFIES the app's RFC 9421 signature (caller must equal the receipt's signer — first-person binding, §8.3.8 cl.1) and RECORDS the receipt verbatim. It does NOT re-sign or append to the Receipt rail.
Three invariants (spec-pinned, non-optional): - §6.2 NOT-A-WRITE: this is the app's attestation, not a policy write. - §10.6 NEVER-GATES-THE-RULE: a missing/rejected confirmation never blocks
  or revives the §8.3.1 rule's enforcement.
- HONEST CEILING (§8.3.8): "reported applied, never proven applied."
The body is the full outer receipt (id, type, spec, body, key_id, sig), not just the inner EnforcementResultBody.


The enforcing app POSTs its **own** signed `enforcement_result` receipt attesting that it
applied a rule. The census verifies the caller's [RFC 9421 signature](/concepts/signing-requests)
(the caller **must equal** the receipt's signer — first-person binding, §8.3.8 cl.1) and
records the receipt verbatim. It does not re-sign or append to the Receipt rail.

The request body is the **full outer receipt** (`id`, `type`, `spec`, `body`, `key_id`,
`sig`), not just the inner `EnforcementResultBody`. Three spec-pinned invariants:

* **§6.2 NOT-A-WRITE** — this is the app's attestation, not a policy write.
* **§10.6 NEVER-GATES-THE-RULE** — a missing or rejected confirmation never blocks or revives
  the rule's enforcement.
* **HONEST CEILING (§8.3.8)** — "reported applied, never proven applied."

## Worked example

The [`@phosra/gatekeeper`](/sdks/mcp-server) SDK is the supported path — `verdict.confirm()`
constructs and signs the receipt, then POSTs it for you:

<CodeGroup>
  ```ts Node (@phosra/gatekeeper — recommended) theme={null}
  import { createGatekeeper } from "@phosra/gatekeeper"

  const gk = createGatekeeper({
    platformDid:          "did:ocss:loopline",
    platformKeyId:        "did:ocss:loopline#2026-06",
    gatekeeperSigningKey: { seed: /* 32-byte Ed25519 seed */ new Uint8Array(32), keyID: "did:ocss:loopline#2026-06" },
    censusBaseUrl:        "https://phosra-api-sandbox-production.up.railway.app",
    trustRootXB64Url:     process.env.PHOSRA_TRUST_ROOT_X!,
    endpointId:           "iGrFqzp43O0S9YTNN2oAT6zMzcugEX_EwZbraWrE1AA",
  })

  const verdict = gk.check("infinite_scroll_block")
  // ...apply the decision at the edge, then attest the outcome:
  await verdict.confirm("applied")   // signs the §8.3.8 receipt + POSTs /enforcement-confirmations
  ```

  ```ts Node (raw — construct + sign the receipt yourself) theme={null}
  import { signRequest, signReceipt, ed25519Sign } from "@openchildsafety/ocss"
  import { randomBytes } from "node:crypto"

  const BASE  = "https://phosra-api-sandbox-production.up.railway.app/api/v1"
  const seed  = new Uint8Array(Buffer.from("bG9vcGxpbmUBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQE", "base64url"))
  const keyID = "did:ocss:loopline#2026-06"
  const key   = { keyId: keyID, sign: (m) => ed25519Sign(seed, m) }

  // rule_ref comes from the enforcement profile's categories[] row you enforced.
  const body = {
    envelope_ref:     "env_abc123",
    rule_ref:         "rr_mia_infinite_scroll",
    enforcement_state: "applied",             // applied | degraded | refused
    applied_at:       new Date().toISOString(),
    method_class:     "platform_gate",         // non-empty when enforcement_state === "applied"
  }
  const receipt = signReceipt("enforcement_result", body, key, new Date(), new Uint8Array(randomBytes(10)))

  const targetURI = BASE + "/enforcement-confirmations", bodyText = JSON.stringify(receipt)
  const headers = signRequest({ method: "POST", targetURI, body: new TextEncoder().encode(bodyText), keyID, seed, created: Math.floor(Date.now() / 1000) })
  headers["Content-Type"] = "application/json"
  const res = await fetch(targetURI, { method: "POST", headers, body: bodyText })
  console.log(res.status)   // 201 recorded, 200 idempotent re-submit
  ```

  ```python Python (raw — sign the receipt + the transport) theme={null}
  # sign_request(...) is the RFC 9421 transport signer from /concepts/signing-requests.
  # sign_receipt(...) below signs the INNER §8.3.8 receipt (JCS over {body, spec, type}).
  import base64, json, os, time, requests
  from cryptography.hazmat.primitives.asymmetric.ed25519 import Ed25519PrivateKey

  BASE, SPEC = "https://phosra-api-sandbox-production.up.railway.app/api/v1", "OCSS-v1.0-pre"
  SEED  = "bG9vcGxpbmUBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQE"
  KEYID = "did:ocss:loopline#2026-06"
  _CROCKFORD = "0123456789ABCDEFGHJKMNPQRSTVWXYZ"

  def _b64u(s): return base64.urlsafe_b64decode(s + "=" * (-len(s) % 4))
  def _jcs(v):  return json.dumps(v, sort_keys=True, separators=(",", ":"), ensure_ascii=False)

  def _ulid() -> str:                       # rcpt_ + a Crockford ULID (SDK-compatible shape)
      n = (int(time.time() * 1000) << 80) | int.from_bytes(os.urandom(10), "big")
      return "".join(_CROCKFORD[(n >> (5 * (25 - i))) & 31] for i in range(26))

  def sign_receipt(rtype: str, body: dict) -> dict:
      sk = Ed25519PrivateKey.from_private_bytes(_b64u(SEED))
      sig = sk.sign(_jcs({"body": body, "spec": SPEC, "type": rtype}).encode())
      return {"id": "rcpt_" + _ulid(), "type": rtype, "spec": SPEC, "body": body,
              "key_id": KEYID, "sig": "ed25519:" + base64.urlsafe_b64encode(sig).decode().rstrip("=")}

  # rule_ref MUST be a live per-child ref from a profile you actually enforced (§8.3.8 cl.1).
  receipt = sign_receipt("enforcement_result", {
      "envelope_ref": "env_abc123", "rule_ref": "rr_mia_infinite_scroll",
      "enforcement_state": "applied", "applied_at": "2026-07-06T09:43:59.612Z",
      "method_class": "platform_gate",                # non-empty when state == "applied"
  })
  url  = BASE + "/enforcement-confirmations"
  body = json.dumps(receipt).encode()
  h    = sign_request("POST", url, KEYID, SEED, body); h["Content-Type"] = "application/json"
  print(requests.post(url, data=body, headers=h).status_code)   # 201 recorded, 200 idempotent
  ```

  ```go Go (raw — sign the receipt + the transport) theme={null}
  // SignRequest(...) is the RFC 9421 transport signer from /concepts/signing-requests.
  // signReceipt below signs the INNER §8.3.8 receipt (JCS over {body, spec, type}).
  package main

  import (
  	"bytes"; "crypto/ed25519"; "crypto/rand"; "encoding/base64"; "encoding/json"
  	"fmt"; "io"; "net/http"; "sort"; "strings"; "time"
  )

  const (
  	base  = "https://phosra-api-sandbox-production.up.railway.app/api/v1"
  	spec  = "OCSS-v1.0-pre"
  	seed  = "bG9vcGxpbmUBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQE"
  	keyID = "did:ocss:loopline#2026-06"
  )

  // jcs renders RFC 8785 canonical JSON for the receipt's flat, ASCII value domain.
  func jcs(v any) []byte {
  	switch t := v.(type) {
  	case map[string]any:
  		keys := make([]string, 0, len(t))
  		for k := range t {
  			keys = append(keys, k)
  		}
  		sort.Strings(keys)
  		var b strings.Builder
  		b.WriteByte('{')
  		for i, k := range keys {
  			if i > 0 {
  				b.WriteByte(',')
  			}
  			kb, _ := json.Marshal(k)
  			b.Write(kb)
  			b.WriteByte(':')
  			b.Write(jcs(t[k]))
  		}
  		b.WriteByte('}')
  		return []byte(b.String())
  	default:
  		out, _ := json.Marshal(v)
  		return out
  	}
  }

  func signReceipt(rtype string, body map[string]any) map[string]any {
  	sk := ed25519.NewKeyFromSeed(mustSeed())
  	sig := ed25519.Sign(sk, jcs(map[string]any{"body": body, "spec": spec, "type": rtype}))
  	var ent [10]byte
  	rand.Read(ent[:])
  	id := fmt.Sprintf("rcpt_%d%X", time.Now().UnixMilli(), ent)
  	return map[string]any{"id": id, "type": rtype, "spec": spec, "body": body,
  		"key_id": keyID, "sig": "ed25519:" + base64.RawURLEncoding.EncodeToString(sig)}
  }

  func mustSeed() []byte { s, _ := base64.RawURLEncoding.DecodeString(seed); return s }

  func main() {
  	// rule_ref MUST be a live per-child ref from a profile you enforced (§8.3.8 cl.1).
  	receipt := signReceipt("enforcement_result", map[string]any{
  		"envelope_ref": "env_abc123", "rule_ref": "rr_mia_infinite_scroll",
  		"enforcement_state": "applied", "applied_at": "2026-07-06T09:43:59.612Z",
  		"method_class": "platform_gate",
  	})
  	url := base + "/enforcement-confirmations"
  	body, _ := json.Marshal(receipt)
  	h, _ := SignRequest("POST", url, keyID, seed, body)
  	req, _ := http.NewRequest("POST", url, bytes.NewReader(body))
  	for k, v := range h {
  		req.Header.Set(k, v)
  	}
  	req.Header.Set("Content-Type", "application/json")
  	resp, _ := http.DefaultClient.Do(req)
  	defer resp.Body.Close()
  	b, _ := io.ReadAll(resp.Body)
  	fmt.Println(resp.StatusCode, string(b)) // 201 recorded, 200 idempotent
  }
  ```
</CodeGroup>

<Note>
  The Python/Go `sign_receipt` here is **byte-verified**: signing the receipt body shown in the
  `201` capture below reproduces its exact `sig`
  (`ed25519:mGm30Y7T…`). It is a faithful port of the SDK's `signReceipt` (JCS over
  `{body, spec, type}`, §8.3.8 D-9 boundary). A live `rule_ref` from a profile you actually
  enforced is required — a fabricated one is rejected `401`/`403`, which is why
  `verdict.confirm()` (recommended tab) is the reliable path.
</Note>

## What comes back

The census **records your receipt and echoes it back byte-for-byte** — it never re-signs or
wraps it (§8.3.8 cl.3: the app's own receipt IS the artifact). So the `201` body is the exact
receipt you POSTed. A byte-identical re-submit returns `200` with an `OCSS-Replay: original`
header (the census deduplicates on `rule_ref` + caller DID); the same `rule_ref` with *different*
content is a `409` replay.

<Note>
  The response bodies below are **real wire captures** — a live `did:ocss:loopline`-signed
  `POST /enforcement-confirmations` against the sandbox census
  (`https://phosra-api-sandbox-production.up.railway.app`), then the byte-identical re-POST. Not
  hand-written.
</Note>

```json 201 Created — your receipt, echoed verbatim theme={null}
{
  "id": "rcpt_01KWVD0ABX041061050R3GG28A",
  "type": "enforcement_result",
  "spec": "OCSS-v1.0-pre",
  "body": {
    "applied_at": "2026-07-06T09:43:59.612Z",
    "enforcement_state": "applied",
    "envelope_ref": "env_9f2c1a7e",
    "method_class": "platform_gate",
    "rule_ref": "rr_loopline_infinite_scroll_block"
  },
  "key_id": "did:ocss:loopline#2026-06",
  "sig": "ed25519:mGm30Y7TKrhTnTXH8fq2H8BaaVwFGOJCmJpI_F1hqefhCf9u9I5TRZawk2t12KSiq0pyuCbgzxjeQF11djnUAA"
}
```

```http 200 OK — idempotent re-submit (byte-identical body) theme={null}
HTTP/2 200
content-type: application/json
ocss-replay: original
```

A `409 Conflict` is returned only when the **same `rule_ref` is re-submitted with different
content** (a D-13 replay), never for a faithful re-submit:

```json 409 Conflict — same rule_ref, different content theme={null}
{
  "error": "Conflict",
  "message": "(rule_ref, app_did) replayed with a different enforcement_result (D-13)",
  "code": 409,
  "class": "replay"
}
```

<Note>
  `rule_ref` must be a **live per-child reference** from a profile the caller actually enforced
  (§8.3.8 cl.1 first-person binding); the receipt signer must equal the RFC 9421 caller. A
  fabricated `rule_ref` or a signer/caller mismatch is rejected `401`/`403` — which is why the
  SDK's `verdict.confirm()` (it carries the exact `rule_ref` from the verdict) is the reliable
  path.
</Note>


## OpenAPI

````yaml POST /enforcement-confirmations
openapi: 3.1.0
info:
  title: Phosra OCSS Data Plane — enforcement endpoints, profiles & confirmations
  description: >
    The signed OCSS data-plane the @phosra/gatekeeper SDK drives. These are NOT
    plain REST: profile GETs are RFC 9421-signed by the resolver, binding POSTs
    require accredited caller signatures, and profile responses are
    root-verifiable signed documents consumed via @openchildsafety/ocss /
    @phosra/gatekeeper. This spec documents the wire shapes for client
    generation; it does not change census behavior. The control plane (provider
    org, keys, advisors) is in openapi.control-plane.yaml; the parental-control
    product API is in openapi.yaml.

    Canonical profile shape: `categories[]` (there is no `rules[]` field — it
    does not exist on the wire, in the Go model, or in @phosra/gatekeeper
    types).

    Wire shapes are authoritative from the Go census:
      - profile.Document / CategoryEntry: internal/ocss/profile/document.go
      - EndpointHandlers.Mint / Rotate: internal/ocsshttp/handler_endpoints.go
      - ProfileReads.ServeHTTP: internal/ocsshttp/handler_profiles.go
      - EnforcementHandlers.Confirm: internal/ocsshttp/handler_enforcement.go
      - receipt.Receipt / EnforcementResultBody: internal/ocss/receipt/types.go
  version: 1.0.0
  license:
    name: Proprietary
    url: https://phosra.com/terms
  contact:
    name: Phosra
servers:
  - url: https://phosra-api-sandbox-production.up.railway.app/api/v1
    description: >-
      Hosted sandbox — the one canonical, stable, partner-facing testing
      endpoint
  - url: http://localhost:8080/api/v1
    description: Local development
security: []
paths:
  /enforcement-confirmations:
    post:
      summary: Submit a signed §8.3.8 enforcement-result receipt
      description: >
        The enforcing app (gatekeeper) POSTs its OWN signed enforcement_result
        receipt attesting that it applied a rule. The census VERIFIES the app's
        RFC 9421 signature (caller must equal the receipt's signer —
        first-person binding, §8.3.8 cl.1) and RECORDS the receipt verbatim. It
        does NOT re-sign or append to the Receipt rail.

        Three invariants (spec-pinned, non-optional): - §6.2 NOT-A-WRITE: this
        is the app's attestation, not a policy write. - §10.6
        NEVER-GATES-THE-RULE: a missing/rejected confirmation never blocks
          or revives the §8.3.1 rule's enforcement.
        - HONEST CEILING (§8.3.8): "reported applied, never proven applied."

        The body is the full outer receipt (id, type, spec, body, key_id, sig),
        not just the inner EnforcementResultBody.
      operationId: submitASigned838EnforcementResultReceipt
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/EnforcementReceipt'
      responses:
        '200':
          description: >
            Idempotent re-submit of the **same** receipt (same `(rule_ref,
            app_did)`, byte-identical content). The body is the original receipt
            echoed verbatim — identical to the `201` body — and the response
            carries an `OCSS-Replay: original` header so a client can tell the
            write already landed.
          headers:
            OCSS-Replay:
              description: >-
                Present only on an idempotent replay; always the literal
                `original`.
              schema:
                type: string
                enum:
                  - original
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/EnforcementReceipt'
              example:
                id: rcpt_01KWVD0ABX041061050R3GG28A
                type: enforcement_result
                spec: OCSS-v1.0-pre
                body:
                  applied_at: '2026-07-06T09:43:59.612Z'
                  enforcement_state: applied
                  envelope_ref: env_9f2c1a7e
                  method_class: platform_gate
                  rule_ref: rr_loopline_infinite_scroll_block
                key_id: did:ocss:loopline#2026-06
                sig: >-
                  ed25519:mGm30Y7TKrhTnTXH8fq2H8BaaVwFGOJCmJpI_F1hqefhCf9u9I5TRZawk2t12KSiq0pyuCbgzxjeQF11djnUAA
        '201':
          description: >
            Confirmation recorded. The census **echoes your signed receipt back
            byte-for-byte** (§8.3.8 cl.3 — it records and returns the app's own
            artifact, it does NOT re-sign or wrap it). `Content-Type` is
            `application/json`; there is no `OCSS-Replay` header on the first
            write.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/EnforcementReceipt'
              example:
                id: rcpt_01KWVD0ABX041061050R3GG28A
                type: enforcement_result
                spec: OCSS-v1.0-pre
                body:
                  applied_at: '2026-07-06T09:43:59.612Z'
                  enforcement_state: applied
                  envelope_ref: env_9f2c1a7e
                  method_class: platform_gate
                  rule_ref: rr_loopline_infinite_scroll_block
                key_id: did:ocss:loopline#2026-06
                sig: >-
                  ed25519:mGm30Y7TKrhTnTXH8fq2H8BaaVwFGOJCmJpI_F1hqefhCf9u9I5TRZawk2t12KSiq0pyuCbgzxjeQF11djnUAA
        '400':
          description: >
            The body did not strict-parse as an enforcement_result receipt
            (wrong `type`, missing `rule_ref`, etc.). `class` is `malformed`.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              example:
                error: Bad Request
                message: payload is not an enforcement_result receipt (§8.3.8)
                code: 400
                class: malformed
        '401':
          description: >
            The receipt is signed by an app DID not resolvable on the Trust
            List, or its `sender_signature` failed verification (§8.3.8 cl.4).
            `class` is `signature_invalid`. (A request with NO RFC 9421
            signature at all gets the generic Unauthorized body — see
            `components/responses/Unauthorized`.)
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              example:
                error: Unauthorized
                message: >-
                  enforcement_result signed by an app DID not resolvable on the
                  Trust List (§8.3.8 cl.4)
                code: 401
                class: signature_invalid
        '403':
          description: >
            First-person binding violation (§8.3.8 cl.1): the receipt was not
            signed by the calling app. `class` is `scope_failure`.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              example:
                error: Forbidden
                message: >-
                  the enforcement_result must be signed by the calling app;
                  failed binding: writer_binding
                code: 403
                class: scope_failure
        '409':
          description: >
            A receipt for the same `(rule_ref, app_did)` was already recorded
            with DIFFERENT content (D-13 replay). An IDENTICAL re-submit is
            idempotent and returns 200, not 409. `class` is `replay`.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              example:
                error: Conflict
                message: >-
                  (rule_ref, app_did) replayed with a different
                  enforcement_result (D-13)
                code: 409
                class: replay
        '429':
          $ref: '#/components/responses/RateLimited'
        '500':
          $ref: '#/components/responses/ServerError'
        '502':
          $ref: '#/components/responses/BadGateway'
        '503':
          description: >
            The census operation is not yet available on this deployment
            (feature-gated surface). Retry later.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              example:
                error: Service Unavailable
                message: census operation not yet available
                code: 503
      security:
        - Rfc9421Signature: []
      x-codeSamples:
        - lang: JavaScript
          label: Node (@phosra/gatekeeper — recommended)
          source: >
            import { createGatekeeper } from "@phosra/gatekeeper"

            const gk = createGatekeeper({
              platformDid: "did:ocss:loopline",
              platformKeyId: "did:ocss:loopline#2026-06",
              gatekeeperSigningKey: { seed: new Uint8Array(32) /* real Ed25519 seed */, keyID: "did:ocss:loopline#2026-06" },
              censusBaseUrl: "https://phosra-api-sandbox-production.up.railway.app",
              trustRootXB64Url: process.env.PHOSRA_TRUST_ROOT_X,
              endpointId: "iGrFqzp43O0S9YTNN2oAT6zMzcugEX_EwZbraWrE1AA",
            })

            const verdict = gk.check("infinite_scroll_block")

            // ...apply the decision at the edge, then attest the outcome:

            await verdict.confirm("applied") // signs the §8.3.8 receipt + POSTs
            it
        - lang: JavaScript
          label: Node (raw — sign the receipt yourself)
          source: >
            import { signRequest, signReceipt, ed25519Sign } from
            "@openchildsafety/ocss"

            import { randomBytes } from "node:crypto"

            const BASE =
            "https://phosra-api-sandbox-production.up.railway.app/api/v1"

            const seed = new
            Uint8Array(Buffer.from("bG9vcGxpbmUBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQE",
            "base64url"))

            const keyID = "did:ocss:loopline#2026-06"

            const key = { keyId: keyID, sign: (m) => ed25519Sign(seed, m) }

            const body = { envelope_ref: "env_abc123", rule_ref:
            "rr_mia_infinite_scroll", enforcement_state: "applied", applied_at:
            new Date().toISOString(), method_class: "platform_gate" }

            const receipt = signReceipt("enforcement_result", body, key, new
            Date(), new Uint8Array(randomBytes(10)))

            const t = BASE + "/enforcement-confirmations", b =
            JSON.stringify(receipt)

            const h = signRequest({ method: "POST", targetURI: t, body: new
            TextEncoder().encode(b), keyID, seed, created: Math.floor(Date.now()
            / 1000) })

            h["Content-Type"] = "application/json"

            const res = await fetch(t, { method: "POST", headers: h, body: b })

            console.log(res.status) // 201 recorded, 200 idempotent re-submit
components:
  schemas:
    EnforcementReceipt:
      type: object
      description: >
        Full §8.3.8 signed receipt (the app's first-person apply attestation).
        The confirmation POST body IS this outer receipt — not the inner body
        alone. Sig covers canon.Marshal({body, spec, type}); id and key_id ride
        outside the signed bytes (D-9 exposure rule). Source: receipt.Receipt in
        internal/ocss/receipt/types.go with body = EnforcementResultBody.
      required:
        - id
        - type
        - spec
        - body
        - key_id
        - sig
      properties:
        id:
          type: string
          description: rcpt_<ULID> — rides outside signed bytes (D-9).
          example: rcpt_01JTEST00000000000000000
        type:
          type: string
          enum:
            - enforcement_result
          description: Always "enforcement_result" for §8.3.8 confirmations.
        spec:
          type: string
          description: OCSS spec version — §11.4 domain separation.
          example: OCSS-v1.0-pre
        body:
          description: >
            JSON-encoded EnforcementResultBody. Kept as raw bytes: re-marshaling
            would alter the canonical signed bytes and break verification.
          oneOf:
            - $ref: '#/components/schemas/EnforcementResultBody'
        key_id:
          type: string
          description: >
            DID key id of the submitting enforcing app (rides outside signed
            bytes). Verified indirectly: the signature only verifies if the
            resolved key matches.
          example: did:ocss:snaptr#snaptr-2026-06
        sig:
          type: string
          description: >-
            "ed25519:" + base64url-raw signature over
            canon.Marshal({body,spec,type}).
      additionalProperties: true
    Error:
      type: object
      description: Standard error envelope returned for every 4xx and 5xx response.
      properties:
        error:
          type: string
          description: >-
            Short, stable, machine-readable error class — matches the HTTP
            status text (e.g. `Not Found`).
        message:
          type: string
          description: >-
            Human-readable explanation of what went wrong and, where possible,
            how to fix it.
        code:
          type: integer
          description: Numeric HTTP status code, duplicated in the body for convenience.
        class:
          type: string
          enum:
            - signature_invalid
            - nonconformant
            - replay
            - standing_failure
            - scope_failure
            - malformed
            - not_found
          description: >
            Stable machine-readable error subclass for programmatic branching.
            Present on ALL seven published census (data-plane) error classes —
            400⇒`malformed`, 401⇒`signature_invalid`,
            403⇒`standing_failure`|`scope_failure`, 404⇒`not_found`,
            409⇒`replay`, 422⇒`nonconformant`. ABSENT on the plain house 500, on
            control-plane/management errors, and on the compact sandbox-lane
            `{error:"<code>"}` bodies (OAuth + sandbox consent).
        failed_step:
          type: string
          description: >
            Present only on a §8.3.1 standing failure (`class:standing_failure`)
            — names the §6.2 step that failed, e.g. `authority_binding`.
      example:
        error: Not Found
        message: unknown enforcement endpoint
        code: 404
        class: not_found
      additionalProperties: true
    EnforcementResultBody:
      type: object
      description: >
        §8.3.8 enforcement-confirmation inner body. Identity-free by
        construction: exactly these five fields; no child ref, device id, or
        user id. Source: receipt.EnforcementResultBody in
        internal/ocss/receipt/types.go.
      required:
        - envelope_ref
        - rule_ref
        - enforcement_state
        - applied_at
        - method_class
      properties:
        envelope_ref:
          type: string
          description: Idempotency key of the carried envelope.
        rule_ref:
          type: string
          description: >
            Per-child opaque rule reference from the enforcement profile
            CategoryEntry. Links this confirmation to the specific rule_ref the
            app enforced.
        enforcement_state:
          type: string
          enum:
            - applied
            - degraded
            - refused
          description: 'One of: applied, degraded, refused.'
        applied_at:
          type: string
          format: date-time
          description: RFC 3339 timestamp.
        method_class:
          type: string
          description: >
            Mechanism-of-enforcement attestation (e.g. dns_block, platform_gate,
            content_removal). MUST be non-empty when enforcement_state =
            applied.
      additionalProperties: true
  responses:
    RateLimited:
      description: >-
        Too many requests. Back off and retry after the interval given in the
        `Retry-After` response header.
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Error'
          example:
            error: Too Many Requests
            message: rate limit exceeded
            code: 429
    ServerError:
      description: >-
        An unexpected error occurred inside Phosra. The request is safe to retry
        with exponential backoff; contact support if it persists.
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Error'
          example:
            error: Internal Server Error
            message: internal error
            code: 500
    BadGateway:
      description: >-
        A downstream provider returned an invalid response while Phosra was
        fulfilling the request. Retry with backoff.
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Error'
          example:
            error: Bad Gateway
            message: downstream provider error
            code: 502
  securitySchemes:
    Rfc9421Signature:
      type: http
      scheme: signature
      description: >
        RFC 9421 message signature (Ed25519). The sender signs the request with
        its Trust-List-published key; the census verifies provenance and
        accreditation tier before processing. Used for POST
        enforcement-endpoints (binding mint), POST
        enforcement-endpoints/{id}/rotate, and POST enforcement-confirmations.
        Profile GETs (GET /enforcement-profiles/{endpoint_id}) also require the
        resolver's RFC 9421 signature — the §9.3(b) bound-resolver auth.

````