Module adcp.types.domains.compliance.comply_test_controller_response
Classes
class AttestationMode (*args, **kwds)-
Expand source code
class AttestationMode(StrEnum): raw = 'raw' digest = 'digest'Enum where members are also (and must be) strings
Ancestors
- enum.StrEnum
- builtins.str
- enum.ReprEnum
- enum.Enum
Class variables
var digestvar raw
class ComplyResponseArm (*args, **kwds)-
Expand source code
class ComplyResponseArm(StrEnum): submitted = 'submitted' completed = 'completed' input_required = 'input-required' rejected = 'rejected'Enum where members are also (and must be) strings
Ancestors
- enum.StrEnum
- builtins.str
- enum.ReprEnum
- enum.Enum
Class variables
var completedvar input_requiredvar rejectedvar submitted
class ComplyTestControllerResponse (**data: Any)-
Expand source code
class ComplyTestControllerResponse(AdcpResponse, ResponseArmDispatchMixin, AdcpVersionEnvelope, ProtocolEnvelope): """Constructible compatibility base for generated response arms.""" @classmethod def _response_arm_models(cls) -> tuple[type[ComplyTestControllerResponse], ...]: return ( ComplyTestControllerResponse1, ComplyTestControllerResponse2, ComplyTestControllerResponse3, ComplyTestControllerResponse4, ComplyTestControllerResponse5, ComplyTestControllerResponse6, ComplyTestControllerResponse7, ComplyTestControllerResponse8, )Constructible compatibility base for generated response arms.
Create a new model by parsing and validating input data from keyword arguments.
Raises [
ValidationError][pydantic_core.ValidationError] if the input data cannot be validated to form a valid model.selfis explicitly positional-only to allowselfas a field name.Ancestors
- AdcpResponse
- adcp.types.base._AdcpMessage
- ResponseArmDispatchMixin
- AdcpVersionEnvelope
- ProtocolEnvelope
- AdCPBaseModel
- pydantic.main.BaseModel
Subclasses
- ComplyTestControllerResponse1
- ComplyTestControllerResponse2
- ComplyTestControllerResponse3
- ComplyTestControllerResponse4
- ComplyTestControllerResponse5
- ComplyTestControllerResponse6
- ComplyTestControllerResponse7
- ComplyTestControllerResponse8
Class variables
var model_config
Inherited members
class ComplyTestControllerResponse1 (**data: Any)-
Expand source code
class ComplyTestControllerResponse1(ComplyTestControllerResponse): model_config = ConfigDict( extra='allow', ) success: Literal[True] scenarios: Annotated[ list[str], Field( 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 `catalog_item_availability_probe` support deterministic cross-principal reference, eligibility-gate, expiry-clock, and catalog-generation tests for the catalog availability storyboard. Adopters who advertise `compact_product_lifecycle_probe` support deterministic synchronous list/request/finalize/decline/accept/control/readback behavior for a prepared product and strict post-deadline expiry of a committed proposal. Adopters who advertise `compact_direct_buy_lifecycle_probe` support deterministic synchronous list/buy/control/readback behavior for a prepared product. Adopters who advertise `reporting_core_lifecycle_probe` support deterministic obligation-before-report, clock-health, zero-row reporting, provisional-restatement, and post-received restatement-grace tests without wall-clock waits. `reliable_reporting_core_integrity_probe`, `reliable_reporting_managed_delivery_probe`, and `reliable_reporting_reconciled_billing_probe` seed the source-calendar/checkpoint, managed-resource, and receipt/adjustment workflows used by the Reliable Reporting tier storyboards. Adopters who advertise `force_creative_purge` opt in to deterministic creative purge coverage for account-level lifecycle webhooks. Adopters who advertise `force_media_buy_purge` opt in to deterministic deletion-independent idempotency replay coverage. 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: context_1.ContextObject | None = None ext: ext_1.ExtensionObject | None = NoneConstructible compatibility base for generated response arms.
Create a new model by parsing and validating input data from keyword arguments.
Raises [
ValidationError][pydantic_core.ValidationError] if the input data cannot be validated to form a valid model.selfis explicitly positional-only to allowselfas a field name.Ancestors
- ComplyTestControllerResponse
- AdcpResponse
- adcp.types.base._AdcpMessage
- ResponseArmDispatchMixin
- AdcpVersionEnvelope
- ProtocolEnvelope
- AdCPBaseModel
- pydantic.main.BaseModel
Class variables
var context : ContextObject | Nonevar ext : ExtensionObject | Nonevar model_configvar scenarios : list[str]var success : Literal[True]
Inherited members
class ComplyTestControllerResponse2 (**data: Any)-
Expand source code
class ComplyTestControllerResponse2(ComplyTestControllerResponse): model_config = ConfigDict( extra='allow', ) success: Literal[True] previous_state: Annotated[str, Field(description='State before this transition')] current_state: Annotated[str, Field(description='State after this transition')] message: Annotated[ str | None, Field(description='Human-readable description of the transition') ] = None context: context_1.ContextObject | None = None ext: ext_1.ExtensionObject | None = NoneConstructible compatibility base for generated response arms.
Create a new model by parsing and validating input data from keyword arguments.
Raises [
ValidationError][pydantic_core.ValidationError] if the input data cannot be validated to form a valid model.selfis explicitly positional-only to allowselfas a field name.Ancestors
- ComplyTestControllerResponse
- AdcpResponse
- adcp.types.base._AdcpMessage
- ResponseArmDispatchMixin
- AdcpVersionEnvelope
- ProtocolEnvelope
- AdCPBaseModel
- pydantic.main.BaseModel
Class variables
var context : ContextObject | Nonevar current_state : strvar ext : ExtensionObject | Nonevar message : str | Nonevar model_configvar previous_state : strvar success : Literal[True]
Inherited members
class ComplyTestControllerResponse3 (**data: Any)-
Expand source code
class ComplyTestControllerResponse3(ComplyTestControllerResponse): model_config = ConfigDict( extra='allow', ) success: Literal[True] simulated: Annotated[ dict[str, Any], Field(description='Values injected or applied by this call. Shape depends on scenario.'), ] cumulative: Annotated[ dict[str, Any] | None, Field(description='Running totals across all simulation calls (simulate_delivery only)'), ] = None message: str | None = None context: context_1.ContextObject | None = None ext: ext_1.ExtensionObject | None = NoneConstructible compatibility base for generated response arms.
Create a new model by parsing and validating input data from keyword arguments.
Raises [
ValidationError][pydantic_core.ValidationError] if the input data cannot be validated to form a valid model.selfis explicitly positional-only to allowselfas a field name.Ancestors
- ComplyTestControllerResponse
- AdcpResponse
- adcp.types.base._AdcpMessage
- ResponseArmDispatchMixin
- AdcpVersionEnvelope
- ProtocolEnvelope
- AdCPBaseModel
- pydantic.main.BaseModel
Class variables
var context : ContextObject | Nonevar cumulative : dict[str, typing.Any] | Nonevar ext : ExtensionObject | Nonevar message : str | Nonevar model_configvar simulated : dict[str, typing.Any]var success : Literal[True]
Inherited members
class ComplyTestControllerResponse4 (**data: Any)-
Expand source code
class ComplyTestControllerResponse4(ComplyTestControllerResponse): model_config = ConfigDict( extra='allow', ) success: Literal[True] forced: Annotated[ Forced, Field( description='Echo of the registered directive. The next matching operation call from this sandbox account will return the named arm.' ), ] message: Annotated[str | None, Field(description='Human-readable acknowledgement.')] = None context: context_1.ContextObject | None = None ext: ext_1.ExtensionObject | None = NoneConstructible compatibility base for generated response arms.
Create a new model by parsing and validating input data from keyword arguments.
Raises [
ValidationError][pydantic_core.ValidationError] if the input data cannot be validated to form a valid model.selfis explicitly positional-only to allowselfas a field name.Ancestors
- ComplyTestControllerResponse
- AdcpResponse
- adcp.types.base._AdcpMessage
- ResponseArmDispatchMixin
- AdcpVersionEnvelope
- ProtocolEnvelope
- AdCPBaseModel
- pydantic.main.BaseModel
Class variables
var context : ContextObject | Nonevar ext : ExtensionObject | Nonevar forced : Forcedvar message : str | Nonevar model_configvar success : Literal[True]
Inherited members
class ComplyTestControllerResponse5 (**data: Any)-
Expand source code
class ComplyTestControllerResponse5(ComplyTestControllerResponse): model_config = ConfigDict( extra='allow', ) success: Literal[True] message: Annotated[str | None, Field(description='Human-readable acknowledgement.')] = None context: context_1.ContextObject | None = None ext: ext_1.ExtensionObject | None = NoneConstructible compatibility base for generated response arms.
Create a new model by parsing and validating input data from keyword arguments.
Raises [
ValidationError][pydantic_core.ValidationError] if the input data cannot be validated to form a valid model.selfis explicitly positional-only to allowselfas a field name.Ancestors
- ComplyTestControllerResponse
- AdcpResponse
- adcp.types.base._AdcpMessage
- ResponseArmDispatchMixin
- AdcpVersionEnvelope
- ProtocolEnvelope
- AdCPBaseModel
- pydantic.main.BaseModel
Class variables
var context : ContextObject | Nonevar ext : ExtensionObject | Nonevar message : str | Nonevar model_configvar success : Literal[True]
Inherited members
class ComplyTestControllerResponse6 (**data: Any)-
Expand source code
class ComplyTestControllerResponse6(ComplyTestControllerResponse): model_config = ConfigDict( extra='allow', ) success: Literal[True] creative_id: Annotated[ str, Field(description='Creative ID whose audit observations were queried.') ] audit_observations: Annotated[ list[audit_observation.CreativeAuditObservation], Field(description='Audit observations recorded for the creative in the sandbox session.'), ] context: context_1.ContextObject | None = None ext: ext_1.ExtensionObject | None = NoneConstructible compatibility base for generated response arms.
Create a new model by parsing and validating input data from keyword arguments.
Raises [
ValidationError][pydantic_core.ValidationError] if the input data cannot be validated to form a valid model.selfis explicitly positional-only to allowselfas a field name.Ancestors
- ComplyTestControllerResponse
- AdcpResponse
- adcp.types.base._AdcpMessage
- ResponseArmDispatchMixin
- AdcpVersionEnvelope
- ProtocolEnvelope
- AdCPBaseModel
- pydantic.main.BaseModel
Class variables
var audit_observations : list[CreativeAuditObservation]var context : ContextObject | Nonevar creative_id : strvar ext : ExtensionObject | Nonevar model_configvar success : Literal[True]
Inherited members
class ComplyTestControllerResponse7 (**data: Any)-
Expand source code
class ComplyTestControllerResponse7(ComplyTestControllerResponse): model_config = ConfigDict( extra='allow', ) success: Literal[True] recorded_calls: Annotated[ list[RecordedCalls], Field( 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." ), ] total_count: Annotated[ SchemaInt, Field( description='Total calls in the requested window before any pagination — `recorded_calls.length` may be smaller when `params.limit` truncated the response.', ge=0, ), ] truncated: Annotated[ StrictBool | None, Field( 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.' ), ] = None since_timestamp: Annotated[ AwareDatetime, Field( 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: context_1.ContextObject | None = None ext: ext_1.ExtensionObject | None = NoneConstructible compatibility base for generated response arms.
Create a new model by parsing and validating input data from keyword arguments.
Raises [
ValidationError][pydantic_core.ValidationError] if the input data cannot be validated to form a valid model.selfis explicitly positional-only to allowselfas a field name.Ancestors
- ComplyTestControllerResponse
- AdcpResponse
- adcp.types.base._AdcpMessage
- ResponseArmDispatchMixin
- AdcpVersionEnvelope
- ProtocolEnvelope
- AdCPBaseModel
- pydantic.main.BaseModel
Class variables
var context : ContextObject | Nonevar ext : ExtensionObject | Nonevar model_configvar recorded_calls : list[RecordedCalls1 | RecordedCalls2]var since_timestamp : pydantic.types.AwareDatetimevar success : Literal[True]var total_count : intvar truncated : bool | None
Inherited members
class ComplyTestControllerResponse8 (**data: Any)-
Expand source code
class ComplyTestControllerResponse8(ComplyTestControllerResponse): model_config = ConfigDict( extra='allow', ) success: Literal[False] error: Annotated[ Error, Field( 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: Annotated[ str | None, Field(description='Human-readable explanation of the failure') ] = None current_state: Annotated[ str | None, Field(description='Current state of the entity, or null if not found') ] = None context: context_1.ContextObject | None = None ext: ext_1.ExtensionObject | None = NoneConstructible compatibility base for generated response arms.
Create a new model by parsing and validating input data from keyword arguments.
Raises [
ValidationError][pydantic_core.ValidationError] if the input data cannot be validated to form a valid model.selfis explicitly positional-only to allowselfas a field name.Ancestors
- ComplyTestControllerResponse
- AdcpResponse
- adcp.types.base._AdcpMessage
- ResponseArmDispatchMixin
- AdcpVersionEnvelope
- ProtocolEnvelope
- AdCPBaseModel
- pydantic.main.BaseModel
Class variables
var context : ContextObject | Nonevar current_state : str | Nonevar error : Errorvar error_detail : str | Nonevar ext : ExtensionObject | Nonevar model_configvar success : Literal[False]
Inherited members
class Error (*args, **kwds)-
Expand source code
class Error(StrEnum): INVALID_TRANSITION = 'INVALID_TRANSITION' INVALID_STATE = 'INVALID_STATE' NOT_FOUND = 'NOT_FOUND' UNKNOWN_SCENARIO = 'UNKNOWN_SCENARIO' INVALID_PARAMS = 'INVALID_PARAMS' FORBIDDEN = 'FORBIDDEN' JCS_NON_FINITE_NUMBER = 'JCS_NON_FINITE_NUMBER' INTERNAL_ERROR = 'INTERNAL_ERROR'Enum where members are also (and must be) strings
Ancestors
- enum.StrEnum
- builtins.str
- enum.ReprEnum
- enum.Enum
Class variables
var FORBIDDENvar INTERNAL_ERRORvar INVALID_PARAMSvar INVALID_STATEvar INVALID_TRANSITIONvar JCS_NON_FINITE_NUMBERvar NOT_FOUNDvar UNKNOWN_SCENARIO
class Forced (**data: Any)-
Expand source code
class Forced(AdCPBaseModel): model_config = ConfigDict( extra='forbid', ) arm: Annotated[ ComplyResponseArm, Field(description='ComplyResponseArm the seller will emit on the next forced operation response.') ] task_id: Annotated[ str | None, Field( description="Echo of the registered task_id. Present only when arm is 'submitted' (the arm that emits a task envelope).", max_length=128, ), ] = None evaluation_id: Annotated[ str | None, Field( description='Echo of the provider evaluation identity registered by force_get_creative_features_arm.', max_length=255, min_length=1, ), ] = None reason: Annotated[ str | None, Field( description="Echo of the deterministic buyer-facing rejection reason. Required when arm is 'rejected'.", max_length=2000, min_length=1, ), ] = None suggestions: Annotated[ list[Suggestion] | None, Field( description='Echo of the optional deterministic alternatives registered for a rejected get_products response.', max_length=20, min_length=1, ), ] = NoneBase model for AdCP types with spec-compliant serialization.
Defaults to
extra='ignore'so unknown fields from newer spec versions are silently dropped rather than causing validation errors. Generated types whose schemas setadditionalProperties: trueoverride this withextra='allow'in their ownmodel_config.Set
ADCP_STRICT_VALIDATION=1in the environment ("1","true","yes","on"are accepted) to flip the default toextra='forbid'. Use this during spec upgrades to catch silently-dropped renamed fields in tests. See :func:_resolve_extra_policy.Important
The env var is resolved once at module import time. Set it in your shell or CI environment before
import adcpruns — mutatingos.environ["ADCP_STRICT_VALIDATION"]after the firstadcpimport has no effect on already-imported model classes (they captured the policy at class-body evaluation).Consumers who want per-model strict validation can override
model_configon their subclass.Create a new model by parsing and validating input data from keyword arguments.
Raises [
ValidationError][pydantic_core.ValidationError] if the input data cannot be validated to form a valid model.selfis explicitly positional-only to allowselfas a field name.Ancestors
- AdCPBaseModel
- pydantic.main.BaseModel
Class variables
var arm : ComplyResponseArmvar evaluation_id : str | Nonevar model_configvar reason : str | Nonevar suggestions : list[Suggestion] | Nonevar task_id : str | None
Inherited members
class IdentifierMatchProof (**data: Any)-
Expand source code
class IdentifierMatchProof(AdCPBaseModel): model_config = ConfigDict( extra='forbid', ) identifier_value_sha256: Annotated[ str, Field( description='Echo of one digest from `params.identifier_value_digests` so the runner can pair this proof with the identifier it queried.', pattern='^[a-f0-9]{64}$', ), ] found: Annotated[ StrictBool, Field( description='True if any string token in the recorded payload hashes to the queried digest. False otherwise.' ), ]Base model for AdCP types with spec-compliant serialization.
Defaults to
extra='ignore'so unknown fields from newer spec versions are silently dropped rather than causing validation errors. Generated types whose schemas setadditionalProperties: trueoverride this withextra='allow'in their ownmodel_config.Set
ADCP_STRICT_VALIDATION=1in the environment ("1","true","yes","on"are accepted) to flip the default toextra='forbid'. Use this during spec upgrades to catch silently-dropped renamed fields in tests. See :func:_resolve_extra_policy.Important
The env var is resolved once at module import time. Set it in your shell or CI environment before
import adcpruns — mutatingos.environ["ADCP_STRICT_VALIDATION"]after the firstadcpimport has no effect on already-imported model classes (they captured the policy at class-body evaluation).Consumers who want per-model strict validation can override
model_configon their subclass.Create a new model by parsing and validating input data from keyword arguments.
Raises [
ValidationError][pydantic_core.ValidationError] if the input data cannot be validated to form a valid model.selfis explicitly positional-only to allowselfas a field name.Ancestors
- AdCPBaseModel
- pydantic.main.BaseModel
Class variables
var found : boolvar identifier_value_sha256 : strvar model_config
Inherited members
class Method (*args, **kwds)-
Expand source code
class Method(StrEnum): GET = 'GET' POST = 'POST' PUT = 'PUT' PATCH = 'PATCH' DELETE = 'DELETE' HEAD = 'HEAD' OPTIONS = 'OPTIONS'Enum where members are also (and must be) strings
Ancestors
- enum.StrEnum
- builtins.str
- enum.ReprEnum
- enum.Enum
Class variables
var DELETEvar GETvar HEADvar OPTIONSvar PATCHvar POSTvar PUT
class Purpose (*args, **kwds)-
Expand source code
class Purpose(StrEnum): platform_primary = 'platform_primary' measurement = 'measurement' attribution = 'attribution' creative_serving = 'creative_serving' identity = 'identity' other = 'other'Enum where members are also (and must be) strings
Ancestors
- enum.StrEnum
- builtins.str
- enum.ReprEnum
- enum.Enum
Class variables
var attributionvar creative_servingvar identityvar measurementvar othervar platform_primary
class RecordedCalls1 (**data: Any)-
Expand source code
class RecordedCalls1(AdCPBaseModel): model_config = ConfigDict( extra='forbid', ) method: Annotated[Method, Field(description='HTTP method of the outbound call.')] endpoint: Annotated[ str, Field( 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: Annotated[ AnyUrl, Field( 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: Annotated[ str | None, Field( description='Host portion of the URL, useful for grouping calls by upstream platform.' ), ] = None path: Annotated[ str | None, Field(description='Path portion of the URL (without query string).') ] = None content_type: Annotated[ str, Field( 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: Annotated[ Literal['raw'], Field( 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." ), ] = 'raw' purpose: Annotated[ Purpose | None, Field( 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." ), ] = None payload: Annotated[ Any, Field( 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.", max_length=65536, ), ] payload_digest_sha256: Annotated[ str | None, Field( 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.', pattern='^[a-f0-9]{64}$', ), ] = None payload_length: Annotated[ SchemaInt, Field( 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.', ge=0, ), ] identifier_match_proofs: Annotated[ list[IdentifierMatchProof] | None, Field( 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.', max_length=64, ), ] = None timestamp: Annotated[ AwareDatetime, Field( 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: Annotated[ SchemaInt | None, Field( description='HTTP status code returned by the upstream. Optional — adopters MAY omit when the call was instrumented before the response arrived.', ge=100, le=599, ), ] = NoneBase model for AdCP types with spec-compliant serialization.
Defaults to
extra='ignore'so unknown fields from newer spec versions are silently dropped rather than causing validation errors. Generated types whose schemas setadditionalProperties: trueoverride this withextra='allow'in their ownmodel_config.Set
ADCP_STRICT_VALIDATION=1in the environment ("1","true","yes","on"are accepted) to flip the default toextra='forbid'. Use this during spec upgrades to catch silently-dropped renamed fields in tests. See :func:_resolve_extra_policy.Important
The env var is resolved once at module import time. Set it in your shell or CI environment before
import adcpruns — mutatingos.environ["ADCP_STRICT_VALIDATION"]after the firstadcpimport has no effect on already-imported model classes (they captured the policy at class-body evaluation).Consumers who want per-model strict validation can override
model_configon their subclass.Create a new model by parsing and validating input data from keyword arguments.
Raises [
ValidationError][pydantic_core.ValidationError] if the input data cannot be validated to form a valid model.selfis explicitly positional-only to allowselfas a field name.Ancestors
- AdCPBaseModel
- pydantic.main.BaseModel
Class variables
var attestation_mode : Literal['raw']var content_type : strvar endpoint : strvar host : str | Nonevar identifier_match_proofs : list[IdentifierMatchProof] | Nonevar method : Methodvar model_configvar path : str | Nonevar payload : Anyvar payload_digest_sha256 : str | Nonevar payload_length : intvar purpose : Purpose | Nonevar status_code : int | Nonevar timestamp : pydantic.types.AwareDatetimevar url : pydantic.networks.AnyUrl
Inherited members
class RecordedCalls2 (**data: Any)-
Expand source code
class RecordedCalls2(AdCPBaseModel): model_config = ConfigDict( extra='forbid', ) method: Annotated[Method, Field(description='HTTP method of the outbound call.')] endpoint: Annotated[ str, Field( 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: Annotated[ AnyUrl, Field( 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: Annotated[ str | None, Field( description='Host portion of the URL, useful for grouping calls by upstream platform.' ), ] = None path: Annotated[ str | None, Field(description='Path portion of the URL (without query string).') ] = None content_type: Annotated[ str, Field( 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: Annotated[ Literal['digest'], Field( 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." ), ] = 'digest' purpose: Annotated[ Purpose | None, Field( 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." ), ] = None payload: Annotated[ Any | None, Field( 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.", max_length=65536, ), ] = None payload_digest_sha256: Annotated[ str, Field( 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.', pattern='^[a-f0-9]{64}$', ), ] payload_length: Annotated[ SchemaInt, Field( 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.', ge=0, ), ] identifier_match_proofs: Annotated[ list[IdentifierMatchProof] | None, Field( 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.', max_length=64, ), ] = None timestamp: Annotated[ AwareDatetime, Field( 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: Annotated[ SchemaInt | None, Field( description='HTTP status code returned by the upstream. Optional — adopters MAY omit when the call was instrumented before the response arrived.', ge=100, le=599, ), ] = NoneBase model for AdCP types with spec-compliant serialization.
Defaults to
extra='ignore'so unknown fields from newer spec versions are silently dropped rather than causing validation errors. Generated types whose schemas setadditionalProperties: trueoverride this withextra='allow'in their ownmodel_config.Set
ADCP_STRICT_VALIDATION=1in the environment ("1","true","yes","on"are accepted) to flip the default toextra='forbid'. Use this during spec upgrades to catch silently-dropped renamed fields in tests. See :func:_resolve_extra_policy.Important
The env var is resolved once at module import time. Set it in your shell or CI environment before
import adcpruns — mutatingos.environ["ADCP_STRICT_VALIDATION"]after the firstadcpimport has no effect on already-imported model classes (they captured the policy at class-body evaluation).Consumers who want per-model strict validation can override
model_configon their subclass.Create a new model by parsing and validating input data from keyword arguments.
Raises [
ValidationError][pydantic_core.ValidationError] if the input data cannot be validated to form a valid model.selfis explicitly positional-only to allowselfas a field name.Ancestors
- AdCPBaseModel
- pydantic.main.BaseModel
Class variables
var attestation_mode : Literal['digest']var content_type : strvar endpoint : strvar host : str | Nonevar identifier_match_proofs : list[IdentifierMatchProof] | Nonevar method : Methodvar model_configvar path : str | Nonevar payload : typing.Any | Nonevar payload_digest_sha256 : strvar payload_length : intvar purpose : Purpose | Nonevar status_code : int | Nonevar timestamp : pydantic.types.AwareDatetimevar url : pydantic.networks.AnyUrl
Inherited members
class Suggestion (value: Any = <object object>, *, root: Any = <object object>)-
Expand source code
class Suggestion(ScalarStr): __slots__ = () _constraints = {'max_length': 1000, 'min_length': 1}A
strgenerated from a JSON Schema string root.Ancestors
- adcp.types._scalar.ScalarStr
- adcp.types._scalar._ScalarRoot
- builtins.str