Module adcp.decisioning.resolve
Async framework-mediated resource resolver for :class:RequestContext.
Defines:
- :class:
ResourceResolver— Protocol for async fetches of framework-validated resources (property lists, collection lists, creative formats). The framework owns the cache + validation; platform methods get pre-validated typed results. - :class:
_NotYetWiredResolver— v6.0 stub. Raises :class:NotImplementedErroron every call with a pointer to the v6.1 follow-up. Asymmetry vs. thestatestub (which returns empty + warns) is deliberate: an empty :class:PropertyListReferencein v6.0 vs. a real one in v6.1 is divergence the framework cannot silently paper over. Seedocs/proposals/decisioning-platform-dispatch-design.md#d15.
The :class:Format and :class:PropertyListReference types are
re-exported from :mod:adcp.types.generated_poc so adopters import
once from :mod:adcp.decisioning. :class:PropertyListReference and
:class:CollectionList use the spec-defined wire shapes; the
resolver returns the same Pydantic models adopters would construct
themselves.
Classes
class CollectionList (**data: Any)-
Expand source code
class CollectionList(AdCPBaseModel): model_config = ConfigDict( extra='forbid', ) list_id: Annotated[str, Field(description='Unique identifier for this collection list')] name: Annotated[str, Field(description='Human-readable name for the list')] description: Annotated[str | None, Field(description="Description of the list's purpose")] = ( None ) account: Annotated[ account_ref.AccountReference | None, Field( description='Account that owns this list. Returned as account_id form (seller-assigned identifier).' ), ] = None base_collections: Annotated[ list[base_collection_source.BaseCollectionSource] | None, Field( description="Array of collection sources to evaluate. Each entry is a discriminated union: distribution_ids (platform-independent identifiers), publisher_collections (publisher_domain + collection_ids), or publisher_genres (publisher_domain + genres). If omitted, queries the agent's entire collection database." ), ] = None filters: Annotated[ collection_list_filters.CollectionListFilters | None, Field(description='Dynamic filters applied when resolving the list'), ] = None brand: Annotated[ brand_ref.BrandReference | None, Field( description='Brand reference used to automatically apply appropriate rules. Resolved to full brand identity at execution time.' ), ] = None webhook_url: Annotated[ AnyUrl | None, Field(description='URL to receive notifications when the resolved list changes'), ] = None cache_duration_hours: Annotated[ int | None, Field( description='Recommended cache duration for resolved list. Consumers should re-fetch after this period. Defaults to 168 (one week) because collection metadata changes less frequently than property metadata.', ge=1, ), ] = 168 created_at: Annotated[AwareDatetime | None, Field(description='When the list was created')] = ( None ) updated_at: Annotated[ AwareDatetime | None, Field(description='When the list was last modified') ] = None collection_count: Annotated[ int | None, Field( description='Number of collections in the resolved list (at time of last resolution)' ), ] = 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 account : adcp.types.generated_poc.core.account_ref.AccountReference | Nonevar base_collections : list[adcp.types.generated_poc.collection.base_collection_source.BaseCollectionSource] | Nonevar brand : adcp.types.generated_poc.core.brand_ref.BrandReference | Nonevar cache_duration_hours : int | Nonevar collection_count : int | Nonevar created_at : pydantic.types.AwareDatetime | Nonevar description : str | Nonevar filters : adcp.types.generated_poc.collection.collection_list_filters.CollectionListFilters | Nonevar list_id : strvar model_configvar name : strvar updated_at : pydantic.types.AwareDatetime | Nonevar webhook_url : pydantic.networks.AnyUrl | None
Inherited members
class Format (**data: Any)-
Expand source code
class Format(AdCPBaseModel): model_config = ConfigDict( extra='allow', ) format_id: Annotated[ format_id_1.FormatReferenceStructuredObject, Field( description="This format's own identifier — a structured object {agent_url, id}, not a string. See /schemas/core/format-id.json for the full shape." ), ] name: Annotated[str, Field(description='Human-readable format name')] description: Annotated[ str | None, Field( description='Plain text explanation of what this format does and what assets it requires' ), ] = None example_url: Annotated[ AnyUrl | None, Field( description='Optional URL to showcase page with examples and interactive demos of this format' ), ] = None accepts_parameters: Annotated[ list[format_id_parameter.FormatIdParameter] | None, Field( description='List of parameters this format accepts in format_id. Template formats define which parameters (dimensions, duration, etc.) can be specified when instantiating the format. Empty or omitted means this is a concrete format with fixed parameters.' ), ] = None renders: Annotated[ list[Renders | Renders1] | None, Field( description='Specification of rendered pieces for this format. Most formats produce a single render. Companion ad formats (video + banner), adaptive formats, and multi-placement formats produce multiple renders. Each render specifies its role and dimensions.', min_length=1, ), ] = None assets: Annotated[ list[ Assets | Assets10 | Assets11 | Assets12 | Assets13 | Assets14 | Assets15 | Assets16 | Assets17 | Assets18 | Assets19 | Assets20 | Assets21 | Assets22 | Assets23 | Assets24 ] | None, Field( description="Array of all assets supported for this format. Each asset is identified by its asset_id, which must be used as the key in creative manifests. Use the 'required' boolean on each asset to indicate whether it's mandatory." ), ] = None delivery: Annotated[ dict[str, Any] | None, Field(description='Delivery method specifications (e.g., hosted, VAST, third-party tags)'), ] = None supported_macros: Annotated[ list[universal_macro.UniversalMacro | str] | None, Field( description='List of universal macros supported by this format (e.g., MEDIA_BUY_ID, CACHEBUSTER, DEVICE_ID). Used for validation and developer tooling. See docs/creative/universal-macros.mdx for full documentation.' ), ] = None input_format_ids: Annotated[ list[format_id_1.FormatReferenceStructuredObject] | None, Field( deprecated=True, description='**DEPRECATED in 3.1. Removed at 4.0.** Use `list_transformers` instead — a transformer declares its own `input_format_ids`/`output_format_ids`, so build capability is a property of the transformer (the unit you select and that carries pricing), not a relationship hung on a format. Discover build capability via `list_transformers` (optionally filtered by `input_format_ids`/`output_format_ids`).\n\nMigration: sellers that expressed transform capability by hanging `input_format_ids` on a format SHOULD declare a transformer via `list_transformers` instead. Buyers SHOULD discover build capability via `list_transformers` rather than filtering formats.\n\n*Legacy behavior, retained for 3.1–3.x backward compatibility:* array of format IDs this format accepts as input creative manifests; when present, indicates this format can take existing creatives in these formats as input. SDKs reading 3.1 catalogs MUST continue to honor this field when present; 4.0+ SDKs MAY reject it. New code SHOULD NOT emit this field.', ), ] = None output_format_ids: Annotated[ list[format_id_1.FormatReferenceStructuredObject] | None, Field( deprecated=True, description='**DEPRECATED in 3.1. Removed at 4.0.** Use `list_transformers` instead — a transformer declares its own `output_format_ids`, so what a builder can produce is a property of the transformer, not a relationship hung on a format. Discover via `list_transformers`.\n\nMigration: sellers that expressed multi-output build capability (e.g. a multi-publisher template) by hanging `output_format_ids` on a format SHOULD declare a transformer via `list_transformers` instead.\n\n*Legacy behavior, retained for 3.1–3.x backward compatibility:* array of format IDs this format can produce as output; when present, indicates this format can build creatives in these output formats. SDKs reading 3.1 catalogs MUST continue to honor this field when present; 4.0+ SDKs MAY reject it. New code SHOULD NOT emit this field.', ), ] = None format_card: Annotated[ FormatCard | None, Field( description='Optional standard visual card (300x400px) for displaying this format in user interfaces. Can be rendered via preview_creative or pre-generated.' ), ] = None accessibility: Annotated[ Accessibility | None, Field( description='Accessibility posture of this format. Declares the WCAG conformance level that creatives produced by this format will meet.' ), ] = None supported_disclosure_positions: Annotated[ list[disclosure_position.DisclosurePosition] | None, Field( description='Disclosure positions this format can render. Buyers use this to determine whether a format can satisfy their compliance requirements before submitting a creative. When omitted, the format makes no disclosure rendering guarantees — creative agents SHOULD treat this as incompatible with briefs that require specific disclosure positions. Values correspond to positions on creative-brief.json required_disclosures.', min_length=1, ), ] = None disclosure_capabilities: Annotated[ list[DisclosureCapability] | None, Field( description='Structured disclosure capabilities per position with persistence modes. Declares which persistence behaviors each disclosure position supports, enabling persistence-aware matching against provenance render guidance and brief requirements. When present, supersedes supported_disclosure_positions for persistence-aware queries. The flat supported_disclosure_positions field is retained for backward compatibility. Each position MUST appear at most once; validators and agents SHOULD reject duplicates.', min_length=1, ), ] = None format_card_detailed: Annotated[ FormatCardDetailed | None, Field( description='Optional detailed card with carousel and full specifications. Provides rich format documentation similar to ad spec pages.' ), ] = None reported_metrics: Annotated[ list[available_metric.AvailableMetric] | None, Field( description='Metrics this format can produce in delivery reporting. Buyers receive the intersection of format reported_metrics and product available_metrics. If omitted, the format defers entirely to product-level metric declarations.', min_length=1, ), ] = None pricing_options: Annotated[ list[vendor_pricing_option.VendorPricingOption] | None, Field( deprecated=True, description='**DEPRECATED in 3.1. Removed at 4.0.** Use `transformer.pricing_options` (via `list_transformers`) instead — pricing belongs on the transformer (the unit selected and billed), exactly as it belongs on a media-buy product. Once formats only describe output shape, format-level pricing is vestigial.\n\nMigration: transformation/generation agents that charged via `format.pricing_options` SHOULD move the same `vendor-pricing-option` entries onto the corresponding transformer. The applied option is echoed per-leaf on the build_creative response and reconciled via report_usage, unchanged.\n\n*Legacy behavior, retained for 3.1–3.x backward compatibility:* pricing options for this format, used by transformation/generation agents that charge per format adapted, per image generated, or per unit of work; present when the request included include_pricing=true and account. SDKs reading 3.1 catalogs MUST continue to honor this field when present; 4.0+ SDKs MAY reject it. New code SHOULD NOT emit this field.', min_length=1, ), ] = None canonical: Annotated[ canonical_projection_ref.CanonicalProjectionReference | None, Field( description='Optional v2 canonical-projection annotation. Always an object — bare-string shorthand (`canonical: "image"`) is not supported; the minimal form is `canonical: { "kind": "image" }`. Carries `kind` (which canonical the v1 format projects to) plus optional `asset_source` and `slots_override` for cases where the v1 format\'s shape doesn\'t follow the canonical\'s defaults (e.g., generative entries whose input is `generation_prompt: text` instead of `image_main: image`).\n\nWhen set, SDKs use this annotation as the authoritative v1 → v2 mapping for this format, bypassing the [v1 canonical mapping registry](/schemas/registries/v1-canonical-mapping.json) lookup. Combined with the slot-level `asset_group_id` declarations on each `assets[i]` entry, a v1 format declaration with `canonical` set is fully self-describing for v1↔v2 translation.\n\nResolution order for SDK projection from v1 wire shape to v2 (per RFC #3305 amendment #3767):\n1. If this `canonical` field is set, use it (seller-declared, highest priority). Apply `asset_source` and `slots_override` from the projection ref when present; otherwise inherit the canonical\'s defaults.\n2. Else, look up `format_id` in the canonical mapping registry\'s `format_id_glob` entries.\n3. Else, attempt structural match against the registry\'s `structural` entries (asset types, slot shape, vast_versions, etc.).\n4. Else, fail closed: SDK MUST NOT emit `format_options` for products carrying this format. Surface `FORMAT_PROJECTION_FAILED` on the response `errors[]` suggesting the seller add an explicit `canonical` annotation or file a registry entry.\n\nWhen `canonical.kind` is `custom`, the seller MUST also declare `canonical_format_shape` and `canonical_format_schema` (parallel to ProductFormatDeclaration\'s `format_shape` and `format_schema`) so buyer SDKs can fetch the seller\'s custom format schema.\n\nSee `canonical-projection-ref.json` for full projection semantics and examples (default-slot case, generative case, brief-driven case).' ), ] = None canonical_parameters: Annotated[ product_format_declaration.ProductFormatDeclaration | None, Field( deprecated=True, description="**DEPRECATED in 3.1. Removed at 4.0.** Use `v1_format_ref` on the v2 `ProductFormatDeclaration` instead — the seller authors a v2 declaration (in `Product.format_options` or `creative.supported_formats`) and links it back to this v1 format via `v1_format_ref: { agent_url, id }`. The directional link from v2 → v1 is the same fact as `canonical_parameters` without the parallel-shape drift surface (v1 file and `canonical_parameters` were two declarations of the same thing; hand-authored, drifting silently).\n\nMigration: every seller currently authoring `canonical_parameters` SHOULD migrate to authoring a v2 declaration on the corresponding product (or capability) with `v1_format_ref` pointing back at this v1 format. v1 files become pure v1 again — no v2-shape mirroring.\n\n*Legacy behavior, retained for 3.1–3.x backward compatibility:* When `canonical` is set, this field carries the full ProductFormatDeclaration that the SDK projects this v1 format into. The `format_kind` MUST equal the `canonical` field value (validators enforce). When set, this is the authoritative source for SDK v1→v2 projection — the registry's structural-match parameter inference is bypassed. SDKs reading 3.1 catalogs MUST continue to honor `canonical_parameters` when present; 4.0+ SDKs MAY reject the field. New code SHOULD NOT emit this field.\n\n**Drift contract (still normative while supported).** Hand-authored `canonical_parameters` MUST satisfy the *narrows* relation against this v1 format's `requirements` and `assets[*]` shape (see canonical-formats.mdx 'Narrows — formal definition'). SDKs that read this v1 file SHOULD lint-time check the equivalence at build/load and emit `FORMAT_PROJECTION_FAILED` if the two disagree.", ), ] = 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 accepts_parameters : list[adcp.types.generated_poc.enums.format_id_parameter.FormatIdParameter] | Nonevar accessibility : adcp.types.generated_poc.core.format.Accessibility | Nonevar assets : list[typing.Union[adcp.types.generated_poc.core.format.Assets, adcp.types.generated_poc.core.format.Assets10, adcp.types.generated_poc.core.format.Assets11, adcp.types.generated_poc.core.format.Assets12, adcp.types.generated_poc.core.format.Assets13, adcp.types.generated_poc.core.format.Assets14, adcp.types.generated_poc.core.format.Assets15, adcp.types.generated_poc.core.format.Assets16, adcp.types.generated_poc.core.format.Assets18, adcp.types.generated_poc.core.format.Assets19, adcp.types.generated_poc.core.format.Assets20, adcp.types.generated_poc.core.format.Assets21, adcp.types.generated_poc.core.format.Assets22, adcp.types.generated_poc.core.format.Assets23, adcp.types.generated_poc.core.format.Assets24, UnknownFormatAsset]] | Nonevar canonical : adcp.types.generated_poc.core.canonical_projection_ref.CanonicalProjectionReference | Nonevar delivery : dict[str, typing.Any] | Nonevar description : str | Nonevar disclosure_capabilities : list[adcp.types.generated_poc.core.format.DisclosureCapability] | Nonevar example_url : pydantic.networks.AnyUrl | Nonevar format_card : adcp.types.generated_poc.core.format.FormatCard | Nonevar format_card_detailed : adcp.types.generated_poc.core.format.FormatCardDetailed | Nonevar format_id : adcp.types.generated_poc.core.format_id.FormatReferenceStructuredObjectvar model_configvar name : strvar renders : list[adcp.types.generated_poc.core.format.Renders | adcp.types.generated_poc.core.format.Renders1] | Nonevar reported_metrics : list[adcp.types.generated_poc.enums.available_metric.AvailableMetric] | Nonevar supported_disclosure_positions : list[adcp.types.generated_poc.enums.disclosure_position.DisclosurePosition] | Nonevar supported_macros : list[adcp.types.generated_poc.enums.universal_macro.UniversalMacro | str] | None
Instance variables
var canonical_parameters : adcp.types.generated_poc.core.product_format_declaration.ProductFormatDeclaration | None-
Expand source code
def __get__(self, obj: BaseModel | None, obj_type: type[BaseModel] | None = None) -> Any: if obj is None: if self.wrapped_property is not None: return self.wrapped_property.__get__(None, obj_type) raise AttributeError(self.field_name) warnings.warn(self.msg, DeprecationWarning, stacklevel=2) if self.wrapped_property is not None: return self.wrapped_property.__get__(obj, obj_type) return obj.__dict__[self.field_name]Read-only data descriptor used to emit a runtime deprecation warning before accessing a deprecated field.
Attributes
msg- The deprecation message to be emitted.
wrapped_property- The property instance if the deprecated field is a computed field, or
None. field_name- The name of the field being deprecated.
var input_format_ids : list[adcp.types.generated_poc.core.format_id.FormatReferenceStructuredObject] | None-
Expand source code
def __get__(self, obj: BaseModel | None, obj_type: type[BaseModel] | None = None) -> Any: if obj is None: if self.wrapped_property is not None: return self.wrapped_property.__get__(None, obj_type) raise AttributeError(self.field_name) warnings.warn(self.msg, DeprecationWarning, stacklevel=2) if self.wrapped_property is not None: return self.wrapped_property.__get__(obj, obj_type) return obj.__dict__[self.field_name]Read-only data descriptor used to emit a runtime deprecation warning before accessing a deprecated field.
Attributes
msg- The deprecation message to be emitted.
wrapped_property- The property instance if the deprecated field is a computed field, or
None. field_name- The name of the field being deprecated.
var output_format_ids : list[adcp.types.generated_poc.core.format_id.FormatReferenceStructuredObject] | None-
Expand source code
def __get__(self, obj: BaseModel | None, obj_type: type[BaseModel] | None = None) -> Any: if obj is None: if self.wrapped_property is not None: return self.wrapped_property.__get__(None, obj_type) raise AttributeError(self.field_name) warnings.warn(self.msg, DeprecationWarning, stacklevel=2) if self.wrapped_property is not None: return self.wrapped_property.__get__(obj, obj_type) return obj.__dict__[self.field_name]Read-only data descriptor used to emit a runtime deprecation warning before accessing a deprecated field.
Attributes
msg- The deprecation message to be emitted.
wrapped_property- The property instance if the deprecated field is a computed field, or
None. field_name- The name of the field being deprecated.
var pricing_options : list[adcp.types.generated_poc.core.vendor_pricing_option.VendorPricingOption] | None-
Expand source code
def __get__(self, obj: BaseModel | None, obj_type: type[BaseModel] | None = None) -> Any: if obj is None: if self.wrapped_property is not None: return self.wrapped_property.__get__(None, obj_type) raise AttributeError(self.field_name) warnings.warn(self.msg, DeprecationWarning, stacklevel=2) if self.wrapped_property is not None: return self.wrapped_property.__get__(obj, obj_type) return obj.__dict__[self.field_name]Read-only data descriptor used to emit a runtime deprecation warning before accessing a deprecated field.
Attributes
msg- The deprecation message to be emitted.
wrapped_property- The property instance if the deprecated field is a computed field, or
None. field_name- The name of the field being deprecated.
Inherited members
class FormatReferenceStructuredObject (**data: Any)-
Expand source code
class FormatReferenceStructuredObject(AdCPBaseModel): model_config = ConfigDict( extra='allow', ) agent_url: Annotated[ AnyUrl, Field( description="URL of the agent that defines this format (e.g., 'https://creative.adcontextprotocol.org' for standard formats, or 'https://publisher.com/.well-known/adcp/sales' for custom formats). Callers comparing two `format-id` values MUST canonicalize `agent_url` per the AdCP URL canonicalization rules before treating two formats as the same. See docs/reference/url-canonicalization." ), ] id: Annotated[ str, Field( description="Format identifier within the agent's namespace (e.g., 'display_static', 'video_hosted', 'audio_standard'). When used alone, references a template format. When combined with dimension/duration fields, creates a parameterized format ID for a specific variant.", pattern='^[a-zA-Z0-9_-]+$', ), ] width: Annotated[ int | None, Field( description='Width in pixels for visual formats. When specified, height must also be specified. Both fields together create a parameterized format ID for dimension-specific variants.', ge=1, ), ] = None height: Annotated[ int | None, Field( description='Height in pixels for visual formats. When specified, width must also be specified. Both fields together create a parameterized format ID for dimension-specific variants.', ge=1, ), ] = None duration_ms: Annotated[ float | None, Field( description='Duration in milliseconds for time-based formats (video, audio). When specified, creates a parameterized format ID. Omit to reference a template format without parameters.', ge=1.0, ), ] = 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 agent_url : pydantic.networks.AnyUrlvar duration_ms : float | Nonevar height : int | Nonevar id : strvar model_configvar width : int | None
Inherited members
class PropertyList (**data: Any)-
Expand source code
class PropertyListReference(AdCPBaseModel): model_config = ConfigDict( extra='forbid', ) agent_url: Annotated[AnyUrl, Field(description='URL of the agent managing the property list')] list_id: Annotated[ str, Field(description='Identifier for the property list within the agent', min_length=1) ] auth_token: Annotated[ str | None, Field( description='JWT or other authorization token for accessing the list. Optional if the list is public or caller has implicit access.' ), ] = 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 agent_url : pydantic.networks.AnyUrlvar auth_token : str | Nonevar list_id : strvar model_config
class PropertyListReference (**data: Any)-
Expand source code
class PropertyListReference(AdCPBaseModel): model_config = ConfigDict( extra='forbid', ) agent_url: Annotated[AnyUrl, Field(description='URL of the agent managing the property list')] list_id: Annotated[ str, Field(description='Identifier for the property list within the agent', min_length=1) ] auth_token: Annotated[ str | None, Field( description='JWT or other authorization token for accessing the list. Optional if the list is public or caller has implicit access.' ), ] = 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 agent_url : pydantic.networks.AnyUrlvar auth_token : str | Nonevar list_id : strvar model_config
Inherited members
class ResourceResolver (*args, **kwargs)-
Expand source code
@runtime_checkable class ResourceResolver(Protocol): """Async fetches of framework-mediated resources. Platforms call ``ctx.resolve.property_list(list_id)`` instead of fetching from their own DB; the framework returns a validated typed result. The resolver routes through ``capabilities.creative_agents`` for creative-format reads, hits the framework's local ``CreativePlatform.list_formats`` for self-hosted formats, and reads the seller's declared property / collection lists with id-validation built in. Framework-supplied; never constructed by adopter code. The ``RequestContext.resolve`` field is populated by the dispatch hydration helper. Adopters substituting test doubles use :func:`dataclasses.replace` on the context, not direct construction. Mirrors the TS-side ``ResourceResolver`` interface in ``src/lib/server/decisioning/context.ts``. v6.0 ships the contract + the no-op stub (raises ``NotImplementedError`` on every call); v6.1 lands the backing fetchers. .. note:: :class:`runtime_checkable` Protocols only check attribute *presence*. Whether a method is ``async def`` is irrelevant to the runtime ``isinstance`` check — a sync method named ``property_list`` would pass the structural check but fail at ``await`` time. Use mypy to enforce ``async def`` signatures across adopter impls. """ async def property_list(self, list_id: str) -> PropertyList: """Fetch a property list by id. Framework validates the id exists in the seller's declared lists before returning; consumers can trust the result.""" ... async def collection_list(self, list_id: str) -> CollectionList: """Fetch a collection list by id. Same id-validation guarantee as :meth:`property_list`.""" ... async def creative_format( self, format_id: FormatReferenceStructuredObject, *, revalidate: bool = False, ) -> Format: """Fetch a creative format definition. Routes through ``capabilities.creative_agents`` declaration with a framework-managed cache; self-hosted formats hit the local ``CreativePlatform.list_formats``. Returns the resolved :class:`Format` with full asset slot definitions. :param revalidate: When ``True``, bypasses the framework cache and re-fetches from the upstream creative-agent. Adopters with freshness needs (e.g., creative submission validating against the latest format spec) pass ``revalidate=True``; most reads use the default (``False``) to amortize the agent round-trip. Cache TTL is implementation detail (defaults to 1h on the reference impl); adopters who need stricter freshness use ``revalidate=True`` rather than depending on the TTL value. """ ...Async fetches of framework-mediated resources.
Platforms call
ctx.resolve.property_list(list_id)instead of fetching from their own DB; the framework returns a validated typed result. The resolver routes throughcapabilities.creative_agentsfor creative-format reads, hits the framework's localCreativePlatform.list_formatsfor self-hosted formats, and reads the seller's declared property / collection lists with id-validation built in.Framework-supplied; never constructed by adopter code. The
RequestContext.resolvefield is populated by the dispatch hydration helper. Adopters substituting test doubles use :func:dataclasses.replaceon the context, not direct construction.Mirrors the TS-side
ResourceResolverinterface insrc/lib/server/decisioning/context.ts. v6.0 ships the contract + the no-op stub (raisesNotImplementedErroron every call); v6.1 lands the backing fetchers.Note
:class:
runtime_checkableProtocols only check attribute presence. Whether a method isasync defis irrelevant to the runtimeisinstancecheck — a sync method namedproperty_listwould pass the structural check but fail atawaittime. Use mypy to enforceasync defsignatures across adopter impls.Ancestors
- typing.Protocol
- typing.Generic
Methods
async def collection_list(self, list_id: str) ‑> adcp.types.generated_poc.collection.collection_list.CollectionList-
Expand source code
async def collection_list(self, list_id: str) -> CollectionList: """Fetch a collection list by id. Same id-validation guarantee as :meth:`property_list`.""" ...Fetch a collection list by id. Same id-validation guarantee as :meth:
property_list. async def creative_format(self,
format_id: FormatReferenceStructuredObject,
*,
revalidate: bool = False) ‑> adcp.types.generated_poc.core.format.Format-
Expand source code
async def creative_format( self, format_id: FormatReferenceStructuredObject, *, revalidate: bool = False, ) -> Format: """Fetch a creative format definition. Routes through ``capabilities.creative_agents`` declaration with a framework-managed cache; self-hosted formats hit the local ``CreativePlatform.list_formats``. Returns the resolved :class:`Format` with full asset slot definitions. :param revalidate: When ``True``, bypasses the framework cache and re-fetches from the upstream creative-agent. Adopters with freshness needs (e.g., creative submission validating against the latest format spec) pass ``revalidate=True``; most reads use the default (``False``) to amortize the agent round-trip. Cache TTL is implementation detail (defaults to 1h on the reference impl); adopters who need stricter freshness use ``revalidate=True`` rather than depending on the TTL value. """ ...Fetch a creative format definition.
Routes through
capabilities.creative_agentsdeclaration with a framework-managed cache; self-hosted formats hit the localCreativePlatform.list_formats. Returns the resolved :class:Formatwith full asset slot definitions.:param revalidate: When
True, bypasses the framework cache and re-fetches from the upstream creative-agent. Adopters with freshness needs (e.g., creative submission validating against the latest format spec) passrevalidate=True; most reads use the default (False) to amortize the agent round-trip.Cache TTL is implementation detail (defaults to 1h on the reference impl); adopters who need stricter freshness use
revalidate=Truerather than depending on the TTL value. async def property_list(self, list_id: str) ‑> adcp.types.generated_poc.core.property_list_ref.PropertyListReference-
Expand source code
async def property_list(self, list_id: str) -> PropertyList: """Fetch a property list by id. Framework validates the id exists in the seller's declared lists before returning; consumers can trust the result.""" ...Fetch a property list by id. Framework validates the id exists in the seller's declared lists before returning; consumers can trust the result.