{
  "$schema": "http://json-schema.org/draft-07/schema#",
  "$id": "/schemas/3.1.0-rc.9/compliance/comply-test-controller-response.json",
  "title": "Comply Test Controller Response",
  "description": "Response from the comply_test_controller tool. Shape varies by scenario type: list_scenarios returns available scenarios, force_* returns state transition results, simulate_* returns simulation results.",
  "type": "object",
  "allOf": [
    {
      "$ref": "/schemas/3.1.0-rc.9/core/version-envelope.json"
    },
    {
      "$ref": "/schemas/3.1.0-rc.9/core/protocol-envelope.json"
    }
  ],
  "oneOf": [
    {
      "title": "ListScenariosSuccess",
      "description": "Lists which scenarios this seller's test controller supports",
      "type": "object",
      "properties": {
        "success": {
          "type": "boolean",
          "const": true
        },
        "scenarios": {
          "type": "array",
          "items": {
            "type": "string"
          },
          "description": "Scenarios this seller has implemented. Runners and sellers MUST accept unknown scenario strings (open-for-extension) — new scenarios may be added in additive releases. Adopters who advertise `force_creative_purge` opt in to deterministic creative purge coverage for account-level lifecycle webhooks. Adopters who advertise `seed_measurement_catalog` opt in to deterministic measurement-catalog fixtures used by vendor_metric precondition storyboards. Adopters who advertise `query_upstream_traffic` opt in to the upstream-traffic conformance contract; storyboards that declare `check: upstream_traffic` grade `not_applicable` against adopters who do not advertise it. Adopters who advertise `query_provenance_audit_observations` opt in to sandbox-only audit-observation assertions for accepted creatives. Adopters who advertise `force_upstream_unavailable` opt in to stale-cache conformance testing via the `stale_response_advisory` storyboard."
        },
        "context": {
          "$ref": "/schemas/3.1.0-rc.9/core/context.json"
        },
        "ext": {
          "$ref": "/schemas/3.1.0-rc.9/core/ext.json"
        }
      },
      "required": [
        "success",
        "scenarios"
      ],
      "additionalProperties": true,
      "not": {
        "anyOf": [
          {
            "required": [
              "error"
            ]
          },
          {
            "required": [
              "previous_state"
            ]
          },
          {
            "required": [
              "simulated"
            ]
          },
          {
            "required": [
              "forced"
            ]
          },
          {
            "required": [
              "recorded_calls"
            ]
          },
          {
            "required": [
              "audit_observations"
            ]
          }
        ]
      }
    },
    {
      "title": "StateTransitionSuccess",
      "description": "A force_* scenario successfully transitioned the entity to the target state",
      "type": "object",
      "properties": {
        "success": {
          "type": "boolean",
          "const": true
        },
        "previous_state": {
          "type": "string",
          "description": "State before this transition"
        },
        "current_state": {
          "type": "string",
          "description": "State after this transition"
        },
        "message": {
          "type": "string",
          "description": "Human-readable description of the transition"
        },
        "context": {
          "$ref": "/schemas/3.1.0-rc.9/core/context.json"
        },
        "ext": {
          "$ref": "/schemas/3.1.0-rc.9/core/ext.json"
        }
      },
      "required": [
        "success",
        "previous_state",
        "current_state"
      ],
      "additionalProperties": true,
      "not": {
        "anyOf": [
          {
            "required": [
              "error"
            ]
          },
          {
            "required": [
              "scenarios"
            ]
          },
          {
            "required": [
              "simulated"
            ]
          },
          {
            "required": [
              "forced"
            ]
          },
          {
            "required": [
              "recorded_calls"
            ]
          },
          {
            "required": [
              "audit_observations"
            ]
          }
        ]
      }
    },
    {
      "title": "SimulationSuccess",
      "description": "A simulate_delivery or simulate_budget_spend scenario succeeded. For delivery: simulated contains the metrics injected by this call (impressions/clicks/reported_spend/conversions plus optional reach/frequency/reach_window/viewability values) and cumulative contains running totals or latest non-additive metric state. For budget: simulated contains spend_percentage/computed_spend/budget.",
      "type": "object",
      "properties": {
        "success": {
          "type": "boolean",
          "const": true
        },
        "simulated": {
          "type": "object",
          "description": "Values injected or applied by this call. Shape depends on scenario.",
          "additionalProperties": true
        },
        "cumulative": {
          "type": "object",
          "description": "Running totals across all simulation calls (simulate_delivery only)",
          "additionalProperties": true
        },
        "message": {
          "type": "string"
        },
        "context": {
          "$ref": "/schemas/3.1.0-rc.9/core/context.json"
        },
        "ext": {
          "$ref": "/schemas/3.1.0-rc.9/core/ext.json"
        }
      },
      "required": [
        "success",
        "simulated"
      ],
      "additionalProperties": true,
      "not": {
        "anyOf": [
          {
            "required": [
              "error"
            ]
          },
          {
            "required": [
              "scenarios"
            ]
          },
          {
            "required": [
              "previous_state"
            ]
          },
          {
            "required": [
              "forced"
            ]
          },
          {
            "required": [
              "recorded_calls"
            ]
          },
          {
            "required": [
              "audit_observations"
            ]
          }
        ]
      }
    },
    {
      "title": "ForcedDirectiveSuccess",
      "description": "A forced response-arm directive was registered. The directive shapes the next matching operation call from this caller's authenticated sandbox account into the requested arm, then is consumed. No entity transitioned yet, so this branch carries 'forced' rather than previous_state/current_state.",
      "type": "object",
      "properties": {
        "success": {
          "type": "boolean",
          "const": true
        },
        "forced": {
          "type": "object",
          "description": "Echo of the registered directive. The next matching operation call from this sandbox account will return the named arm.",
          "properties": {
            "arm": {
              "type": "string",
              "enum": [
                "submitted",
                "input-required"
              ],
              "description": "Arm the seller will emit on the next forced operation response."
            },
            "task_id": {
              "type": "string",
              "maxLength": 128,
              "description": "Echo of the registered task_id. Present only when arm is 'submitted' (the arm that emits a task envelope).",
              "x-entity": "task"
            }
          },
          "required": [
            "arm"
          ],
          "additionalProperties": false
        },
        "message": {
          "type": "string",
          "description": "Human-readable acknowledgement."
        },
        "context": {
          "$ref": "/schemas/3.1.0-rc.9/core/context.json"
        },
        "ext": {
          "$ref": "/schemas/3.1.0-rc.9/core/ext.json"
        }
      },
      "required": [
        "success",
        "forced"
      ],
      "additionalProperties": true,
      "not": {
        "anyOf": [
          {
            "required": [
              "error"
            ]
          },
          {
            "required": [
              "scenarios"
            ]
          },
          {
            "required": [
              "previous_state"
            ]
          },
          {
            "required": [
              "simulated"
            ]
          },
          {
            "required": [
              "recorded_calls"
            ]
          },
          {
            "required": [
              "audit_observations"
            ]
          }
        ]
      }
    },
    {
      "title": "SeedSuccess",
      "description": "A seed_* scenario successfully pre-populated a fixture in the seller's test state",
      "type": "object",
      "properties": {
        "success": {
          "type": "boolean",
          "const": true
        },
        "message": {
          "type": "string",
          "description": "Human-readable acknowledgement."
        },
        "context": {
          "$ref": "/schemas/3.1.0-rc.9/core/context.json"
        },
        "ext": {
          "$ref": "/schemas/3.1.0-rc.9/core/ext.json"
        }
      },
      "required": [
        "success"
      ],
      "additionalProperties": true,
      "not": {
        "anyOf": [
          {
            "required": [
              "error"
            ]
          },
          {
            "required": [
              "scenarios"
            ]
          },
          {
            "required": [
              "previous_state"
            ]
          },
          {
            "required": [
              "simulated"
            ]
          },
          {
            "required": [
              "forced"
            ]
          },
          {
            "required": [
              "recorded_calls"
            ]
          },
          {
            "required": [
              "audit_observations"
            ]
          }
        ]
      }
    },
    {
      "title": "ProvenanceAuditObservationsSuccess",
      "description": "A query_provenance_audit_observations scenario returned sandbox-recorded audit observations for a creative. This hook is for conformance only; public seller responses do not have to expose internal audit-log state.",
      "type": "object",
      "properties": {
        "success": {
          "type": "boolean",
          "const": true
        },
        "creative_id": {
          "type": "string",
          "description": "Creative ID whose audit observations were queried.",
          "x-entity": "creative"
        },
        "audit_observations": {
          "type": "array",
          "description": "Audit observations recorded for the creative in the sandbox session.",
          "items": {
            "$ref": "/schemas/3.1.0-rc.9/creative/audit-observation.json"
          }
        },
        "context": {
          "$ref": "/schemas/3.1.0-rc.9/core/context.json"
        },
        "ext": {
          "$ref": "/schemas/3.1.0-rc.9/core/ext.json"
        }
      },
      "required": [
        "success",
        "creative_id",
        "audit_observations"
      ],
      "additionalProperties": true,
      "not": {
        "anyOf": [
          {
            "required": [
              "error"
            ]
          },
          {
            "required": [
              "scenarios"
            ]
          },
          {
            "required": [
              "previous_state"
            ]
          },
          {
            "required": [
              "simulated"
            ]
          },
          {
            "required": [
              "forced"
            ]
          },
          {
            "required": [
              "recorded_calls"
            ]
          }
        ]
      }
    },
    {
      "title": "UpstreamTrafficSuccess",
      "description": "A query_upstream_traffic scenario returned the outbound HTTP calls the agent has made since the requested time window. Used by storyboard runners to apply `check: upstream_traffic` assertions. The mechanism raises the bar against unintentional façades — adapters (often LLM-generated) that satisfy AdCP schema requirements with synthetic placeholders without forwarding data upstream. Adopters self-report their own traffic; this contract is NOT an adversarial integrity check, and consumers MUST NOT treat upstream_traffic passing as cryptographic proof of adapter behavior. Synthetic vectors only: adopters MUST NOT enable query_upstream_traffic against a sandbox that processes production identifier values, regardless of attestation mode. Storyboards SHOULD use synthetic hashed inputs (e.g., the `acme-user-NNNN` form in the example below). The synthetic-vectors-only requirement applies to digest mode as well as raw — the digest carrying production hashed PII would still let a runner with the right precomputed digest set learn membership of arbitrary identifiers in the adopter's production user base (existence-oracle), which is exactly the threat synthetic vectors close. Privacy-conscious adopters use digest mode to support upstream_traffic conformance without raw-payload disclosure of synthetic test data — not to enable testing against production data. Caller scoping: adopters MUST scope recorded_calls to traffic caused by the requesting principal's session/auth context — cross-caller traffic MUST NOT be returned regardless of `since_timestamp`. Multi-tenant sandboxes MUST key the recording buffer on the comply_test_controller invocation's auth principal, not just process-global. Secret redaction: adopters MUST recursively redact values at keys matching the case-insensitive pattern `^(authorization|credentials?|token|api[_-]?key|password|secret|client[_-]secret|refresh[_-]token|access[_-]token|bearer|session[_-]token|offering[_-]token|cookie|set[_-]cookie)$` from the recorded payload before emission (raw mode) or before digest computation (digest mode). The redaction obligation is normative on the controller — runner-side redaction is a backstop, not a substitute.",
      "type": "object",
      "properties": {
        "success": {
          "type": "boolean",
          "const": true
        },
        "recorded_calls": {
          "type": "array",
          "description": "Outbound HTTP calls caused by the requesting principal in the requested window, ordered by `timestamp` ascending. Cross-caller calls MUST NOT appear here. Each item declares its `attestation_mode`: `raw` items carry the full `payload`; `digest` items carry `payload_digest_sha256` + `payload_length` + optional `identifier_match_proofs[]` instead, for adopters who can't return raw payloads under their privacy/data-residency policy.",
          "items": {
            "type": "object",
            "properties": {
              "method": {
                "type": "string",
                "enum": [
                  "GET",
                  "POST",
                  "PUT",
                  "PATCH",
                  "DELETE",
                  "HEAD",
                  "OPTIONS"
                ],
                "description": "HTTP method of the outbound call."
              },
              "endpoint": {
                "type": "string",
                "description": "Composed `<METHOD> <URL>` string used for `endpoint_pattern` matching, e.g. 'POST https://api.tiktok.com/v2/audience/upload'. Convenience field — the runner can also reconstruct from `method` + URL components."
              },
              "url": {
                "type": "string",
                "format": "uri",
                "description": "Full URL of the outbound call (scheme + host + path + query). Treated as untrusted agent-controlled input by report renderers — see runner-output-contract.yaml > security.rendered_output_fencing."
              },
              "host": {
                "type": "string",
                "description": "Host portion of the URL, useful for grouping calls by upstream platform."
              },
              "path": {
                "type": "string",
                "description": "Path portion of the URL (without query string)."
              },
              "content_type": {
                "type": "string",
                "description": "Media type of the outbound request body, mirroring the agent's outbound `Content-Type` header (e.g., `application/json`, `application/x-www-form-urlencoded`, `multipart/form-data`, `text/plain`). In raw mode this describes the returned `payload`; in digest mode it describes the body the digest was computed over. Storyboard `payload_must_contain` JSONPath-lite assertions are valid only when content_type is `application/json` or has a `+json` suffix AND attestation_mode is `raw` — digest mode and non-JSON content types grade `payload_must_contain` as not_applicable. Required so the runner can choose the right matcher deterministically."
              },
              "attestation_mode": {
                "type": "string",
                "enum": [
                  "raw",
                  "digest"
                ],
                "description": "Per-call attestation mode echoing the request's `params.attestation_mode`. Required on every recorded_call so the `oneOf` discriminator always has an explicit value to dispatch on — no implicit defaults inside oneOf branches. Adopters MAY unilaterally downgrade a `raw` request to `digest` for a specific call when their policy requires it (e.g., the call carried regulated PII the adopter can't return raw). The runner reads this field to know which assertions to apply."
              },
              "purpose": {
                "type": "string",
                "enum": [
                  "platform_primary",
                  "measurement",
                  "attribution",
                  "creative_serving",
                  "identity",
                  "other"
                ],
                "description": "Optional adopter-supplied semantic tag for the call's role. Values: `platform_primary` for the primary upstream platform the adapter is integrating with (e.g., a TikTok audience-upload call from a sales-social adapter); `measurement` for ancillary calls to measurement vendors (DV, IAS, Nielsen, MOAT); `attribution` for server-side conversion APIs (TTD Trans-API, Meta CAPI, AppsFlyer/Branch postbacks) that flow alongside primary platform calls in a buy-step; `creative_serving` for ad-server / CDN / tag-build calls (GAM tag generation, VAST/CDN fetches, creative trafficking); `identity` for ID-graph / hashing-service calls (LiveRamp, ID5, UID2); `other` for everything else (config fetches, internal telemetry, consent signal exchange). Lets storyboards scope `upstream_traffic` assertions via `purpose_filter` so a buyer-agent adapter that legitimately calls measurement vendors during a single buy step doesn't muddy the platform-primary assertion. Calls without a `purpose` field are treated as `purpose: other` for `purpose_filter` matching — adopters who haven't classified are matched only by storyboards filtering on `other` (or by storyboards with no `purpose_filter`). Self-reported, not adversarially trustworthy — same trust model as the rest of recorded_calls; misclassification by a façade is bounded by the runner's reporting of unclassified-call counts in `actual` when filters match zero."
              },
              "payload": {
                "description": "Request body the agent sent. Required when `attestation_mode` is `raw` (or omitted); MUST be absent when `attestation_mode` is `digest`. Object when content_type is JSON-shaped and the controller decoded it; string otherwise. The `x-adcp-open-payload: true` annotation applies to the decoded JSON/object arm of this mixed field; non-JSON string payloads remain scalar values governed by the surrounding schema. Adopters MUST apply the recursive secret-key redaction described in this branch's top-level description before emission — secrets at any depth (Authorization values inlined into JSON bodies, embedded JWTs, presigned-URL tokens, OAuth refresh tokens) MUST be replaced with the literal string `[redacted]`. Storyboards that assert `payload_must_contain` or `identifier_paths` are matching against THIS field — secrets MUST be redacted but storyboard-supplied identifiers (hashed PII, request correlation values) MUST NOT be redacted. Adopters SHOULD cap individual payload size at 64 KiB; payloads exceeding that SHOULD be truncated with a trailing `[…truncated]` marker — large payloads bloat compliance reports and the LLM-rendered context windows that consume them.",
                "x-adcp-open-payload": true,
                "maxLength": 65536
              },
              "payload_digest_sha256": {
                "type": "string",
                "pattern": "^[a-f0-9]{64}$",
                "description": "SHA-256 digest of the canonicalized outbound request body, lowercase hex (64 chars). Required when `attestation_mode` is `digest`; MUST be absent when `attestation_mode` is `raw`. Canonicalization order is normative: (1) controllers MUST apply the recursive secret-key redaction (same pattern as the raw-mode payload field) BEFORE computing the digest; (2) for `application/json` and `*+json` content types, controllers MUST then serialize the redacted body to RFC 8785 (JCS) canonical form — sorted keys, no extraneous whitespace — and digest the resulting bytes. Storyboard-supplied identifiers (hashed PII, request correlation values) MUST NOT be redacted before digest computation; they are the load-bearing match target for `identifier_match_proofs` and digesting them away makes echo verification impossible. Both `payload_digest_sha256` AND `identifier_match_proofs` MUST be computed against the same post-redaction canonical bytes — diverging the two surfaces breaks coherence between digest replay and identifier echo. JCS edge cases: when a digest-mode `query_upstream_traffic` response cannot be produced because the parsed JSON-like value tree contains a non-finite numeric value (`NaN`, `+Infinity`, or `-Infinity`), controllers MUST NOT coerce that value to `null`, a string, or any other placeholder for digest computation; they MUST return the typed ControllerError code `JCS_NON_FINITE_NUMBER`. Runners MUST grade the affected upstream_traffic digest validation `not_applicable` because RFC 8785 forbids non-finite numbers. Payloads carrying numeric identifiers MUST serialize them as JSON strings before digest computation (adtech bid payloads regularly carry IDs outside ±2^53 where I-JSON / RFC 7493 number round-tripping diverges across implementations). For non-JSON content types the digest is computed over the post-redaction raw body bytes."
              },
              "payload_length": {
                "type": "integer",
                "minimum": 0,
                "description": "Byte length of the post-redaction body bytes represented by this recorded_call. Required in both `raw` and `digest` modes — symmetric across modes so runners can detect adopter-side truncation regardless of attestation choice. In `raw` mode this MUST equal the UTF-8 byte length of the emitted `payload` value after the same recursive secret-key redaction the controller applied before returning it. In `digest` mode this MUST equal the exact number of bytes fed into SHA-256 for `payload_digest_sha256`: RFC 8785 (JCS) canonical bytes for JSON-shaped content after redaction, or the post-redaction raw body bytes for non-JSON content. Digest-mode `payload_length` is therefore NOT the original outbound body length before JSON parsing, redaction, or canonicalization. Mismatch between observed payload length and reported `payload_length` is a controller-side bug worth surfacing in the report."
              },
              "identifier_match_proofs": {
                "type": "array",
                "maxItems": 64,
                "description": "Per-identifier echo proofs for digest-mode calls. Required when `attestation_mode` is `digest` AND the request supplied `params.identifier_value_digests`; MUST be absent or empty otherwise. Each entry corresponds to one digest from the request. Capped at 64 to match the request-side `params.identifier_value_digests` cap. Lets storyboards verify `identifier_paths` echo in digest mode without ever transmitting plaintext identifiers to the controller. SHA-256 is a privacy mechanism here, not a trust mechanism — controllers self-report `found` and a determined façade can return any boolean; consumers MUST NOT treat digest-mode passing as cryptographically more trustworthy than raw mode. Tokenization is normative: for `application/json` and `*+json` content types, controllers MUST scan exactly the JSON string-typed leaf values of the post-redaction canonicalized body — no substring matching, no word splitting, no case folding, no Unicode normalization. A token matches when its SHA-256 hash equals one of the requested digests byte-for-byte. For non-JSON content types (form-urlencoded, multipart, plain text), `identifier_match_proofs` MUST be empty and runner-side `identifier_paths` assertions targeting those calls grade `not_applicable` — token boundaries are not portably defined across non-JSON shapes.",
                "items": {
                  "type": "object",
                  "properties": {
                    "identifier_value_sha256": {
                      "type": "string",
                      "pattern": "^[a-f0-9]{64}$",
                      "description": "Echo of one digest from `params.identifier_value_digests` so the runner can pair this proof with the identifier it queried."
                    },
                    "found": {
                      "type": "boolean",
                      "description": "True if any string token in the recorded payload hashes to the queried digest. False otherwise."
                    }
                  },
                  "required": [
                    "identifier_value_sha256",
                    "found"
                  ],
                  "additionalProperties": false
                }
              },
              "timestamp": {
                "type": "string",
                "format": "date-time",
                "description": "ISO 8601 timestamp the adopter recorded the outbound call. MUST reflect the adopter's wall clock at the moment the outbound request was sent (not log-flush time), and MUST be monotonically non-decreasing across recorded_calls of a single response. Used by runners to scope assertions to a specific storyboard step's window — see runner-output-contract.yaml > validation_result for the timestamp boundary semantics."
              },
              "status_code": {
                "type": "integer",
                "minimum": 100,
                "maximum": 599,
                "description": "HTTP status code returned by the upstream. Optional — adopters MAY omit when the call was instrumented before the response arrived."
              }
            },
            "required": [
              "method",
              "endpoint",
              "url",
              "content_type",
              "attestation_mode",
              "payload_length",
              "timestamp"
            ],
            "additionalProperties": false,
            "discriminator": {
              "propertyName": "attestation_mode"
            },
            "oneOf": [
              {
                "title": "RawAttestation",
                "description": "attestation_mode raw — payload is required; payload_digest_sha256 and identifier_match_proofs are absent. attestation_mode is required at the item level so the discriminator always has a value to dispatch on (no implicit defaults inside oneOf branches).",
                "properties": {
                  "attestation_mode": {
                    "const": "raw"
                  }
                },
                "required": [
                  "attestation_mode",
                  "payload"
                ],
                "not": {
                  "anyOf": [
                    {
                      "required": [
                        "payload_digest_sha256"
                      ]
                    },
                    {
                      "required": [
                        "identifier_match_proofs"
                      ]
                    }
                  ]
                }
              },
              {
                "title": "DigestAttestation",
                "description": "attestation_mode digest — payload_digest_sha256 required, payload absent. identifier_match_proofs present when the request supplied identifier_value_digests.",
                "properties": {
                  "attestation_mode": {
                    "const": "digest"
                  }
                },
                "required": [
                  "attestation_mode",
                  "payload_digest_sha256"
                ],
                "not": {
                  "required": [
                    "payload"
                  ]
                }
              }
            ]
          }
        },
        "total_count": {
          "type": "integer",
          "minimum": 0,
          "description": "Total calls in the requested window before any pagination — `recorded_calls.length` may be smaller when `params.limit` truncated the response."
        },
        "truncated": {
          "type": "boolean",
          "description": "True when `total_count > recorded_calls.length`. Runners MAY raise the `limit` and re-query, but storyboards SHOULD declare assertions that fit within the default 100-call window — a truncated response is a signal that the storyboard step is causing more upstream activity than expected."
        },
        "since_timestamp": {
          "type": "string",
          "format": "date-time",
          "description": "Echo of the `since_timestamp` the runner requested (or the session-start timestamp the adopter substituted when the runner omitted it). Informational — the runner SHOULD use its own clock-bracket of when it issued the AdCP step request, not this echo, when attributing recorded_calls to a specific step. The controller is part of the adopter's claimed conformance; the echo is not adversarially trustworthy."
        },
        "context": {
          "$ref": "/schemas/3.1.0-rc.9/core/context.json"
        },
        "ext": {
          "$ref": "/schemas/3.1.0-rc.9/core/ext.json"
        }
      },
      "required": [
        "success",
        "recorded_calls",
        "total_count",
        "since_timestamp"
      ],
      "additionalProperties": true,
      "not": {
        "anyOf": [
          {
            "required": [
              "error"
            ]
          },
          {
            "required": [
              "scenarios"
            ]
          },
          {
            "required": [
              "previous_state"
            ]
          },
          {
            "required": [
              "simulated"
            ]
          },
          {
            "required": [
              "forced"
            ]
          },
          {
            "required": [
              "audit_observations"
            ]
          }
        ]
      }
    },
    {
      "title": "ControllerError",
      "description": "The scenario failed or could not produce a conformant response — invalid transition, unknown entity, unsupported scenario, invalid params, forbidden sandbox access, non-finite JCS canonicalization, or internal failure",
      "type": "object",
      "properties": {
        "success": {
          "type": "boolean",
          "const": false
        },
        "error": {
          "type": "string",
          "enum": [
            "INVALID_TRANSITION",
            "INVALID_STATE",
            "NOT_FOUND",
            "UNKNOWN_SCENARIO",
            "INVALID_PARAMS",
            "FORBIDDEN",
            "JCS_NON_FINITE_NUMBER",
            "INTERNAL_ERROR"
          ],
          "description": "Structured error code. `JCS_NON_FINITE_NUMBER` is reserved for digest-mode upstream_traffic responses that cannot be RFC 8785/JCS-canonicalized because the parsed JSON-like value tree contains a non-finite numeric value (`NaN`, `+Infinity`, or `-Infinity`); controllers MUST NOT coerce those values during digest computation, and runners grade that validation `not_applicable`, not failed."
        },
        "error_detail": {
          "type": "string",
          "description": "Human-readable explanation of the failure"
        },
        "current_state": {
          "type": [
            "string",
            "null"
          ],
          "description": "Current state of the entity, or null if not found"
        },
        "context": {
          "$ref": "/schemas/3.1.0-rc.9/core/context.json"
        },
        "ext": {
          "$ref": "/schemas/3.1.0-rc.9/core/ext.json"
        }
      },
      "required": [
        "success",
        "error"
      ],
      "additionalProperties": true,
      "not": {
        "anyOf": [
          {
            "required": [
              "scenarios"
            ]
          },
          {
            "required": [
              "simulated"
            ]
          },
          {
            "required": [
              "previous_state"
            ]
          },
          {
            "required": [
              "forced"
            ]
          },
          {
            "required": [
              "recorded_calls"
            ]
          },
          {
            "required": [
              "audit_observations"
            ]
          }
        ]
      }
    }
  ],
  "examples": [
    {
      "description": "List scenarios response",
      "data": {
        "status": "completed",
        "success": true,
        "scenarios": [
          "force_creative_status",
          "force_creative_purge",
          "force_account_status",
          "force_media_buy_status"
        ]
      }
    },
    {
      "description": "Successful state transition",
      "data": {
        "status": "completed",
        "success": true,
        "previous_state": "processing",
        "current_state": "approved",
        "message": "Creative cr-123 transitioned from processing to approved"
      }
    },
    {
      "description": "Delivery simulation with cumulative totals",
      "data": {
        "status": "completed",
        "success": true,
        "simulated": {
          "impressions": 10000,
          "clicks": 150,
          "reported_spend": {
            "amount": 150,
            "currency": "USD"
          }
        },
        "cumulative": {
          "impressions": 25000,
          "clicks": 380,
          "reported_spend": {
            "amount": 375,
            "currency": "USD"
          }
        },
        "message": "Delivery simulated for mb-789: 10000 impressions, 150 clicks, $150.00 spend"
      }
    },
    {
      "description": "Budget spend simulation",
      "data": {
        "status": "completed",
        "success": true,
        "simulated": {
          "spend_percentage": 95,
          "computed_spend": {
            "amount": 950,
            "currency": "USD"
          },
          "budget": {
            "amount": 1000,
            "currency": "USD"
          }
        },
        "message": "Budget for mb-789 set to 95% consumed ($950.00 of $1000.00)"
      }
    },
    {
      "description": "force_create_media_buy_arm directive registered",
      "data": {
        "status": "completed",
        "success": true,
        "forced": {
          "arm": "submitted",
          "task_id": "task_async_signed_io_q2"
        },
        "message": "Next create_media_buy call from this sandbox account will return the submitted arm with task_id task_async_signed_io_q2"
      }
    },
    {
      "description": "Invalid transition error",
      "data": {
        "status": "completed",
        "success": false,
        "error": "INVALID_TRANSITION",
        "error_detail": "Cannot transition from archived to processing — archived is terminal",
        "current_state": "archived"
      }
    },
    {
      "description": "Entity not found",
      "data": {
        "status": "completed",
        "success": false,
        "error": "NOT_FOUND",
        "error_detail": "Creative cr-unknown not found",
        "current_state": null
      }
    },
    {
      "description": "Upstream traffic in raw attestation mode (default) — adapter forwarded synthetic hashed members to a hypothetical audience-upload endpoint, payload returned in full so the runner can apply payload_must_contain assertions.",
      "data": {
        "status": "completed",
        "success": true,
        "since_timestamp": "2026-05-02T14:30:00Z",
        "total_count": 1,
        "truncated": false,
        "recorded_calls": [
          {
            "method": "POST",
            "endpoint": "POST https://business-api.tiktok.com/open_api/v1.3/dmp/custom_audience/upload/",
            "url": "https://business-api.tiktok.com/open_api/v1.3/dmp/custom_audience/upload/",
            "host": "business-api.tiktok.com",
            "path": "/open_api/v1.3/dmp/custom_audience/upload/",
            "content_type": "application/json",
            "purpose": "platform_primary",
            "attestation_mode": "raw",
            "payload": {
              "advertiser_id": "1234567890",
              "audience_name": "outdoor_enthusiasts_25_54",
              "users": [
                {
                  "external_id": "acme-user-0001",
                  "hashed_email": "a000000000000000000000000000000000000000000000000000000000000001"
                },
                {
                  "external_id": "acme-user-0002",
                  "hashed_phone": "b000000000000000000000000000000000000000000000000000000000000002"
                }
              ]
            },
            "payload_length": 387,
            "timestamp": "2026-05-02T14:30:01.245Z",
            "status_code": 200
          }
        ]
      }
    },
    {
      "description": "Upstream traffic in digest attestation mode — privacy-conscious adopter returns payload_digest_sha256 + payload_length + identifier_match_proofs[] (per-digest echo verification matching the request's identifier_value_digests) instead of raw payload. Synthetic vectors only: digest mode reduces what the runner sees, but the controller must still operate on synthetic test data.",
      "data": {
        "status": "completed",
        "success": true,
        "since_timestamp": "2026-05-02T14:30:00Z",
        "total_count": 1,
        "truncated": false,
        "recorded_calls": [
          {
            "method": "POST",
            "endpoint": "POST https://api.example.eu/v1/audience/members",
            "url": "https://api.example.eu/v1/audience/members",
            "host": "api.example.eu",
            "path": "/v1/audience/members",
            "content_type": "application/json",
            "attestation_mode": "digest",
            "payload_digest_sha256": "3f786850e387550fdab836ed7e6dc881de23001b1f8e64ab38b1e30a2ad7c92e",
            "payload_length": 412,
            "identifier_match_proofs": [
              {
                "identifier_value_sha256": "1f0c1bda935708f24218ee06d62f2a91dffaadb4cd5b7f9d33fcad66b66d97c4",
                "found": true
              },
              {
                "identifier_value_sha256": "9d4e1e23bd5b727046a9e3b4b7db57bd8d6ee684634008d1dad34b2e4b834d09",
                "found": true
              },
              {
                "identifier_value_sha256": "0000000000000000000000000000000000000000000000000000000000000000",
                "found": false
              }
            ],
            "timestamp": "2026-05-02T14:30:01.245Z",
            "status_code": 200
          }
        ]
      }
    }
  ],
  "properties": {}
}
