diff --git a/README.md b/README.md index a6c52ee5a..58c34e2c8 100644 --- a/README.md +++ b/README.md @@ -276,7 +276,7 @@ async with ADCPMultiAgentClient( ## AdCP version support -The 7.x line is built against **AdCP 3.1.8 stable**, makes canonical creatives +The 7.x line is built against **AdCP 3.1.10 stable**, makes canonical creatives the primary Python contract, and negotiates AdCP 3.0, 3.1, and 3.2 wire dialects. The SDK package version and protocol version are intentionally independent: @@ -285,7 +285,7 @@ independent: import adcp adcp.get_adcp_sdk_version() # SDK package version, e.g. "7.0.0rc1" -adcp.get_adcp_spec_version() # AdCP spec this build targets, e.g. "3.1.8" +adcp.get_adcp_spec_version() # AdCP spec this build targets, e.g. "3.1.10" ``` If you talk to an agent on a newer spec than this SDK validates, the response diff --git a/SCHEMA_DELTAS.md b/SCHEMA_DELTAS.md index 3fbd9bf1d..14c0feba5 100644 --- a/SCHEMA_DELTAS.md +++ b/SCHEMA_DELTAS.md @@ -1,15 +1,18 @@ # Generated-types delta +## Files added + +- `trusted_match/provider_identity_match_response.py` — IdentityMatchResponseProviderRouter +- `trusted_match/publisher_tmpx_config.py` — PublisherTmpxMacroMapping +- `trusted_match/tmpx_chunk.py` — TmpxChunk + ## Field changes -- `bundled/protocol/get_adcp_capabilities_response.py` - - **classes added**: EventType2, Features2, Idempotency3, MraidVersion2, SupportedTarget3, Type12, VastVersion2 - - **classes removed**: EventType1, Features1, Idempotency1, MraidVersion1, SupportedTarget1, Type9, VastVersion1 -- `creative/list_creatives_response.py` - - **classes added**: Creatives, Creatives1 - - **classes removed**: Creative -- `protocol/get_adcp_capabilities_response.py` - - **classes added**: Idempotency1, SupportedTarget1, Type9 - - **classes removed**: Idempotency3, SupportedTarget3, Type12 -- `signals/activate_signal_request.py` - - `ActivateSignalRequest`: `+governance_context` +- `trusted_match/identity_match_response.py` + - **classes added**: IdentityMatchResponseRouterPublisher + - **classes removed**: IdentityMatchResponse + - `TmpxProviders`: `+chunks` `-macros` +- `trusted_match/provider_registration.py` + - **classes added**: TmpxSlot + - `TmpProviderRegistration1`: `+tmpx_slots` `-tmpx_macros` + - `TmpProviderRegistration2`: `+tmpx_slots` `-tmpx_macros` diff --git a/schemas/cache/3.1/adagents.json b/schemas/cache/3.1/adagents.json index f1d8b678c..38b2be4ec 100644 --- a/schemas/cache/3.1/adagents.json +++ b/schemas/cache/3.1/adagents.json @@ -786,12 +786,12 @@ ], "examples": [ { - "$schema": "/schemas/3.1.8/adagents.json", + "$schema": "/schemas/3.1.10/adagents.json", "authoritative_location": "https://cdn.example.com/adagents/v2/adagents.json", "last_updated": "2025-01-15T10:00:00Z" }, { - "$schema": "/schemas/3.1.8/adagents.json", + "$schema": "/schemas/3.1.10/adagents.json", "properties": [ { "property_id": "example_site", @@ -872,7 +872,7 @@ "last_updated": "2025-01-10T12:00:00Z" }, { - "$schema": "/schemas/3.1.8/adagents.json", + "$schema": "/schemas/3.1.10/adagents.json", "contact": { "name": "Meta Advertising Operations", "email": "adops@meta.com", @@ -981,7 +981,7 @@ "last_updated": "2025-01-10T15:30:00Z" }, { - "$schema": "/schemas/3.1.8/adagents.json", + "$schema": "/schemas/3.1.10/adagents.json", "contact": { "name": "Tumblr Advertising" }, @@ -1020,7 +1020,7 @@ "last_updated": "2025-01-10T16:00:00Z" }, { - "$schema": "/schemas/3.1.8/adagents.json", + "$schema": "/schemas/3.1.10/adagents.json", "contact": { "name": "Example Third-Party Sales Agent", "email": "sales@agent.example", @@ -1085,7 +1085,7 @@ "last_updated": "2025-01-10T17:00:00Z" }, { - "$schema": "/schemas/3.1.8/adagents.json", + "$schema": "/schemas/3.1.10/adagents.json", "contact": { "name": "Premium News Publisher", "email": "adops@news.example.com", @@ -1160,7 +1160,7 @@ "last_updated": "2025-01-10T18:00:00Z" }, { - "$schema": "/schemas/3.1.8/adagents.json", + "$schema": "/schemas/3.1.10/adagents.json", "contact": { "name": "Polk Automotive Data", "email": "partnerships@polk.com", diff --git a/schemas/cache/3.1/brand.json b/schemas/cache/3.1/brand.json index 3606330d8..06565e879 100644 --- a/schemas/cache/3.1/brand.json +++ b/schemas/cache/3.1/brand.json @@ -2720,16 +2720,16 @@ ], "examples": [ { - "$schema": "/schemas/3.1.8/brand.json", + "$schema": "/schemas/3.1.10/brand.json", "authoritative_location": "https://adcontextprotocol.org/brand/abc123/brand.json" }, { - "$schema": "/schemas/3.1.8/brand.json", + "$schema": "/schemas/3.1.10/brand.json", "house": "nikeinc.com", "note": "Redirect to house domain for full brand portfolio" }, { - "$schema": "/schemas/3.1.8/brand.json", + "$schema": "/schemas/3.1.10/brand.json", "version": "1.0", "agents": [ { @@ -2740,7 +2740,7 @@ ] }, { - "$schema": "/schemas/3.1.8/brand.json", + "$schema": "/schemas/3.1.10/brand.json", "version": "1.0", "house": { "domain": "pg.com", @@ -3041,7 +3041,7 @@ "last_updated": "2026-01-15T10:00:00Z" }, { - "$schema": "/schemas/3.1.8/brand.json", + "$schema": "/schemas/3.1.10/brand.json", "version": "1.0", "house": { "domain": "nikeinc.com", @@ -3222,7 +3222,7 @@ "last_updated": "2026-01-15T10:00:00Z" }, { - "$schema": "/schemas/3.1.8/brand.json", + "$schema": "/schemas/3.1.10/brand.json", "version": "1.0", "house": { "domain": "mediavine.com", @@ -3273,7 +3273,7 @@ "last_updated": "2026-01-15T10:00:00Z" }, { - "$schema": "/schemas/3.1.8/brand.json", + "$schema": "/schemas/3.1.10/brand.json", "version": "1.0", "house": { "domain": "nikeinc.com", @@ -3310,7 +3310,7 @@ "last_updated": "2026-01-15T10:00:00Z" }, { - "$schema": "/schemas/3.1.8/brand.json", + "$schema": "/schemas/3.1.10/brand.json", "version": "1.0", "house": { "domain": "wpp.com", @@ -3335,7 +3335,7 @@ "last_updated": "2026-01-15T10:00:00Z" }, { - "$schema": "/schemas/3.1.8/brand.json", + "$schema": "/schemas/3.1.10/brand.json", "version": "1.0", "id": "converse", "names": [ @@ -3355,7 +3355,7 @@ "last_updated": "2026-01-15T10:00:00Z" }, { - "$schema": "/schemas/3.1.8/brand.json", + "$schema": "/schemas/3.1.10/brand.json", "version": "1.0", "id": "patagonia", "names": [ diff --git a/schemas/cache/3.1/bundled/content-standards/calibrate-content-request.json b/schemas/cache/3.1/bundled/content-standards/calibrate-content-request.json index cd3d9a840..7d736d344 100644 --- a/schemas/cache/3.1/bundled/content-standards/calibrate-content-request.json +++ b/schemas/cache/3.1/bundled/content-standards/calibrate-content-request.json @@ -2279,7 +2279,7 @@ } }, "_bundled": { - "generatedAt": "2026-07-28T13:04:06.248Z", + "generatedAt": "2026-08-04T05:39:57.421Z", "note": "This is a bundled schema with all $ref resolved inline. For the modular version with references, use the parent directory." } } \ No newline at end of file diff --git a/schemas/cache/3.1/bundled/content-standards/calibrate-content-response.json b/schemas/cache/3.1/bundled/content-standards/calibrate-content-response.json index 130652429..561e18ea5 100644 --- a/schemas/cache/3.1/bundled/content-standards/calibrate-content-response.json +++ b/schemas/cache/3.1/bundled/content-standards/calibrate-content-response.json @@ -667,7 +667,7 @@ ], "properties": {}, "_bundled": { - "generatedAt": "2026-07-28T13:04:06.250Z", + "generatedAt": "2026-08-04T05:39:57.424Z", "note": "This is a bundled schema with all $ref resolved inline. For the modular version with references, use the parent directory." } } \ No newline at end of file diff --git a/schemas/cache/3.1/bundled/content-standards/create-content-standards-request.json b/schemas/cache/3.1/bundled/content-standards/create-content-standards-request.json index b23ece0b2..70befe15a 100644 --- a/schemas/cache/3.1/bundled/content-standards/create-content-standards-request.json +++ b/schemas/cache/3.1/bundled/content-standards/create-content-standards-request.json @@ -4697,7 +4697,7 @@ } }, "_bundled": { - "generatedAt": "2026-07-28T13:04:06.264Z", + "generatedAt": "2026-08-04T05:39:57.444Z", "note": "This is a bundled schema with all $ref resolved inline. For the modular version with references, use the parent directory." } } \ No newline at end of file diff --git a/schemas/cache/3.1/bundled/content-standards/create-content-standards-response.json b/schemas/cache/3.1/bundled/content-standards/create-content-standards-response.json index 298253806..be29188a6 100644 --- a/schemas/cache/3.1/bundled/content-standards/create-content-standards-response.json +++ b/schemas/cache/3.1/bundled/content-standards/create-content-standards-response.json @@ -603,7 +603,7 @@ ], "properties": {}, "_bundled": { - "generatedAt": "2026-07-28T13:04:06.271Z", + "generatedAt": "2026-08-04T05:39:57.450Z", "note": "This is a bundled schema with all $ref resolved inline. For the modular version with references, use the parent directory." } } \ No newline at end of file diff --git a/schemas/cache/3.1/bundled/content-standards/get-content-standards-request.json b/schemas/cache/3.1/bundled/content-standards/get-content-standards-request.json index 7a86a95d6..2d1e029df 100644 --- a/schemas/cache/3.1/bundled/content-standards/get-content-standards-request.json +++ b/schemas/cache/3.1/bundled/content-standards/get-content-standards-request.json @@ -51,7 +51,7 @@ "standards_id" ], "_bundled": { - "generatedAt": "2026-07-28T13:04:06.272Z", + "generatedAt": "2026-08-04T05:39:57.450Z", "note": "This is a bundled schema with all $ref resolved inline. For the modular version with references, use the parent directory." } } \ No newline at end of file diff --git a/schemas/cache/3.1/bundled/content-standards/get-content-standards-response.json b/schemas/cache/3.1/bundled/content-standards/get-content-standards-response.json index c3f349c9e..bfd3de339 100644 --- a/schemas/cache/3.1/bundled/content-standards/get-content-standards-response.json +++ b/schemas/cache/3.1/bundled/content-standards/get-content-standards-response.json @@ -5454,7 +5454,7 @@ } }, "_bundled": { - "generatedAt": "2026-07-28T13:04:06.284Z", + "generatedAt": "2026-08-04T05:39:57.465Z", "note": "This is a bundled schema with all $ref resolved inline. For the modular version with references, use the parent directory." } } \ No newline at end of file diff --git a/schemas/cache/3.1/bundled/content-standards/get-media-buy-artifacts-request.json b/schemas/cache/3.1/bundled/content-standards/get-media-buy-artifacts-request.json index 5967323b0..0d3d027e4 100644 --- a/schemas/cache/3.1/bundled/content-standards/get-media-buy-artifacts-request.json +++ b/schemas/cache/3.1/bundled/content-standards/get-media-buy-artifacts-request.json @@ -743,7 +743,7 @@ "media_buy_id" ], "_bundled": { - "generatedAt": "2026-07-28T13:04:06.290Z", + "generatedAt": "2026-08-04T05:39:57.471Z", "note": "This is a bundled schema with all $ref resolved inline. For the modular version with references, use the parent directory." } } \ No newline at end of file diff --git a/schemas/cache/3.1/bundled/content-standards/get-media-buy-artifacts-response.json b/schemas/cache/3.1/bundled/content-standards/get-media-buy-artifacts-response.json index 81ddfdeeb..1705a0b63 100644 --- a/schemas/cache/3.1/bundled/content-standards/get-media-buy-artifacts-response.json +++ b/schemas/cache/3.1/bundled/content-standards/get-media-buy-artifacts-response.json @@ -2921,7 +2921,7 @@ } }, "_bundled": { - "generatedAt": "2026-07-28T13:04:06.295Z", + "generatedAt": "2026-08-04T05:39:57.476Z", "note": "This is a bundled schema with all $ref resolved inline. For the modular version with references, use the parent directory." } } \ No newline at end of file diff --git a/schemas/cache/3.1/bundled/content-standards/list-content-standards-request.json b/schemas/cache/3.1/bundled/content-standards/list-content-standards-request.json index 7ca732730..091f6351a 100644 --- a/schemas/cache/3.1/bundled/content-standards/list-content-standards-request.json +++ b/schemas/cache/3.1/bundled/content-standards/list-content-standards-request.json @@ -134,7 +134,7 @@ }, "additionalProperties": true, "_bundled": { - "generatedAt": "2026-07-28T13:04:06.297Z", + "generatedAt": "2026-08-04T05:39:57.478Z", "note": "This is a bundled schema with all $ref resolved inline. For the modular version with references, use the parent directory." } } \ No newline at end of file diff --git a/schemas/cache/3.1/bundled/content-standards/list-content-standards-response.json b/schemas/cache/3.1/bundled/content-standards/list-content-standards-response.json index 3daadec84..bbafae28e 100644 --- a/schemas/cache/3.1/bundled/content-standards/list-content-standards-response.json +++ b/schemas/cache/3.1/bundled/content-standards/list-content-standards-response.json @@ -5483,7 +5483,7 @@ } }, "_bundled": { - "generatedAt": "2026-07-28T13:04:06.304Z", + "generatedAt": "2026-08-04T05:39:57.485Z", "note": "This is a bundled schema with all $ref resolved inline. For the modular version with references, use the parent directory." } } \ No newline at end of file diff --git a/schemas/cache/3.1/bundled/content-standards/update-content-standards-request.json b/schemas/cache/3.1/bundled/content-standards/update-content-standards-request.json index d86113928..0c8617a83 100644 --- a/schemas/cache/3.1/bundled/content-standards/update-content-standards-request.json +++ b/schemas/cache/3.1/bundled/content-standards/update-content-standards-request.json @@ -4686,7 +4686,7 @@ } }, "_bundled": { - "generatedAt": "2026-07-28T13:04:06.311Z", + "generatedAt": "2026-08-04T05:39:57.494Z", "note": "This is a bundled schema with all $ref resolved inline. For the modular version with references, use the parent directory." } } \ No newline at end of file diff --git a/schemas/cache/3.1/bundled/content-standards/update-content-standards-response.json b/schemas/cache/3.1/bundled/content-standards/update-content-standards-response.json index 83b691a34..71ff01937 100644 --- a/schemas/cache/3.1/bundled/content-standards/update-content-standards-response.json +++ b/schemas/cache/3.1/bundled/content-standards/update-content-standards-response.json @@ -618,7 +618,7 @@ ], "properties": {}, "_bundled": { - "generatedAt": "2026-07-28T13:04:06.313Z", + "generatedAt": "2026-08-04T05:39:57.496Z", "note": "This is a bundled schema with all $ref resolved inline. For the modular version with references, use the parent directory." } } \ No newline at end of file diff --git a/schemas/cache/3.1/bundled/content-standards/validate-content-delivery-request.json b/schemas/cache/3.1/bundled/content-standards/validate-content-delivery-request.json index 0aef9cfe4..312b93213 100644 --- a/schemas/cache/3.1/bundled/content-standards/validate-content-delivery-request.json +++ b/schemas/cache/3.1/bundled/content-standards/validate-content-delivery-request.json @@ -2333,7 +2333,7 @@ } }, "_bundled": { - "generatedAt": "2026-07-28T13:04:06.316Z", + "generatedAt": "2026-08-04T05:39:57.498Z", "note": "This is a bundled schema with all $ref resolved inline. For the modular version with references, use the parent directory." } } \ No newline at end of file diff --git a/schemas/cache/3.1/bundled/content-standards/validate-content-delivery-response.json b/schemas/cache/3.1/bundled/content-standards/validate-content-delivery-response.json index e742b70ae..1fa4eeab2 100644 --- a/schemas/cache/3.1/bundled/content-standards/validate-content-delivery-response.json +++ b/schemas/cache/3.1/bundled/content-standards/validate-content-delivery-response.json @@ -695,7 +695,7 @@ ], "properties": {}, "_bundled": { - "generatedAt": "2026-07-28T13:04:06.317Z", + "generatedAt": "2026-08-04T05:39:57.500Z", "note": "This is a bundled schema with all $ref resolved inline. For the modular version with references, use the parent directory." } } \ No newline at end of file diff --git a/schemas/cache/3.1/bundled/core/tasks-get-request.json b/schemas/cache/3.1/bundled/core/tasks-get-request.json index 295d669ee..6315d00f7 100644 --- a/schemas/cache/3.1/bundled/core/tasks-get-request.json +++ b/schemas/cache/3.1/bundled/core/tasks-get-request.json @@ -737,7 +737,7 @@ } ], "_bundled": { - "generatedAt": "2026-07-28T13:04:06.319Z", + "generatedAt": "2026-08-04T05:39:57.502Z", "note": "This is a bundled schema with all $ref resolved inline. For the modular version with references, use the parent directory." } } \ No newline at end of file diff --git a/schemas/cache/3.1/bundled/core/tasks-get-response.json b/schemas/cache/3.1/bundled/core/tasks-get-response.json index 993d690e0..de97d69fe 100644 --- a/schemas/cache/3.1/bundled/core/tasks-get-response.json +++ b/schemas/cache/3.1/bundled/core/tasks-get-response.json @@ -158095,7 +158095,7 @@ } }, "_bundled": { - "generatedAt": "2026-07-28T13:04:06.584Z", + "generatedAt": "2026-08-04T05:39:57.783Z", "note": "This is a bundled schema with all $ref resolved inline. For the modular version with references, use the parent directory." } } \ No newline at end of file diff --git a/schemas/cache/3.1/bundled/core/tasks-list-request.json b/schemas/cache/3.1/bundled/core/tasks-list-request.json index e7956eb5a..5fc4138af 100644 --- a/schemas/cache/3.1/bundled/core/tasks-list-request.json +++ b/schemas/cache/3.1/bundled/core/tasks-list-request.json @@ -993,7 +993,7 @@ } }, "_bundled": { - "generatedAt": "2026-07-28T13:04:06.655Z", + "generatedAt": "2026-08-04T05:39:57.854Z", "note": "This is a bundled schema with all $ref resolved inline. For the modular version with references, use the parent directory." } } \ No newline at end of file diff --git a/schemas/cache/3.1/bundled/core/tasks-list-response.json b/schemas/cache/3.1/bundled/core/tasks-list-response.json index f0b6aa08d..4f561852a 100644 --- a/schemas/cache/3.1/bundled/core/tasks-list-response.json +++ b/schemas/cache/3.1/bundled/core/tasks-list-response.json @@ -665,7 +665,7 @@ } }, "_bundled": { - "generatedAt": "2026-07-28T13:04:06.657Z", + "generatedAt": "2026-08-04T05:39:57.855Z", "note": "This is a bundled schema with all $ref resolved inline. For the modular version with references, use the parent directory." } } \ No newline at end of file diff --git a/schemas/cache/3.1/bundled/creative/get-creative-delivery-request.json b/schemas/cache/3.1/bundled/creative/get-creative-delivery-request.json index b4368432d..f9cda7446 100644 --- a/schemas/cache/3.1/bundled/creative/get-creative-delivery-request.json +++ b/schemas/cache/3.1/bundled/creative/get-creative-delivery-request.json @@ -754,7 +754,7 @@ ], "additionalProperties": true, "_bundled": { - "generatedAt": "2026-07-28T13:04:06.658Z", + "generatedAt": "2026-08-04T05:39:57.856Z", "note": "This is a bundled schema with all $ref resolved inline. For the modular version with references, use the parent directory." } } \ No newline at end of file diff --git a/schemas/cache/3.1/bundled/creative/get-creative-delivery-response.json b/schemas/cache/3.1/bundled/creative/get-creative-delivery-response.json index ac8ba6b85..ed382df64 100644 --- a/schemas/cache/3.1/bundled/creative/get-creative-delivery-response.json +++ b/schemas/cache/3.1/bundled/creative/get-creative-delivery-response.json @@ -23570,7 +23570,7 @@ } }, "_bundled": { - "generatedAt": "2026-07-28T13:04:06.691Z", + "generatedAt": "2026-08-04T05:39:57.890Z", "note": "This is a bundled schema with all $ref resolved inline. For the modular version with references, use the parent directory." } } \ No newline at end of file diff --git a/schemas/cache/3.1/bundled/creative/get-creative-features-request.json b/schemas/cache/3.1/bundled/creative/get-creative-features-request.json index b95bdad59..7ec484194 100644 --- a/schemas/cache/3.1/bundled/creative/get-creative-features-request.json +++ b/schemas/cache/3.1/bundled/creative/get-creative-features-request.json @@ -20170,7 +20170,7 @@ } }, "_bundled": { - "generatedAt": "2026-07-28T13:04:06.726Z", + "generatedAt": "2026-08-04T05:39:57.922Z", "note": "This is a bundled schema with all $ref resolved inline. For the modular version with references, use the parent directory." } } \ No newline at end of file diff --git a/schemas/cache/3.1/bundled/creative/get-creative-features-response.json b/schemas/cache/3.1/bundled/creative/get-creative-features-response.json index 86c2a2597..10b677d04 100644 --- a/schemas/cache/3.1/bundled/creative/get-creative-features-response.json +++ b/schemas/cache/3.1/bundled/creative/get-creative-features-response.json @@ -836,7 +836,7 @@ ], "properties": {}, "_bundled": { - "generatedAt": "2026-07-28T13:04:06.732Z", + "generatedAt": "2026-08-04T05:39:57.930Z", "note": "This is a bundled schema with all $ref resolved inline. For the modular version with references, use the parent directory." } } \ No newline at end of file diff --git a/schemas/cache/3.1/bundled/creative/list-creative-formats-request.json b/schemas/cache/3.1/bundled/creative/list-creative-formats-request.json index 24421bdfc..b7b357850 100644 --- a/schemas/cache/3.1/bundled/creative/list-creative-formats-request.json +++ b/schemas/cache/3.1/bundled/creative/list-creative-formats-request.json @@ -988,7 +988,7 @@ } }, "_bundled": { - "generatedAt": "2026-07-28T13:04:06.734Z", + "generatedAt": "2026-08-04T05:39:57.931Z", "note": "This is a bundled schema with all $ref resolved inline. For the modular version with references, use the parent directory." } } \ No newline at end of file diff --git a/schemas/cache/3.1/bundled/creative/list-creative-formats-response.json b/schemas/cache/3.1/bundled/creative/list-creative-formats-response.json index b6445cefa..0d92c36c8 100644 --- a/schemas/cache/3.1/bundled/creative/list-creative-formats-response.json +++ b/schemas/cache/3.1/bundled/creative/list-creative-formats-response.json @@ -13645,7 +13645,7 @@ } }, "_bundled": { - "generatedAt": "2026-07-28T13:04:06.747Z", + "generatedAt": "2026-08-04T05:39:57.945Z", "note": "This is a bundled schema with all $ref resolved inline. For the modular version with references, use the parent directory." } } \ No newline at end of file diff --git a/schemas/cache/3.1/bundled/creative/list-creatives-request.json b/schemas/cache/3.1/bundled/creative/list-creatives-request.json index 93a09fed5..58709f075 100644 --- a/schemas/cache/3.1/bundled/creative/list-creatives-request.json +++ b/schemas/cache/3.1/bundled/creative/list-creatives-request.json @@ -1666,7 +1666,7 @@ } }, "_bundled": { - "generatedAt": "2026-07-28T13:04:06.755Z", + "generatedAt": "2026-08-04T05:39:57.951Z", "note": "This is a bundled schema with all $ref resolved inline. For the modular version with references, use the parent directory." } } \ No newline at end of file diff --git a/schemas/cache/3.1/bundled/creative/list-creatives-response.json b/schemas/cache/3.1/bundled/creative/list-creatives-response.json index 0f32692b9..8b9e4972d 100644 --- a/schemas/cache/3.1/bundled/creative/list-creatives-response.json +++ b/schemas/cache/3.1/bundled/creative/list-creatives-response.json @@ -21408,7 +21408,7 @@ } }, "_bundled": { - "generatedAt": "2026-07-28T13:04:06.777Z", + "generatedAt": "2026-08-04T05:39:57.975Z", "note": "This is a bundled schema with all $ref resolved inline. For the modular version with references, use the parent directory." } } \ No newline at end of file diff --git a/schemas/cache/3.1/bundled/creative/list-transformers-request.json b/schemas/cache/3.1/bundled/creative/list-transformers-request.json index b9b5f352c..22ca90084 100644 --- a/schemas/cache/3.1/bundled/creative/list-transformers-request.json +++ b/schemas/cache/3.1/bundled/creative/list-transformers-request.json @@ -887,7 +887,7 @@ }, "additionalProperties": true, "_bundled": { - "generatedAt": "2026-07-28T13:04:06.785Z", + "generatedAt": "2026-08-04T05:39:57.984Z", "note": "This is a bundled schema with all $ref resolved inline. For the modular version with references, use the parent directory." } } \ No newline at end of file diff --git a/schemas/cache/3.1/bundled/creative/list-transformers-response.json b/schemas/cache/3.1/bundled/creative/list-transformers-response.json index cd1457fa4..e66610411 100644 --- a/schemas/cache/3.1/bundled/creative/list-transformers-response.json +++ b/schemas/cache/3.1/bundled/creative/list-transformers-response.json @@ -1413,7 +1413,7 @@ ], "additionalProperties": true, "_bundled": { - "generatedAt": "2026-07-28T13:04:06.787Z", + "generatedAt": "2026-08-04T05:39:57.986Z", "note": "This is a bundled schema with all $ref resolved inline. For the modular version with references, use the parent directory." } } \ No newline at end of file diff --git a/schemas/cache/3.1/bundled/creative/preview-creative-request.json b/schemas/cache/3.1/bundled/creative/preview-creative-request.json index 43550c60d..b259405ff 100644 --- a/schemas/cache/3.1/bundled/creative/preview-creative-request.json +++ b/schemas/cache/3.1/bundled/creative/preview-creative-request.json @@ -38730,7 +38730,7 @@ } }, "_bundled": { - "generatedAt": "2026-07-28T13:04:06.828Z", + "generatedAt": "2026-08-04T05:39:58.027Z", "note": "This is a bundled schema with all $ref resolved inline. For the modular version with references, use the parent directory." } } \ No newline at end of file diff --git a/schemas/cache/3.1/bundled/creative/preview-creative-response.json b/schemas/cache/3.1/bundled/creative/preview-creative-response.json index c7a4995d8..36dbc2c65 100644 --- a/schemas/cache/3.1/bundled/creative/preview-creative-response.json +++ b/schemas/cache/3.1/bundled/creative/preview-creative-response.json @@ -21080,7 +21080,7 @@ } }, "_bundled": { - "generatedAt": "2026-07-28T13:04:06.862Z", + "generatedAt": "2026-08-04T05:39:58.063Z", "note": "This is a bundled schema with all $ref resolved inline. For the modular version with references, use the parent directory." } } \ No newline at end of file diff --git a/schemas/cache/3.1/bundled/creative/sync-creatives-request.json b/schemas/cache/3.1/bundled/creative/sync-creatives-request.json index 4a46761ef..f85858a72 100644 --- a/schemas/cache/3.1/bundled/creative/sync-creatives-request.json +++ b/schemas/cache/3.1/bundled/creative/sync-creatives-request.json @@ -19885,7 +19885,7 @@ } }, "_bundled": { - "generatedAt": "2026-07-28T13:04:06.889Z", + "generatedAt": "2026-08-04T05:39:58.091Z", "note": "This is a bundled schema with all $ref resolved inline. For the modular version with references, use the parent directory." } } \ No newline at end of file diff --git a/schemas/cache/3.1/bundled/creative/sync-creatives-response.json b/schemas/cache/3.1/bundled/creative/sync-creatives-response.json index d58b98c84..025bb1d87 100644 --- a/schemas/cache/3.1/bundled/creative/sync-creatives-response.json +++ b/schemas/cache/3.1/bundled/creative/sync-creatives-response.json @@ -2448,7 +2448,7 @@ } }, "_bundled": { - "generatedAt": "2026-07-28T13:04:06.898Z", + "generatedAt": "2026-08-04T05:39:58.101Z", "note": "This is a bundled schema with all $ref resolved inline. For the modular version with references, use the parent directory." } } \ No newline at end of file diff --git a/schemas/cache/3.1/bundled/creative/validate-input-request.json b/schemas/cache/3.1/bundled/creative/validate-input-request.json index aeb1b5d7c..72ea6bc62 100644 --- a/schemas/cache/3.1/bundled/creative/validate-input-request.json +++ b/schemas/cache/3.1/bundled/creative/validate-input-request.json @@ -20724,7 +20724,7 @@ } }, "_bundled": { - "generatedAt": "2026-07-28T13:04:06.920Z", + "generatedAt": "2026-08-04T05:39:58.123Z", "note": "This is a bundled schema with all $ref resolved inline. For the modular version with references, use the parent directory." } } \ No newline at end of file diff --git a/schemas/cache/3.1/bundled/creative/validate-input-response.json b/schemas/cache/3.1/bundled/creative/validate-input-response.json index e221b9d76..31d1e6b4e 100644 --- a/schemas/cache/3.1/bundled/creative/validate-input-response.json +++ b/schemas/cache/3.1/bundled/creative/validate-input-response.json @@ -592,7 +592,7 @@ } ], "_bundled": { - "generatedAt": "2026-07-28T13:04:06.927Z", + "generatedAt": "2026-08-04T05:39:58.131Z", "note": "This is a bundled schema with all $ref resolved inline. For the modular version with references, use the parent directory." } } \ No newline at end of file diff --git a/schemas/cache/3.1/bundled/media-buy/build-creative-request.json b/schemas/cache/3.1/bundled/media-buy/build-creative-request.json index 07623a82b..7f2c31d2d 100644 --- a/schemas/cache/3.1/bundled/media-buy/build-creative-request.json +++ b/schemas/cache/3.1/bundled/media-buy/build-creative-request.json @@ -26224,7 +26224,7 @@ } }, "_bundled": { - "generatedAt": "2026-07-28T13:04:06.955Z", + "generatedAt": "2026-08-04T05:39:58.159Z", "note": "This is a bundled schema with all $ref resolved inline. For the modular version with references, use the parent directory." } } \ No newline at end of file diff --git a/schemas/cache/3.1/bundled/media-buy/build-creative-response.json b/schemas/cache/3.1/bundled/media-buy/build-creative-response.json index 54ed0bdae..a83d70da9 100644 --- a/schemas/cache/3.1/bundled/media-buy/build-creative-response.json +++ b/schemas/cache/3.1/bundled/media-buy/build-creative-response.json @@ -60679,7 +60679,7 @@ } }, "_bundled": { - "generatedAt": "2026-07-28T13:04:07.058Z", + "generatedAt": "2026-08-04T05:39:58.270Z", "note": "This is a bundled schema with all $ref resolved inline. For the modular version with references, use the parent directory." } } \ No newline at end of file diff --git a/schemas/cache/3.1/bundled/media-buy/create-media-buy-request.json b/schemas/cache/3.1/bundled/media-buy/create-media-buy-request.json index 66b540ae6..a5a6f9964 100644 --- a/schemas/cache/3.1/bundled/media-buy/create-media-buy-request.json +++ b/schemas/cache/3.1/bundled/media-buy/create-media-buy-request.json @@ -27058,7 +27058,7 @@ } }, "_bundled": { - "generatedAt": "2026-07-28T13:04:07.108Z", + "generatedAt": "2026-08-04T05:39:58.324Z", "note": "This is a bundled schema with all $ref resolved inline. For the modular version with references, use the parent directory." } } \ No newline at end of file diff --git a/schemas/cache/3.1/bundled/media-buy/create-media-buy-response.json b/schemas/cache/3.1/bundled/media-buy/create-media-buy-response.json index 54fd61353..bf43c4801 100644 --- a/schemas/cache/3.1/bundled/media-buy/create-media-buy-response.json +++ b/schemas/cache/3.1/bundled/media-buy/create-media-buy-response.json @@ -10489,7 +10489,7 @@ } }, "_bundled": { - "generatedAt": "2026-07-28T13:04:07.128Z", + "generatedAt": "2026-08-04T05:39:58.344Z", "note": "This is a bundled schema with all $ref resolved inline. For the modular version with references, use the parent directory." } } \ No newline at end of file diff --git a/schemas/cache/3.1/bundled/media-buy/get-media-buy-delivery-request.json b/schemas/cache/3.1/bundled/media-buy/get-media-buy-delivery-request.json index 37a58f6d5..0cc965ea7 100644 --- a/schemas/cache/3.1/bundled/media-buy/get-media-buy-delivery-request.json +++ b/schemas/cache/3.1/bundled/media-buy/get-media-buy-delivery-request.json @@ -1332,7 +1332,7 @@ } }, "_bundled": { - "generatedAt": "2026-07-28T13:04:07.133Z", + "generatedAt": "2026-08-04T05:39:58.349Z", "note": "This is a bundled schema with all $ref resolved inline. For the modular version with references, use the parent directory." } } \ No newline at end of file diff --git a/schemas/cache/3.1/bundled/media-buy/get-media-buy-delivery-response.json b/schemas/cache/3.1/bundled/media-buy/get-media-buy-delivery-response.json index 60b929310..d3216957b 100644 --- a/schemas/cache/3.1/bundled/media-buy/get-media-buy-delivery-response.json +++ b/schemas/cache/3.1/bundled/media-buy/get-media-buy-delivery-response.json @@ -22157,7 +22157,7 @@ } }, "_bundled": { - "generatedAt": "2026-07-28T13:04:07.154Z", + "generatedAt": "2026-08-04T05:39:58.371Z", "note": "This is a bundled schema with all $ref resolved inline. For the modular version with references, use the parent directory." } } \ No newline at end of file diff --git a/schemas/cache/3.1/bundled/media-buy/get-media-buys-request.json b/schemas/cache/3.1/bundled/media-buy/get-media-buys-request.json index 1b99b12fc..a1bee723f 100644 --- a/schemas/cache/3.1/bundled/media-buy/get-media-buys-request.json +++ b/schemas/cache/3.1/bundled/media-buy/get-media-buys-request.json @@ -782,7 +782,7 @@ } }, "_bundled": { - "generatedAt": "2026-07-28T13:04:07.164Z", + "generatedAt": "2026-08-04T05:39:58.380Z", "note": "This is a bundled schema with all $ref resolved inline. For the modular version with references, use the parent directory." } } \ No newline at end of file diff --git a/schemas/cache/3.1/bundled/media-buy/get-media-buys-response.json b/schemas/cache/3.1/bundled/media-buy/get-media-buys-response.json index 274efd609..6c9f9d03c 100644 --- a/schemas/cache/3.1/bundled/media-buy/get-media-buys-response.json +++ b/schemas/cache/3.1/bundled/media-buy/get-media-buys-response.json @@ -6142,7 +6142,7 @@ } }, "_bundled": { - "generatedAt": "2026-07-28T13:04:07.170Z", + "generatedAt": "2026-08-04T05:39:58.386Z", "note": "This is a bundled schema with all $ref resolved inline. For the modular version with references, use the parent directory." } } \ No newline at end of file diff --git a/schemas/cache/3.1/bundled/media-buy/get-products-request.json b/schemas/cache/3.1/bundled/media-buy/get-products-request.json index dc3038e2d..35b7d2c82 100644 --- a/schemas/cache/3.1/bundled/media-buy/get-products-request.json +++ b/schemas/cache/3.1/bundled/media-buy/get-products-request.json @@ -5317,7 +5317,7 @@ } }, "_bundled": { - "generatedAt": "2026-07-28T13:04:07.177Z", + "generatedAt": "2026-08-04T05:39:58.394Z", "note": "This is a bundled schema with all $ref resolved inline. For the modular version with references, use the parent directory." } } \ No newline at end of file diff --git a/schemas/cache/3.1/bundled/media-buy/get-products-response.json b/schemas/cache/3.1/bundled/media-buy/get-products-response.json index d3ce49393..7299d6b71 100644 --- a/schemas/cache/3.1/bundled/media-buy/get-products-response.json +++ b/schemas/cache/3.1/bundled/media-buy/get-products-response.json @@ -37002,7 +37002,7 @@ } }, "_bundled": { - "generatedAt": "2026-07-28T13:04:07.218Z", + "generatedAt": "2026-08-04T05:39:58.432Z", "note": "This is a bundled schema with all $ref resolved inline. For the modular version with references, use the parent directory." } } \ No newline at end of file diff --git a/schemas/cache/3.1/bundled/media-buy/list-creative-formats-request.json b/schemas/cache/3.1/bundled/media-buy/list-creative-formats-request.json index 0f07cc48b..f8679ec7b 100644 --- a/schemas/cache/3.1/bundled/media-buy/list-creative-formats-request.json +++ b/schemas/cache/3.1/bundled/media-buy/list-creative-formats-request.json @@ -343,7 +343,7 @@ }, "additionalProperties": true, "_bundled": { - "generatedAt": "2026-07-28T13:04:07.229Z", + "generatedAt": "2026-08-04T05:39:58.444Z", "note": "This is a bundled schema with all $ref resolved inline. For the modular version with references, use the parent directory." } } \ No newline at end of file diff --git a/schemas/cache/3.1/bundled/media-buy/list-creative-formats-response.json b/schemas/cache/3.1/bundled/media-buy/list-creative-formats-response.json index 8b1391509..541924b99 100644 --- a/schemas/cache/3.1/bundled/media-buy/list-creative-formats-response.json +++ b/schemas/cache/3.1/bundled/media-buy/list-creative-formats-response.json @@ -13658,7 +13658,7 @@ } }, "_bundled": { - "generatedAt": "2026-07-28T13:04:07.244Z", + "generatedAt": "2026-08-04T05:39:58.455Z", "note": "This is a bundled schema with all $ref resolved inline. For the modular version with references, use the parent directory." } } \ No newline at end of file diff --git a/schemas/cache/3.1/bundled/media-buy/log-event-request.json b/schemas/cache/3.1/bundled/media-buy/log-event-request.json index abd9be2bd..78dd2f51f 100644 --- a/schemas/cache/3.1/bundled/media-buy/log-event-request.json +++ b/schemas/cache/3.1/bundled/media-buy/log-event-request.json @@ -627,7 +627,7 @@ ], "additionalProperties": true, "_bundled": { - "generatedAt": "2026-07-28T13:04:07.252Z", + "generatedAt": "2026-08-04T05:39:58.461Z", "note": "This is a bundled schema with all $ref resolved inline. For the modular version with references, use the parent directory." } } \ No newline at end of file diff --git a/schemas/cache/3.1/bundled/media-buy/log-event-response.json b/schemas/cache/3.1/bundled/media-buy/log-event-response.json index b5435f62e..1cf084565 100644 --- a/schemas/cache/3.1/bundled/media-buy/log-event-response.json +++ b/schemas/cache/3.1/bundled/media-buy/log-event-response.json @@ -680,7 +680,7 @@ ], "properties": {}, "_bundled": { - "generatedAt": "2026-07-28T13:04:07.253Z", + "generatedAt": "2026-08-04T05:39:58.462Z", "note": "This is a bundled schema with all $ref resolved inline. For the modular version with references, use the parent directory." } } \ No newline at end of file diff --git a/schemas/cache/3.1/bundled/media-buy/package-request.json b/schemas/cache/3.1/bundled/media-buy/package-request.json index 2f046e76f..69a3c6423 100644 --- a/schemas/cache/3.1/bundled/media-buy/package-request.json +++ b/schemas/cache/3.1/bundled/media-buy/package-request.json @@ -25250,7 +25250,7 @@ } }, "_bundled": { - "generatedAt": "2026-07-28T13:04:07.277Z", + "generatedAt": "2026-08-04T05:39:58.486Z", "note": "This is a bundled schema with all $ref resolved inline. For the modular version with references, use the parent directory." } } \ No newline at end of file diff --git a/schemas/cache/3.1/bundled/media-buy/provide-performance-feedback-request.json b/schemas/cache/3.1/bundled/media-buy/provide-performance-feedback-request.json index 071ee6bab..d1b0c1eda 100644 --- a/schemas/cache/3.1/bundled/media-buy/provide-performance-feedback-request.json +++ b/schemas/cache/3.1/bundled/media-buy/provide-performance-feedback-request.json @@ -132,7 +132,7 @@ ], "additionalProperties": true, "_bundled": { - "generatedAt": "2026-07-28T13:04:07.285Z", + "generatedAt": "2026-08-04T05:39:58.494Z", "note": "This is a bundled schema with all $ref resolved inline. For the modular version with references, use the parent directory." } } \ No newline at end of file diff --git a/schemas/cache/3.1/bundled/media-buy/provide-performance-feedback-response.json b/schemas/cache/3.1/bundled/media-buy/provide-performance-feedback-response.json index 90d1f5d78..7fdbfc699 100644 --- a/schemas/cache/3.1/bundled/media-buy/provide-performance-feedback-response.json +++ b/schemas/cache/3.1/bundled/media-buy/provide-performance-feedback-response.json @@ -629,7 +629,7 @@ ], "properties": {}, "_bundled": { - "generatedAt": "2026-07-28T13:04:07.286Z", + "generatedAt": "2026-08-04T05:39:58.495Z", "note": "This is a bundled schema with all $ref resolved inline. For the modular version with references, use the parent directory." } } \ No newline at end of file diff --git a/schemas/cache/3.1/bundled/media-buy/sync-audiences-request.json b/schemas/cache/3.1/bundled/media-buy/sync-audiences-request.json index 704702db4..5af5630de 100644 --- a/schemas/cache/3.1/bundled/media-buy/sync-audiences-request.json +++ b/schemas/cache/3.1/bundled/media-buy/sync-audiences-request.json @@ -965,7 +965,7 @@ } }, "_bundled": { - "generatedAt": "2026-07-28T13:04:07.287Z", + "generatedAt": "2026-08-04T05:39:58.496Z", "note": "This is a bundled schema with all $ref resolved inline. For the modular version with references, use the parent directory." } } \ No newline at end of file diff --git a/schemas/cache/3.1/bundled/media-buy/sync-audiences-response.json b/schemas/cache/3.1/bundled/media-buy/sync-audiences-response.json index 2448a4dea..3be1b3b17 100644 --- a/schemas/cache/3.1/bundled/media-buy/sync-audiences-response.json +++ b/schemas/cache/3.1/bundled/media-buy/sync-audiences-response.json @@ -1104,7 +1104,7 @@ ], "properties": {}, "_bundled": { - "generatedAt": "2026-07-28T13:04:07.289Z", + "generatedAt": "2026-08-04T05:39:58.498Z", "note": "This is a bundled schema with all $ref resolved inline. For the modular version with references, use the parent directory." } } \ No newline at end of file diff --git a/schemas/cache/3.1/bundled/media-buy/sync-catalogs-request.json b/schemas/cache/3.1/bundled/media-buy/sync-catalogs-request.json index d0b5f5666..a25ad7678 100644 --- a/schemas/cache/3.1/bundled/media-buy/sync-catalogs-request.json +++ b/schemas/cache/3.1/bundled/media-buy/sync-catalogs-request.json @@ -1372,7 +1372,7 @@ } ], "_bundled": { - "generatedAt": "2026-07-28T13:04:07.291Z", + "generatedAt": "2026-08-04T05:39:58.499Z", "note": "This is a bundled schema with all $ref resolved inline. For the modular version with references, use the parent directory." } } \ No newline at end of file diff --git a/schemas/cache/3.1/bundled/media-buy/sync-catalogs-response.json b/schemas/cache/3.1/bundled/media-buy/sync-catalogs-response.json index 85d0f84aa..82ba2cc54 100644 --- a/schemas/cache/3.1/bundled/media-buy/sync-catalogs-response.json +++ b/schemas/cache/3.1/bundled/media-buy/sync-catalogs-response.json @@ -1089,7 +1089,7 @@ ], "properties": {}, "_bundled": { - "generatedAt": "2026-07-28T13:04:07.292Z", + "generatedAt": "2026-08-04T05:39:58.502Z", "note": "This is a bundled schema with all $ref resolved inline. For the modular version with references, use the parent directory." } } \ No newline at end of file diff --git a/schemas/cache/3.1/bundled/media-buy/sync-event-sources-request.json b/schemas/cache/3.1/bundled/media-buy/sync-event-sources-request.json index 8c5bd6786..c9778b276 100644 --- a/schemas/cache/3.1/bundled/media-buy/sync-event-sources-request.json +++ b/schemas/cache/3.1/bundled/media-buy/sync-event-sources-request.json @@ -905,7 +905,7 @@ ], "additionalProperties": true, "_bundled": { - "generatedAt": "2026-07-28T13:04:07.294Z", + "generatedAt": "2026-08-04T05:39:58.503Z", "note": "This is a bundled schema with all $ref resolved inline. For the modular version with references, use the parent directory." } } \ No newline at end of file diff --git a/schemas/cache/3.1/bundled/media-buy/sync-event-sources-response.json b/schemas/cache/3.1/bundled/media-buy/sync-event-sources-response.json index 800c0f154..6118983f2 100644 --- a/schemas/cache/3.1/bundled/media-buy/sync-event-sources-response.json +++ b/schemas/cache/3.1/bundled/media-buy/sync-event-sources-response.json @@ -1098,7 +1098,7 @@ ], "properties": {}, "_bundled": { - "generatedAt": "2026-07-28T13:04:07.295Z", + "generatedAt": "2026-08-04T05:39:58.504Z", "note": "This is a bundled schema with all $ref resolved inline. For the modular version with references, use the parent directory." } } \ No newline at end of file diff --git a/schemas/cache/3.1/bundled/media-buy/update-media-buy-request.json b/schemas/cache/3.1/bundled/media-buy/update-media-buy-request.json index cb05b3944..62bcb1442 100644 --- a/schemas/cache/3.1/bundled/media-buy/update-media-buy-request.json +++ b/schemas/cache/3.1/bundled/media-buy/update-media-buy-request.json @@ -48818,7 +48818,7 @@ } }, "_bundled": { - "generatedAt": "2026-07-28T13:04:07.343Z", + "generatedAt": "2026-08-04T05:39:58.554Z", "note": "This is a bundled schema with all $ref resolved inline. For the modular version with references, use the parent directory." } } \ No newline at end of file diff --git a/schemas/cache/3.1/bundled/media-buy/update-media-buy-response.json b/schemas/cache/3.1/bundled/media-buy/update-media-buy-response.json index 6253f683b..d68a7577d 100644 --- a/schemas/cache/3.1/bundled/media-buy/update-media-buy-response.json +++ b/schemas/cache/3.1/bundled/media-buy/update-media-buy-response.json @@ -8068,7 +8068,7 @@ } }, "_bundled": { - "generatedAt": "2026-07-28T13:04:07.365Z", + "generatedAt": "2026-08-04T05:39:58.577Z", "note": "This is a bundled schema with all $ref resolved inline. For the modular version with references, use the parent directory." } } \ No newline at end of file diff --git a/schemas/cache/3.1/bundled/property/create-property-list-request.json b/schemas/cache/3.1/bundled/property/create-property-list-request.json index e9224b997..f9917d5b5 100644 --- a/schemas/cache/3.1/bundled/property/create-property-list-request.json +++ b/schemas/cache/3.1/bundled/property/create-property-list-request.json @@ -1602,7 +1602,7 @@ } }, "_bundled": { - "generatedAt": "2026-07-28T13:04:07.370Z", + "generatedAt": "2026-08-04T05:39:58.582Z", "note": "This is a bundled schema with all $ref resolved inline. For the modular version with references, use the parent directory." } } \ No newline at end of file diff --git a/schemas/cache/3.1/bundled/property/create-property-list-response.json b/schemas/cache/3.1/bundled/property/create-property-list-response.json index 80d1e5438..eb39f21ba 100644 --- a/schemas/cache/3.1/bundled/property/create-property-list-response.json +++ b/schemas/cache/3.1/bundled/property/create-property-list-response.json @@ -2322,7 +2322,7 @@ } }, "_bundled": { - "generatedAt": "2026-07-28T13:04:07.373Z", + "generatedAt": "2026-08-04T05:39:58.585Z", "note": "This is a bundled schema with all $ref resolved inline. For the modular version with references, use the parent directory." } } \ No newline at end of file diff --git a/schemas/cache/3.1/bundled/property/delete-property-list-request.json b/schemas/cache/3.1/bundled/property/delete-property-list-request.json index c592b11cb..5930a20c4 100644 --- a/schemas/cache/3.1/bundled/property/delete-property-list-request.json +++ b/schemas/cache/3.1/bundled/property/delete-property-list-request.json @@ -707,7 +707,7 @@ ], "additionalProperties": true, "_bundled": { - "generatedAt": "2026-07-28T13:04:07.374Z", + "generatedAt": "2026-08-04T05:39:58.586Z", "note": "This is a bundled schema with all $ref resolved inline. For the modular version with references, use the parent directory." } } \ No newline at end of file diff --git a/schemas/cache/3.1/bundled/property/delete-property-list-response.json b/schemas/cache/3.1/bundled/property/delete-property-list-response.json index 3a3c7c53e..048aef3cf 100644 --- a/schemas/cache/3.1/bundled/property/delete-property-list-response.json +++ b/schemas/cache/3.1/bundled/property/delete-property-list-response.json @@ -456,7 +456,7 @@ ], "additionalProperties": true, "_bundled": { - "generatedAt": "2026-07-28T13:04:07.375Z", + "generatedAt": "2026-08-04T05:39:58.587Z", "note": "This is a bundled schema with all $ref resolved inline. For the modular version with references, use the parent directory." } } \ No newline at end of file diff --git a/schemas/cache/3.1/bundled/property/get-property-list-request.json b/schemas/cache/3.1/bundled/property/get-property-list-request.json index 94ac79af3..4fec9bf0d 100644 --- a/schemas/cache/3.1/bundled/property/get-property-list-request.json +++ b/schemas/cache/3.1/bundled/property/get-property-list-request.json @@ -721,7 +721,7 @@ ], "additionalProperties": true, "_bundled": { - "generatedAt": "2026-07-28T13:04:07.376Z", + "generatedAt": "2026-08-04T05:39:58.589Z", "note": "This is a bundled schema with all $ref resolved inline. For the modular version with references, use the parent directory." } } \ No newline at end of file diff --git a/schemas/cache/3.1/bundled/property/get-property-list-response.json b/schemas/cache/3.1/bundled/property/get-property-list-response.json index 20df32b0d..a7ce9d3f1 100644 --- a/schemas/cache/3.1/bundled/property/get-property-list-response.json +++ b/schemas/cache/3.1/bundled/property/get-property-list-response.json @@ -2395,7 +2395,7 @@ } }, "_bundled": { - "generatedAt": "2026-07-28T13:04:07.379Z", + "generatedAt": "2026-08-04T05:39:58.591Z", "note": "This is a bundled schema with all $ref resolved inline. For the modular version with references, use the parent directory." } } \ No newline at end of file diff --git a/schemas/cache/3.1/bundled/property/list-property-lists-request.json b/schemas/cache/3.1/bundled/property/list-property-lists-request.json index 129563928..dc078cb04 100644 --- a/schemas/cache/3.1/bundled/property/list-property-lists-request.json +++ b/schemas/cache/3.1/bundled/property/list-property-lists-request.json @@ -713,7 +713,7 @@ }, "additionalProperties": true, "_bundled": { - "generatedAt": "2026-07-28T13:04:07.380Z", + "generatedAt": "2026-08-04T05:39:58.593Z", "note": "This is a bundled schema with all $ref resolved inline. For the modular version with references, use the parent directory." } } \ No newline at end of file diff --git a/schemas/cache/3.1/bundled/property/list-property-lists-response.json b/schemas/cache/3.1/bundled/property/list-property-lists-response.json index a8595d45f..eee775c4f 100644 --- a/schemas/cache/3.1/bundled/property/list-property-lists-response.json +++ b/schemas/cache/3.1/bundled/property/list-property-lists-response.json @@ -2340,7 +2340,7 @@ } }, "_bundled": { - "generatedAt": "2026-07-28T13:04:07.382Z", + "generatedAt": "2026-08-04T05:39:58.595Z", "note": "This is a bundled schema with all $ref resolved inline. For the modular version with references, use the parent directory." } } \ No newline at end of file diff --git a/schemas/cache/3.1/bundled/property/update-property-list-request.json b/schemas/cache/3.1/bundled/property/update-property-list-request.json index 8e9e3c06a..f624a0cbe 100644 --- a/schemas/cache/3.1/bundled/property/update-property-list-request.json +++ b/schemas/cache/3.1/bundled/property/update-property-list-request.json @@ -1611,7 +1611,7 @@ } }, "_bundled": { - "generatedAt": "2026-07-28T13:04:07.385Z", + "generatedAt": "2026-08-04T05:39:58.598Z", "note": "This is a bundled schema with all $ref resolved inline. For the modular version with references, use the parent directory." } } \ No newline at end of file diff --git a/schemas/cache/3.1/bundled/property/update-property-list-response.json b/schemas/cache/3.1/bundled/property/update-property-list-response.json index cb5d9aa3b..429b5e1f5 100644 --- a/schemas/cache/3.1/bundled/property/update-property-list-response.json +++ b/schemas/cache/3.1/bundled/property/update-property-list-response.json @@ -2317,7 +2317,7 @@ } }, "_bundled": { - "generatedAt": "2026-07-28T13:04:07.388Z", + "generatedAt": "2026-08-04T05:39:58.600Z", "note": "This is a bundled schema with all $ref resolved inline. For the modular version with references, use the parent directory." } } \ No newline at end of file diff --git a/schemas/cache/3.1/bundled/property/validate-property-delivery-request.json b/schemas/cache/3.1/bundled/property/validate-property-delivery-request.json index 5475326b1..26a130197 100644 --- a/schemas/cache/3.1/bundled/property/validate-property-delivery-request.json +++ b/schemas/cache/3.1/bundled/property/validate-property-delivery-request.json @@ -817,7 +817,7 @@ ], "additionalProperties": true, "_bundled": { - "generatedAt": "2026-07-28T13:04:07.389Z", + "generatedAt": "2026-08-04T05:39:58.602Z", "note": "This is a bundled schema with all $ref resolved inline. For the modular version with references, use the parent directory." } } \ No newline at end of file diff --git a/schemas/cache/3.1/bundled/property/validate-property-delivery-response.json b/schemas/cache/3.1/bundled/property/validate-property-delivery-response.json index 0f5ee61a6..34731f8c7 100644 --- a/schemas/cache/3.1/bundled/property/validate-property-delivery-response.json +++ b/schemas/cache/3.1/bundled/property/validate-property-delivery-response.json @@ -830,7 +830,7 @@ ], "additionalProperties": true, "_bundled": { - "generatedAt": "2026-07-28T13:04:07.390Z", + "generatedAt": "2026-08-04T05:39:58.603Z", "note": "This is a bundled schema with all $ref resolved inline. For the modular version with references, use the parent directory." } } \ No newline at end of file diff --git a/schemas/cache/3.1/bundled/protocol/get-adcp-capabilities-request.json b/schemas/cache/3.1/bundled/protocol/get-adcp-capabilities-request.json index b6dce1f9f..f36329241 100644 --- a/schemas/cache/3.1/bundled/protocol/get-adcp-capabilities-request.json +++ b/schemas/cache/3.1/bundled/protocol/get-adcp-capabilities-request.json @@ -60,7 +60,7 @@ }, "additionalProperties": true, "_bundled": { - "generatedAt": "2026-07-28T13:04:07.391Z", + "generatedAt": "2026-08-04T05:39:58.604Z", "note": "This is a bundled schema with all $ref resolved inline. For the modular version with references, use the parent directory." } } \ No newline at end of file diff --git a/schemas/cache/3.1/bundled/protocol/get-adcp-capabilities-response.json b/schemas/cache/3.1/bundled/protocol/get-adcp-capabilities-response.json index 9c156933e..475134960 100644 --- a/schemas/cache/3.1/bundled/protocol/get-adcp-capabilities-response.json +++ b/schemas/cache/3.1/bundled/protocol/get-adcp-capabilities-response.json @@ -11750,7 +11750,7 @@ } }, "_bundled": { - "generatedAt": "2026-07-28T13:04:07.401Z", + "generatedAt": "2026-08-04T05:39:58.614Z", "note": "This is a bundled schema with all $ref resolved inline. For the modular version with references, use the parent directory." } } \ No newline at end of file diff --git a/schemas/cache/3.1/bundled/protocol/get-task-status-request.json b/schemas/cache/3.1/bundled/protocol/get-task-status-request.json index 54f643dfd..ba2fdcb7f 100644 --- a/schemas/cache/3.1/bundled/protocol/get-task-status-request.json +++ b/schemas/cache/3.1/bundled/protocol/get-task-status-request.json @@ -737,7 +737,7 @@ } ], "_bundled": { - "generatedAt": "2026-07-28T13:04:07.406Z", + "generatedAt": "2026-08-04T05:39:58.619Z", "note": "This is a bundled schema with all $ref resolved inline. For the modular version with references, use the parent directory." } } \ No newline at end of file diff --git a/schemas/cache/3.1/bundled/protocol/get-task-status-response.json b/schemas/cache/3.1/bundled/protocol/get-task-status-response.json index 1705ec67f..0595f4365 100644 --- a/schemas/cache/3.1/bundled/protocol/get-task-status-response.json +++ b/schemas/cache/3.1/bundled/protocol/get-task-status-response.json @@ -158095,7 +158095,7 @@ } }, "_bundled": { - "generatedAt": "2026-07-28T13:04:07.565Z", + "generatedAt": "2026-08-04T05:39:58.790Z", "note": "This is a bundled schema with all $ref resolved inline. For the modular version with references, use the parent directory." } } \ No newline at end of file diff --git a/schemas/cache/3.1/bundled/protocol/list-tasks-request.json b/schemas/cache/3.1/bundled/protocol/list-tasks-request.json index 01acc4357..50b2251a3 100644 --- a/schemas/cache/3.1/bundled/protocol/list-tasks-request.json +++ b/schemas/cache/3.1/bundled/protocol/list-tasks-request.json @@ -993,7 +993,7 @@ } }, "_bundled": { - "generatedAt": "2026-07-28T13:04:07.632Z", + "generatedAt": "2026-08-04T05:39:58.859Z", "note": "This is a bundled schema with all $ref resolved inline. For the modular version with references, use the parent directory." } } \ No newline at end of file diff --git a/schemas/cache/3.1/bundled/protocol/list-tasks-response.json b/schemas/cache/3.1/bundled/protocol/list-tasks-response.json index 772ce0488..9b0e2a3d2 100644 --- a/schemas/cache/3.1/bundled/protocol/list-tasks-response.json +++ b/schemas/cache/3.1/bundled/protocol/list-tasks-response.json @@ -665,7 +665,7 @@ } }, "_bundled": { - "generatedAt": "2026-07-28T13:04:07.633Z", + "generatedAt": "2026-08-04T05:39:58.860Z", "note": "This is a bundled schema with all $ref resolved inline. For the modular version with references, use the parent directory." } } \ No newline at end of file diff --git a/schemas/cache/3.1/bundled/signals/activate-signal-request.json b/schemas/cache/3.1/bundled/signals/activate-signal-request.json index 9d8eec78f..a37b9cb45 100644 --- a/schemas/cache/3.1/bundled/signals/activate-signal-request.json +++ b/schemas/cache/3.1/bundled/signals/activate-signal-request.json @@ -788,7 +788,7 @@ ], "additionalProperties": true, "_bundled": { - "generatedAt": "2026-07-28T13:04:07.634Z", + "generatedAt": "2026-08-04T05:39:58.862Z", "note": "This is a bundled schema with all $ref resolved inline. For the modular version with references, use the parent directory." } } \ No newline at end of file diff --git a/schemas/cache/3.1/bundled/signals/activate-signal-response.json b/schemas/cache/3.1/bundled/signals/activate-signal-response.json index 7842b5fcc..515071bb4 100644 --- a/schemas/cache/3.1/bundled/signals/activate-signal-response.json +++ b/schemas/cache/3.1/bundled/signals/activate-signal-response.json @@ -816,7 +816,7 @@ ], "properties": {}, "_bundled": { - "generatedAt": "2026-07-28T13:04:07.636Z", + "generatedAt": "2026-08-04T05:39:58.863Z", "note": "This is a bundled schema with all $ref resolved inline. For the modular version with references, use the parent directory." } } \ No newline at end of file diff --git a/schemas/cache/3.1/bundled/signals/get-signals-request.json b/schemas/cache/3.1/bundled/signals/get-signals-request.json index 354e2ef38..7968b9788 100644 --- a/schemas/cache/3.1/bundled/signals/get-signals-request.json +++ b/schemas/cache/3.1/bundled/signals/get-signals-request.json @@ -1286,7 +1286,7 @@ }, "additionalProperties": true, "_bundled": { - "generatedAt": "2026-07-28T13:04:07.637Z", + "generatedAt": "2026-08-04T05:39:58.864Z", "note": "This is a bundled schema with all $ref resolved inline. For the modular version with references, use the parent directory." } } \ No newline at end of file diff --git a/schemas/cache/3.1/bundled/signals/get-signals-response.json b/schemas/cache/3.1/bundled/signals/get-signals-response.json index 5ae76f079..1e2b66a44 100644 --- a/schemas/cache/3.1/bundled/signals/get-signals-response.json +++ b/schemas/cache/3.1/bundled/signals/get-signals-response.json @@ -5608,7 +5608,7 @@ } }, "_bundled": { - "generatedAt": "2026-07-28T13:04:07.643Z", + "generatedAt": "2026-08-04T05:39:58.871Z", "note": "This is a bundled schema with all $ref resolved inline. For the modular version with references, use the parent directory." } } \ No newline at end of file diff --git a/schemas/cache/3.1/bundled/sponsored-intelligence/si-get-offering-request.json b/schemas/cache/3.1/bundled/sponsored-intelligence/si-get-offering-request.json index 051e20ce7..9f7f93f06 100644 --- a/schemas/cache/3.1/bundled/sponsored-intelligence/si-get-offering-request.json +++ b/schemas/cache/3.1/bundled/sponsored-intelligence/si-get-offering-request.json @@ -70,7 +70,7 @@ ], "additionalProperties": true, "_bundled": { - "generatedAt": "2026-07-28T13:04:07.645Z", + "generatedAt": "2026-08-04T05:39:58.873Z", "note": "This is a bundled schema with all $ref resolved inline. For the modular version with references, use the parent directory." } } \ No newline at end of file diff --git a/schemas/cache/3.1/bundled/sponsored-intelligence/si-get-offering-response.json b/schemas/cache/3.1/bundled/sponsored-intelligence/si-get-offering-response.json index 97bed8865..5670c20a1 100644 --- a/schemas/cache/3.1/bundled/sponsored-intelligence/si-get-offering-response.json +++ b/schemas/cache/3.1/bundled/sponsored-intelligence/si-get-offering-response.json @@ -1477,7 +1477,7 @@ } }, "_bundled": { - "generatedAt": "2026-07-28T13:04:07.647Z", + "generatedAt": "2026-08-04T05:39:58.875Z", "note": "This is a bundled schema with all $ref resolved inline. For the modular version with references, use the parent directory." } } \ No newline at end of file diff --git a/schemas/cache/3.1/bundled/sponsored-intelligence/si-initiate-session-request.json b/schemas/cache/3.1/bundled/sponsored-intelligence/si-initiate-session-request.json index 79862987f..0d13a8904 100644 --- a/schemas/cache/3.1/bundled/sponsored-intelligence/si-initiate-session-request.json +++ b/schemas/cache/3.1/bundled/sponsored-intelligence/si-initiate-session-request.json @@ -1400,7 +1400,7 @@ } }, "_bundled": { - "generatedAt": "2026-07-28T13:04:07.649Z", + "generatedAt": "2026-08-04T05:39:58.877Z", "note": "This is a bundled schema with all $ref resolved inline. For the modular version with references, use the parent directory." } } \ No newline at end of file diff --git a/schemas/cache/3.1/bundled/sponsored-intelligence/si-initiate-session-response.json b/schemas/cache/3.1/bundled/sponsored-intelligence/si-initiate-session-response.json index 1729ff967..1142ee5f9 100644 --- a/schemas/cache/3.1/bundled/sponsored-intelligence/si-initiate-session-response.json +++ b/schemas/cache/3.1/bundled/sponsored-intelligence/si-initiate-session-response.json @@ -1859,7 +1859,7 @@ ], "additionalProperties": true, "_bundled": { - "generatedAt": "2026-07-28T13:04:07.651Z", + "generatedAt": "2026-08-04T05:39:58.879Z", "note": "This is a bundled schema with all $ref resolved inline. For the modular version with references, use the parent directory." } } \ No newline at end of file diff --git a/schemas/cache/3.1/bundled/sponsored-intelligence/si-send-message-request.json b/schemas/cache/3.1/bundled/sponsored-intelligence/si-send-message-request.json index 06a5d17fd..5111a1060 100644 --- a/schemas/cache/3.1/bundled/sponsored-intelligence/si-send-message-request.json +++ b/schemas/cache/3.1/bundled/sponsored-intelligence/si-send-message-request.json @@ -1159,7 +1159,7 @@ } }, "_bundled": { - "generatedAt": "2026-07-28T13:04:07.653Z", + "generatedAt": "2026-08-04T05:39:58.881Z", "note": "This is a bundled schema with all $ref resolved inline. For the modular version with references, use the parent directory." } } \ No newline at end of file diff --git a/schemas/cache/3.1/bundled/sponsored-intelligence/si-send-message-response.json b/schemas/cache/3.1/bundled/sponsored-intelligence/si-send-message-response.json index 7923c6a27..3854880f2 100644 --- a/schemas/cache/3.1/bundled/sponsored-intelligence/si-send-message-response.json +++ b/schemas/cache/3.1/bundled/sponsored-intelligence/si-send-message-response.json @@ -1830,7 +1830,7 @@ ], "additionalProperties": true, "_bundled": { - "generatedAt": "2026-07-28T13:04:07.655Z", + "generatedAt": "2026-08-04T05:39:58.883Z", "note": "This is a bundled schema with all $ref resolved inline. For the modular version with references, use the parent directory." } } \ No newline at end of file diff --git a/schemas/cache/3.1/bundled/sponsored-intelligence/si-terminate-session-request.json b/schemas/cache/3.1/bundled/sponsored-intelligence/si-terminate-session-request.json index 33fedd0d3..c097ba57b 100644 --- a/schemas/cache/3.1/bundled/sponsored-intelligence/si-terminate-session-request.json +++ b/schemas/cache/3.1/bundled/sponsored-intelligence/si-terminate-session-request.json @@ -100,7 +100,7 @@ ], "additionalProperties": true, "_bundled": { - "generatedAt": "2026-07-28T13:04:07.656Z", + "generatedAt": "2026-08-04T05:39:58.883Z", "note": "This is a bundled schema with all $ref resolved inline. For the modular version with references, use the parent directory." } } \ No newline at end of file diff --git a/schemas/cache/3.1/bundled/sponsored-intelligence/si-terminate-session-response.json b/schemas/cache/3.1/bundled/sponsored-intelligence/si-terminate-session-response.json index 31a77b23d..ecfc66f72 100644 --- a/schemas/cache/3.1/bundled/sponsored-intelligence/si-terminate-session-response.json +++ b/schemas/cache/3.1/bundled/sponsored-intelligence/si-terminate-session-response.json @@ -642,7 +642,7 @@ ], "additionalProperties": true, "_bundled": { - "generatedAt": "2026-07-28T13:04:07.656Z", + "generatedAt": "2026-08-04T05:39:58.884Z", "note": "This is a bundled schema with all $ref resolved inline. For the modular version with references, use the parent directory." } } \ No newline at end of file diff --git a/schemas/cache/3.1/creative/asset-types/index.json b/schemas/cache/3.1/creative/asset-types/index.json index cea47ac8d..a576d0db3 100644 --- a/schemas/cache/3.1/creative/asset-types/index.json +++ b/schemas/cache/3.1/creative/asset-types/index.json @@ -3,7 +3,7 @@ "title": "AdCP Asset Type Registry", "description": "Registry of asset types used in AdCP creative manifests. Each asset type defines the structure of actual content payloads (what you send), not requirements or constraints (which belong in format specifications).", "version": "1.0.0", - "lastUpdated": "2026-07-28", + "lastUpdated": "2026-08-04", "asset_types": { "image": { "description": "Static image asset (JPG, PNG, GIF, WebP, SVG)", @@ -139,9 +139,9 @@ "creative_manifests": "Creative manifests provide actual asset content, keyed by asset_id from the format. Each asset value carries an `asset_type` discriminator (one of the registry keys) so validators can select the matching asset schema and report errors against only that branch. The format specification also defines what asset_type each asset_id should have \u2014 payload and format should agree.", "example_flow": "Format says 'hero_image' must be type 'image' with width 1200, height 627. Manifest provides hero_image: {url: '...', width: 1200, height: 627}. The format spec tells us it's an image type." }, - "published_version": "3.1.8", - "adcp_version": "3.1.8", - "baseUrl": "/schemas/3.1.8", + "published_version": "3.1.10", + "adcp_version": "3.1.10", + "baseUrl": "/schemas/3.1.10", "protocol_layers": [ { "id": "negotiation", @@ -170,6 +170,6 @@ "prerelease": false, "deprecated": false, "versioning": { - "note": "AdCP uses build-time versioning. This directory contains schemas for AdCP 3.1.8. Full semantic versions are available at /schemas/{version}/ (e.g., /schemas/2.5.0/). Major version aliases point to the latest stable release in that major line; use /schemas/index.json or /schemas/latest.json for the canonical file-based pointer." + "note": "AdCP uses build-time versioning. This directory contains schemas for AdCP 3.1.10. Full semantic versions are available at /schemas/{version}/ (e.g., /schemas/2.5.0/). Major version aliases point to the latest stable release in that major line; use /schemas/index.json or /schemas/latest.json for the canonical file-based pointer." } } \ No newline at end of file diff --git a/schemas/cache/3.1/extensions/index.json b/schemas/cache/3.1/extensions/index.json index 30f5535b8..dc6dba666 100644 --- a/schemas/cache/3.1/extensions/index.json +++ b/schemas/cache/3.1/extensions/index.json @@ -3,6 +3,6 @@ "title": "AdCP Extension Registry", "description": "Auto-generated registry of formal AdCP extensions. Extensions provide typed schemas for vendor-specific or domain-specific data within the ext field. Agents declare which extensions they support in their agent card.", "_generated": true, - "_generatedAt": "2026-07-28T13:04:06.049Z", + "_generatedAt": "2026-08-04T05:39:57.231Z", "extensions": {} } \ No newline at end of file diff --git a/schemas/cache/3.1/index.json b/schemas/cache/3.1/index.json index 98e21b0d8..ec44c37c5 100644 --- a/schemas/cache/3.1/index.json +++ b/schemas/cache/3.1/index.json @@ -3,12 +3,12 @@ "title": "AdCP Schema Registry", "version": "1.0.0", "description": "Registry of all AdCP JSON schemas for validation and discovery", - "adcp_version": "3.1.8", + "adcp_version": "3.1.10", "versioning": { - "note": "AdCP uses build-time versioning. This directory contains schemas for AdCP 3.1.8. Full semantic versions are available at /schemas/{version}/ (e.g., /schemas/2.5.0/). Major version aliases point to the latest stable release in that major line; use /schemas/index.json or /schemas/latest.json for the canonical file-based pointer." + "note": "AdCP uses build-time versioning. This directory contains schemas for AdCP 3.1.10. Full semantic versions are available at /schemas/{version}/ (e.g., /schemas/2.5.0/). Major version aliases point to the latest stable release in that major line; use /schemas/index.json or /schemas/latest.json for the canonical file-based pointer." }, - "lastUpdated": "2026-07-28", - "baseUrl": "/schemas/3.1.8", + "lastUpdated": "2026-08-04", + "baseUrl": "/schemas/3.1.10", "stability": "stable", "prerelease": false, "deprecated": false, @@ -1848,6 +1848,18 @@ "provider-registration": { "$ref": "trusted-match/provider-registration.json", "description": "TMP provider registration \u2014 endpoint, capabilities, and operational parameters for router configuration" + }, + "provider-identity-match-response": { + "$ref": "trusted-match/provider-identity-match-response.json", + "description": "Provider-to-router Identity Match response shape \u2014 carries ordered TMPX `{slot_id, value}` chunks with no publisher-local names" + }, + "publisher-tmpx-config": { + "$ref": "trusted-match/publisher-tmpx-config.json", + "description": "Publisher-owned deployment configuration that maps (provider_id, slot_id) to the ad-server macro name, GAM key-value, VAST substitution, or play-log field for that surface" + }, + "tmpx-chunk": { + "$ref": "trusted-match/tmpx-chunk.json", + "description": "A single TMPX chunk \u2014 provider-local slot_id and opaque URL-safe value; shared between provider\u2192router and router\u2192publisher hops" } }, "operations": { @@ -2015,5 +2027,5 @@ "code": "// Use everit-org/json-schema or similar library" } ], - "published_version": "3.1.8" + "published_version": "3.1.10" } \ No newline at end of file diff --git a/schemas/cache/3.1/manifest.json b/schemas/cache/3.1/manifest.json index c1e4b2e84..71b52a36e 100644 --- a/schemas/cache/3.1/manifest.json +++ b/schemas/cache/3.1/manifest.json @@ -1,7 +1,7 @@ { - "$schema": "/schemas/3.1.8/manifest.schema.json", - "adcp_version": "3.1.8", - "generated_at": "2026-07-28T13:04:06.237Z", + "$schema": "/schemas/3.1.10/manifest.schema.json", + "adcp_version": "3.1.10", + "generated_at": "2026-08-04T05:39:57.409Z", "tools": { "acquire_rights": { "protocol": "brand", diff --git a/schemas/cache/3.1/registries/v1-canonical-mapping.json b/schemas/cache/3.1/registries/v1-canonical-mapping.json index 10b06e2e4..6c46dcdbe 100644 --- a/schemas/cache/3.1/registries/v1-canonical-mapping.json +++ b/schemas/cache/3.1/registries/v1-canonical-mapping.json @@ -1,9 +1,9 @@ { "$schema": "http://json-schema.org/draft-07/schema#", "title": "v1 \u2192 v2 Canonical Format Mapping Registry", - "description": "Authoritative AAO-published mapping from v1 named formats to v2 canonical declarations. Used by SDKs to project the v1 wire shape into v2 canonical declarations during the migration window.\n\n**Direction of truth (normative).** This registry is authoritative for **v1 \u2192 v2 projection only**. v2 \u2192 v1 projection MUST rely on `v1_format_ref` on the v2 `ProductFormatDeclaration` \u2014 sellers assert the v1 pairing explicitly. SDKs MUST NOT synthesize a v1 `format_id` from the registry by inverting structural matches: the registry's `id` slugs lack the `agent_url` half of a `FormatId`, and registry entries with `format_id_glob: '*'` or pure-structural matches have no single literal to invert to. SDKs that synthesize unilaterally produce inter-SDK divergence on structurally-equal values (different SDKs pick different `agent_url` and `id` patterns for the same v2 declaration). When a v2 declaration carries no `v1_format_ref` and a v1-only buyer queries the product, the SDK reports the canonical as v1-unreachable via `FORMAT_DECLARATION_V1_AMBIGUOUS` and lets the buyer surface it to the seller; the seller's path is to add `v1_format_ref` to disambiguate.\n\nBest-effort inversion is available only from this registry's non-wildcarded literal format_id_glob entries. Structural matches remain family-level and are not invertible to a specific v1 format_id. SDKs MAY do best-effort inversion for non-wildcarded literals only, AND only when the seller hasn't authored a contradicting `v1_format_ref` \u2014 even then, the projection is non-normative and downstream consumers MUST NOT depend on it.\n\n**Resolution order** (per RFC #3305 amendment #3767, normative):\n1. **Authoritative v2\u2192v1 link**: if any v2 `ProductFormatDeclaration` on the same product carries `v1_format_ref` pointing at this v1 format_id, use that v2 declaration. Highest priority \u2014 seller asserts the link directly. SDKs SHOULD run the *narrows* check (canonical-formats.mdx 'Narrows \u2014 formal definition') between the v2 declaration's `params` and the referenced v1 format's `requirements`; on conflict, surface `FORMAT_DECLARATION_DIVERGENT` on the `get_products` response `errors[]`. Without the narrowing check, `v1_format_ref` is a hint rather than a contract.\n2. **Seller-asserted on the v1 file**: if the v1 format declaration carries an explicit `canonical` field, use it. (Note: `canonical_parameters` on the v1 file is deprecated for 3.1; SDKs reading 3.1 catalogs MUST still honor it when present, but `v1_format_ref` is the path forward.)\n3. **Registry glob**: look up `format_id` in this registry's `format_id_glob` entries.\n4. **Structural match**: attempt structural match against this registry's `structural` entries. A successful structural match yields a *family-level* identification only (e.g., 'this is a `video_vast`') \u2014 it does NOT yield a specific v1 `format_id`. SDKs use structural match for v1 \u2192 v2 projection (the inbound direction) but MUST NOT invert it to a v1 `format_id` on the outbound path.\n5. **Ambiguous family**: if step 4 succeeded but the matched entries are family-only (pure structural, no invertible literal), the canonical is **v1-unreachable for THIS specific product** unless the seller authors `v1_format_ref`. SDKs MUST surface `FORMAT_DECLARATION_V1_AMBIGUOUS` via `errors[]` augmentation rather than synthesize a plausible-but-arbitrary v1 `format_id`. Distinct from canonical-level v1-unreachability (a canonical with `v1_translatable: false` \u2014 `agent_placement`, `sponsored_placement`, `responsive_creative`, `image_carousel` \u2014 never has any v1 form regardless of registry coverage).\n6. **Fail closed**: SDK MUST NOT emit `format_options` for products carrying this format. SDKs MUST augment the response's `errors[]` array with an entry carrying `source: \"sdk\"`, `sdk_id: \"@\"`, `code: \"FORMAT_PROJECTION_FAILED\"`, `field: \"products[N].format_ids[K]\"`, and `error.details: { format_id, product_id, resolution_failure: \"no_explicit_canonical\" | \"no_registry_match\" | \"no_structural_match\" }`. Single mandated surface (`errors[]` augmentation) \u2014 lint-output channels are NOT acceptable; the multi-hop agent network needs warnings to propagate across SDK boundaries via the wire response. Logger-only warnings die in DEBUG. The advisory is non-fatal: the response stays 200/success, the product is still valid on the v1 path, only the v2 `format_options` projection is absent. Consumer-side counterpart to the producer SHOULD (sellers should add a v2 declaration with `v1_format_ref`, an explicit `canonical` field, or file a registry PR).\n\n**Match modes:**\n- `format_id_glob` \u2014 exact / glob match against the v1 `format_id.id`. Published non-wildcarded literals cover independently observed legacy conventions whose names carry semantic narrowing (duration, dimensions, or VAST delivery) that slot shape alone cannot recover. Each literal mapping preserves those constraints in canonical parameters; AAO-catalog-published formats with explicit canonical annotations still project via resolution-order step 2. Glob syntax: `*` matches any segment.\n- `structural` \u2014 match against the format's slot shape, asset types, and version constraints. The PRIMARY fallback for v1 wire traffic \u2014 catches custom v1 formats (a publisher's `acme_homepage_300x250` is structurally an IAB MREC) without enumerating every possible v1 name. v1 sellers in the wild naming things their own way are handled here, not by literal globs.\n\n**Alias collision precedence (normative).** When a v1 format's `assets[i]` carries multiple `asset_group_id` aliases that resolve to the same canonical asset_group (e.g., two slots both aliasing to `landing_page_url`), the SDK MUST resolve deterministically: the v1 format's `assets[*]` array order is authoritative \u2014 the first slot in declaration order wins, subsequent collisions are dropped from the projected v2 manifest and surfaced via `FORMAT_PROJECTION_FAILED` with `error.details: { collision_kind: \"asset_group_id_alias\", asset_group_id, winning_slot_id, dropped_slot_ids }`. SDKs MUST NOT silently pick one and discard the other without surfacing \u2014 silent picking creates inter-SDK divergence. Producers SHOULD avoid the collision by deduplicating aliased slots or using distinct `asset_group_id` values when both slots are semantically meaningful.\n\n**Governance**: same vocabulary-governance rules as `asset-group-vocabulary.json` and `format-shape-vocabulary.json` \u2014 additions land via PR with rationale + \u22651 reference adopter; AAO maintainer review; versioned + content-digested. Entries are additive; once published they are not removed (they may be marked `deprecated: true` if superseded).\n\n**Scope**: 7 structural fallback entries cover VAST 4.x / legacy VAST, DAAST 1.x, HTML5 zip bundles, hosted video, hosted audio, and url-shaped display tags. Literal entries cover independently observed legacy duration-, dimension-, and VAST-token naming conventions. Durationless placement ids video_pre_roll and video_mid_roll are deliberately omitted: projecting either to video_hosted without duration_ms_exact would resolve to an untraffickable format and defer failure until ad-server line-item creation. Failing closed during discovery is safer. Platform-specific formats (Meta Reels, TikTok Spark Ads, etc.) project via structural fallback or via the platform's own adagents.json `formats[]` block (#4620). The full v1-format audit dataset (~76% of formats from the 12-platform / 86-format audit in #3305) seeds the long-term roadmap and informs future literal-entry decisions.\n\nDigest the file content (sha256) when emitting in capabilities responses or referencing from SDK output. Buyers cache by `version` + `digest`.", - "version": "1.2.0", - "last_updated": "2026-07-28", + "description": "Authoritative AAO-published mapping from v1 named formats to v2 canonical declarations. Used by SDKs to project the v1 wire shape into v2 canonical declarations during the migration window.\n\n**Direction of truth (normative).** This registry is authoritative for **v1 \u2192 v2 projection only**. v2 \u2192 v1 projection MUST rely on `v1_format_ref` on the v2 `ProductFormatDeclaration` \u2014 sellers assert the v1 pairing explicitly. SDKs MUST NOT synthesize a v1 `format_id` from the registry by inverting structural matches: the registry's `id` slugs lack the `agent_url` half of a `FormatId`, and registry entries with `format_id_glob: '*'` or pure-structural matches have no single literal to invert to. SDKs that synthesize unilaterally produce inter-SDK divergence on structurally-equal values (different SDKs pick different `agent_url` and `id` patterns for the same v2 declaration). When a v2 declaration carries no `v1_format_ref` and a v1-only buyer queries the product, the SDK reports the canonical as v1-unreachable via `FORMAT_DECLARATION_V1_AMBIGUOUS` and lets the buyer surface it to the seller; the seller's path is to add `v1_format_ref` to disambiguate.\n\nBest-effort inversion is available only from this registry's non-wildcarded literal format_id_glob entries. Structural matches remain family-level and are not invertible to a specific v1 format_id. SDKs MAY do best-effort inversion for non-wildcarded literals only, AND only when the seller hasn't authored a contradicting `v1_format_ref` \u2014 even then, the projection is non-normative and downstream consumers MUST NOT depend on it.\n\n**Resolution order** (per RFC #3305 amendment #3767, normative):\n1. **Authoritative v2\u2192v1 link**: if any v2 `ProductFormatDeclaration` on the same product carries `v1_format_ref` pointing at this v1 format_id, use that v2 declaration. Highest priority \u2014 seller asserts the link directly. SDKs SHOULD run the *narrows* check (canonical-formats.mdx 'Narrows \u2014 formal definition') between the v2 declaration's `params` and the referenced v1 format's `requirements`; on conflict, surface `FORMAT_DECLARATION_DIVERGENT` on the `get_products` response `errors[]`. Without the narrowing check, `v1_format_ref` is a hint rather than a contract.\n2. **Seller-asserted on the v1 file**: if the v1 format declaration carries an explicit `canonical` field, use it. (Note: `canonical_parameters` on the v1 file is deprecated for 3.1; SDKs reading 3.1 catalogs MUST still honor it when present, but `v1_format_ref` is the path forward.)\n3. **Registry glob**: look up `format_id` in this registry's `format_id_glob` entries.\n4. **Structural match**: attempt structural match against this registry's `structural` entries. A successful structural match yields a *family-level* identification only (e.g., 'this is a `video_vast`') \u2014 it does NOT yield a specific v1 `format_id`. SDKs use structural match for v1 \u2192 v2 projection (the inbound direction) but MUST NOT invert it to a v1 `format_id` on the outbound path.\n5. **Ambiguous family**: if step 4 succeeded but the matched entries are family-only (pure structural, no invertible literal), the canonical is **v1-unreachable for THIS specific product** unless the seller authors `v1_format_ref`. SDKs MUST surface `FORMAT_DECLARATION_V1_AMBIGUOUS` via `errors[]` augmentation rather than synthesize a plausible-but-arbitrary v1 `format_id`. Distinct from canonical-level v1-unreachability (a canonical with `v1_translatable: false` \u2014 `agent_placement`, `sponsored_placement`, `responsive_creative`, `image_carousel` \u2014 never has any v1 form regardless of registry coverage).\n6. **Fail closed**: SDK MUST NOT emit `format_options` for products carrying this format. SDKs MUST augment the response's `errors[]` array with an entry carrying `source: \"sdk\"`, `sdk_id: \"@\"`, `code: \"FORMAT_PROJECTION_FAILED\"`, `field: \"products[N].format_ids[K]\"`, and `error.details: { format_id, product_id, resolution_failure: \"no_explicit_canonical\" | \"no_registry_match\" | \"no_structural_match\" }`. Single mandated surface (`errors[]` augmentation) \u2014 lint-output channels are NOT acceptable; the multi-hop agent network needs warnings to propagate across SDK boundaries via the wire response. Logger-only warnings die in DEBUG. The advisory is non-fatal: the response stays 200/success, the product is still valid on the v1 path, only the v2 `format_options` projection is absent. Consumer-side counterpart to the producer SHOULD (sellers should add a v2 declaration with `v1_format_ref`, an explicit `canonical` field, or file a registry PR).\n\n**Match modes:**\n- `format_id_glob` \u2014 exact / glob match against the v1 `format_id.id`. Published non-wildcarded literals cover independently observed legacy conventions whose names carry semantic narrowing (duration, dimensions, or VAST delivery) that slot shape alone cannot recover. Each literal mapping preserves those constraints in canonical parameters; AAO-catalog-published formats with explicit canonical annotations still project via resolution-order step 2. Glob syntax: `*` matches any segment.\n- `structural` \u2014 match against the format's slot shape, asset types, and version constraints. The PRIMARY fallback for v1 wire traffic \u2014 catches custom v1 formats (a publisher's `acme_homepage_300x250` is structurally an IAB MREC) without enumerating every possible v1 name. v1 sellers in the wild naming things their own way are handled here, not by literal globs.\n\n**Alias collision precedence (normative).** When a v1 format's `assets[i]` carries multiple `asset_group_id` aliases that resolve to the same canonical asset_group (e.g., two slots both aliasing to `landing_page_url`), the SDK MUST resolve deterministically: the v1 format's `assets[*]` array order is authoritative \u2014 the first slot in declaration order wins, subsequent collisions are dropped from the projected v2 manifest and surfaced via `FORMAT_PROJECTION_FAILED` with `error.details: { collision_kind: \"asset_group_id_alias\", asset_group_id, winning_slot_id, dropped_slot_ids }`. SDKs MUST NOT silently pick one and discard the other without surfacing \u2014 silent picking creates inter-SDK divergence. Producers SHOULD avoid the collision by deduplicating aliased slots or using distinct `asset_group_id` values when both slots are semantically meaningful.\n\n**Image rendition-set exception (normative).** This specific rule takes precedence over the generic alias-collision rule above. When the matched mapping declares an image slot with `required_pixel_ratios`, v1 image assets sharing that slot's `asset_group_id` are intentional renditions rather than collisions. The SDK MUST validate each asset against a distinct accepted density and collect them, in v1 declaration order, into the canonical slot array. Missing or duplicate required densities fail under the rendition-set rules; only remaining same-group assets enter ordinary collision handling.\n\n**Governance**: same vocabulary-governance rules as `asset-group-vocabulary.json` and `format-shape-vocabulary.json` \u2014 additions land via PR with rationale + \u22651 reference adopter; AAO maintainer review; versioned + content-digested. Entries are additive; once published they are not removed (they may be marked `deprecated: true` if superseded).\n\n**Scope**: 7 structural fallback entries cover VAST 4.x / legacy VAST, DAAST 1.x, HTML5 zip bundles, hosted video, hosted audio, and url-shaped display tags. Literal entries cover independently observed legacy duration-, dimension-, and VAST-token naming conventions. Durationless placement ids video_pre_roll and video_mid_roll are deliberately omitted: projecting either to video_hosted without duration_ms_exact would resolve to an untraffickable format and defer failure until ad-server line-item creation. Failing closed during discovery is safer. Platform-specific formats (Meta Reels, TikTok Spark Ads, etc.) project via structural fallback or via the platform's own adagents.json `formats[]` block (#4620). The full v1-format audit dataset (~76% of formats from the 12-platform / 86-format audit in #3305) seeds the long-term roadmap and informs future literal-entry decisions.\n\nDigest the file content (sha256) when emitting in capabilities responses or referencing from SDK output. Buyers cache by `version` + `digest`.", + "version": "1.3.0", + "last_updated": "2026-08-03", "type": "object", "required": [ "version", @@ -287,6 +287,356 @@ }, "notes": "Observed AAO-namespace unsuffixed display size id. Exact pixel dimensions are retained in the projected parameters." }, + { + "v1_pattern": { + "format_id_glob": "display_300x250_image_2x" + }, + "v2": { + "canonical": "image", + "parameters": { + "width": 300, + "height": 250, + "pixel_ratios": [ + 2 + ] + } + }, + "notes": "Unversioned legacy reference-catalog compatibility format requiring only a 600x500 asset for a logical 300x250 image. pixel_ratios is opaque forward-projection metadata interpreted only by a 3.2-aware SDK; it is not pre-3.2 canonical protocol support." + }, + { + "v1_pattern": { + "format_id_glob": "display_728x90_image_2x" + }, + "v2": { + "canonical": "image", + "parameters": { + "width": 728, + "height": 90, + "pixel_ratios": [ + 2 + ] + } + }, + "notes": "Unversioned legacy reference-catalog compatibility format requiring only a 1456x180 asset for a logical 728x90 image. pixel_ratios is opaque forward-projection metadata interpreted only by a 3.2-aware SDK; it is not pre-3.2 canonical protocol support." + }, + { + "v1_pattern": { + "format_id_glob": "display_320x50_image_2x" + }, + "v2": { + "canonical": "image", + "parameters": { + "width": 320, + "height": 50, + "pixel_ratios": [ + 2 + ] + } + }, + "notes": "Unversioned legacy reference-catalog compatibility format requiring only a 640x100 asset for a logical 320x50 image. pixel_ratios is opaque forward-projection metadata interpreted only by a 3.2-aware SDK; it is not pre-3.2 canonical protocol support." + }, + { + "v1_pattern": { + "format_id_glob": "display_160x600_image_2x" + }, + "v2": { + "canonical": "image", + "parameters": { + "width": 160, + "height": 600, + "pixel_ratios": [ + 2 + ] + } + }, + "notes": "Unversioned legacy reference-catalog compatibility format requiring only a 320x1200 asset for a logical 160x600 image. pixel_ratios is opaque forward-projection metadata interpreted only by a 3.2-aware SDK; it is not pre-3.2 canonical protocol support." + }, + { + "v1_pattern": { + "format_id_glob": "display_336x280_image_2x" + }, + "v2": { + "canonical": "image", + "parameters": { + "width": 336, + "height": 280, + "pixel_ratios": [ + 2 + ] + } + }, + "notes": "Unversioned legacy reference-catalog compatibility format requiring only a 672x560 asset for a logical 336x280 image. pixel_ratios is opaque forward-projection metadata interpreted only by a 3.2-aware SDK; it is not pre-3.2 canonical protocol support." + }, + { + "v1_pattern": { + "format_id_glob": "display_300x600_image_2x" + }, + "v2": { + "canonical": "image", + "parameters": { + "width": 300, + "height": 600, + "pixel_ratios": [ + 2 + ] + } + }, + "notes": "Unversioned legacy reference-catalog compatibility format requiring only a 600x1200 asset for a logical 300x600 image. pixel_ratios is opaque forward-projection metadata interpreted only by a 3.2-aware SDK; it is not pre-3.2 canonical protocol support." + }, + { + "v1_pattern": { + "format_id_glob": "display_970x250_image_2x" + }, + "v2": { + "canonical": "image", + "parameters": { + "width": 970, + "height": 250, + "pixel_ratios": [ + 2 + ] + } + }, + "notes": "Unversioned legacy reference-catalog compatibility format requiring only a 1940x500 asset for a logical 970x250 image. pixel_ratios is opaque forward-projection metadata interpreted only by a 3.2-aware SDK; it is not pre-3.2 canonical protocol support." + }, + { + "v1_pattern": { + "format_id_glob": "display_300x250_image_1x_2x" + }, + "v2": { + "canonical": "image", + "parameters": { + "width": 300, + "height": 250, + "pixel_ratios": [ + 1, + 2 + ], + "slots": [ + { + "asset_group_id": "image_main", + "asset_type": "image", + "required": true, + "min": 2, + "max": 2, + "pixel_ratios": [ + 1, + 2 + ], + "required_pixel_ratios": [ + 1, + 2 + ] + } + ] + } + }, + "notes": "Unversioned legacy reference-catalog compatibility format requiring 300x250 and 600x500 renditions of one logical image. Density and required-coverage values are opaque forward-projection metadata for 3.2-aware SDKs, not pre-3.2 canonical protocol support." + }, + { + "v1_pattern": { + "format_id_glob": "display_728x90_image_1x_2x" + }, + "v2": { + "canonical": "image", + "parameters": { + "width": 728, + "height": 90, + "pixel_ratios": [ + 1, + 2 + ], + "slots": [ + { + "asset_group_id": "image_main", + "asset_type": "image", + "required": true, + "min": 2, + "max": 2, + "pixel_ratios": [ + 1, + 2 + ], + "required_pixel_ratios": [ + 1, + 2 + ] + } + ] + } + }, + "notes": "Unversioned legacy reference-catalog compatibility format requiring 728x90 and 1456x180 renditions of one logical image. Density and required-coverage values are opaque forward-projection metadata for 3.2-aware SDKs, not pre-3.2 canonical protocol support." + }, + { + "v1_pattern": { + "format_id_glob": "display_320x50_image_1x_2x" + }, + "v2": { + "canonical": "image", + "parameters": { + "width": 320, + "height": 50, + "pixel_ratios": [ + 1, + 2 + ], + "slots": [ + { + "asset_group_id": "image_main", + "asset_type": "image", + "required": true, + "min": 2, + "max": 2, + "pixel_ratios": [ + 1, + 2 + ], + "required_pixel_ratios": [ + 1, + 2 + ] + } + ] + } + }, + "notes": "Unversioned legacy reference-catalog compatibility format requiring 320x50 and 640x100 renditions of one logical image. Density and required-coverage values are opaque forward-projection metadata for 3.2-aware SDKs, not pre-3.2 canonical protocol support." + }, + { + "v1_pattern": { + "format_id_glob": "display_160x600_image_1x_2x" + }, + "v2": { + "canonical": "image", + "parameters": { + "width": 160, + "height": 600, + "pixel_ratios": [ + 1, + 2 + ], + "slots": [ + { + "asset_group_id": "image_main", + "asset_type": "image", + "required": true, + "min": 2, + "max": 2, + "pixel_ratios": [ + 1, + 2 + ], + "required_pixel_ratios": [ + 1, + 2 + ] + } + ] + } + }, + "notes": "Unversioned legacy reference-catalog compatibility format requiring 160x600 and 320x1200 renditions of one logical image. Density and required-coverage values are opaque forward-projection metadata for 3.2-aware SDKs, not pre-3.2 canonical protocol support." + }, + { + "v1_pattern": { + "format_id_glob": "display_336x280_image_1x_2x" + }, + "v2": { + "canonical": "image", + "parameters": { + "width": 336, + "height": 280, + "pixel_ratios": [ + 1, + 2 + ], + "slots": [ + { + "asset_group_id": "image_main", + "asset_type": "image", + "required": true, + "min": 2, + "max": 2, + "pixel_ratios": [ + 1, + 2 + ], + "required_pixel_ratios": [ + 1, + 2 + ] + } + ] + } + }, + "notes": "Unversioned legacy reference-catalog compatibility format requiring 336x280 and 672x560 renditions of one logical image. Density and required-coverage values are opaque forward-projection metadata for 3.2-aware SDKs, not pre-3.2 canonical protocol support." + }, + { + "v1_pattern": { + "format_id_glob": "display_300x600_image_1x_2x" + }, + "v2": { + "canonical": "image", + "parameters": { + "width": 300, + "height": 600, + "pixel_ratios": [ + 1, + 2 + ], + "slots": [ + { + "asset_group_id": "image_main", + "asset_type": "image", + "required": true, + "min": 2, + "max": 2, + "pixel_ratios": [ + 1, + 2 + ], + "required_pixel_ratios": [ + 1, + 2 + ] + } + ] + } + }, + "notes": "Unversioned legacy reference-catalog compatibility format requiring 300x600 and 600x1200 renditions of one logical image. Density and required-coverage values are opaque forward-projection metadata for 3.2-aware SDKs, not pre-3.2 canonical protocol support." + }, + { + "v1_pattern": { + "format_id_glob": "display_970x250_image_1x_2x" + }, + "v2": { + "canonical": "image", + "parameters": { + "width": 970, + "height": 250, + "pixel_ratios": [ + 1, + 2 + ], + "slots": [ + { + "asset_group_id": "image_main", + "asset_type": "image", + "required": true, + "min": 2, + "max": 2, + "pixel_ratios": [ + 1, + 2 + ], + "required_pixel_ratios": [ + 1, + 2 + ] + } + ] + } + }, + "notes": "Unversioned legacy reference-catalog compatibility format requiring 970x250 and 1940x500 renditions of one logical image. Density and required-coverage values are opaque forward-projection metadata for 3.2-aware SDKs, not pre-3.2 canonical protocol support." + }, { "v1_pattern": { "format_id_glob": "video_30s" diff --git a/schemas/cache/3.1/trusted-match/identity-match-response.json b/schemas/cache/3.1/trusted-match/identity-match-response.json index 12333515c..4c0064733 100644 --- a/schemas/cache/3.1/trusted-match/identity-match-response.json +++ b/schemas/cache/3.1/trusted-match/identity-match-response.json @@ -1,7 +1,7 @@ { "$schema": "http://json-schema.org/draft-07/schema#", - "title": "Identity Match Response", - "description": "Response indicating which packages the user is eligible for. The serve_window_sec field defines a per-package single-shot fcap: after serving the user one impression on each eligible package, the publisher MUST re-query Identity Match before serving from those packages again. Extension fields (ext, context) are intentionally omitted to prevent data leakage across the identity privacy boundary.", + "title": "Identity Match Response (Router \u2192 Publisher)", + "description": "Router-to-publisher shape of the Identity Match response. The router collects each identity agent's ordered TMPX chunks (see provider-identity-match-response.json) and forwards them under the emitting `provider_id`, preserving provider attribution and chunk order. Each chunk is a provider-declared `{slot_id, value}` pair; the publisher's deployment configuration (see publisher-tmpx-config.json) maps `(provider_id, slot_id)` to the local ad-server macro name, targeting key, VAST substitution, or play-log field. The provider\u2192router boundary never carries a publisher-local destination name, so no cross-provider name-hijack surface exists. Provider-hop fields (`tmpx_chunks` at the root) MUST NOT appear on this shape \u2014 a router that leaks them alongside `tmpx_providers` corrupts per-provider accounting. Envelope extension fields (`context`, `ext`) are intentionally omitted to prevent data leakage across the identity privacy boundary; they are forbidden by this schema. The serve_window_sec field defines a per-package single-shot fcap: after serving the user one impression on each eligible package, the publisher MUST re-query Identity Match before serving from those packages again.", "type": "object", "allOf": [ { @@ -39,69 +39,69 @@ "type": "string", "description": "DEPRECATED in favor of tmpx_providers. Routers MAY continue to populate this field for back-compat with consumers that only know the single-token shape; when both fields are present, tmpx_providers is authoritative. Single HPKE-encrypted exposure token containing the resolved user identity tokens. Wire format: kid.base64url_nopad(ciphertext) \u2014 unpadded base64url per RFC 4648 section 5 (no = characters). Publishers MUST treat this value as opaque pass-through data. Removed in 4.0." }, - "tmpx_macros": { - "type": "array", - "description": "Provider-emitted: the identity agent's ordered TMPX chunks paired with the macro name each chunk fills. Macro names MUST be drawn from the provider's registered `tmpx_macros` list (provider-registration.json) and appear in the same order \u2014 names are part of operational setup, not protocol-synthesized. Capped at 2 chunks in v1; the cap MAY rise without a shape change. Each `value` is an opaque URL-safe wire string the publisher substitutes verbatim into the matching ad-server macro slot \u2014 publishers MUST NOT parse, decode, transform, or choose an encoding. The router collects entries from every provider that emits them into `tmpx_providers`, keyed by provider_id; consumers reading the merged response SHOULD consume `tmpx_providers` and ignore `tmpx_macros` at the root.", - "items": { - "$ref": "#/$defs/TmpxMacro" - }, - "minItems": 1, - "maxItems": 2 - }, "tmpx_providers": { "type": "object", - "description": "Router-populated: TMPX macro/value pairs grouped by the originating identity provider's provider_id, so the publisher fires each provider's tokens through that provider's specific ad-server macros (configured per provider in GAM / VAST URL / DOOH play log). Each entry's `macros[]` is a copy of the provider's emitted `tmpx_macros` ordered list. SHAPE CHANGE: was `Map` in the experimental surface that shipped in #5689; now `Map` to carry exact macro/value pairs and support multi-chunk TMPX. Sanctioned by the experimental contract (`x-status: experimental` on this schema). Required by router conformance when any identity provider emitted TMPX in this request; collapsing per-provider tokens into a single string loses attribution and breaks per-provider impression accounting. Map keys MUST be valid provider_ids registered for this fan-out. Publishers MUST traffic only the macro names the response advertises; macro names MUST NOT be derived from provider_id at runtime.", + "description": "Router-populated: ordered TMPX chunk/value pairs grouped by the originating identity provider's `provider_id`. Each entry's `chunks[]` is a copy of the provider's emitted `tmpx_chunks` list, in the same order. Each chunk carries a provider-local `slot_id` (from the provider's registered `tmpx_slots`) and an opaque URL-safe `value`; the publisher's deployment configuration (see publisher-tmpx-config.json) resolves each `(provider_id, slot_id)` pair to the ad-server macro name, targeting key, VAST substitution, or play-log field for that surface. The protocol carries values and attribution only. Required by router conformance when any identity provider emitted TMPX in this request; collapsing per-provider tokens into a single string loses attribution and breaks per-provider impression accounting. Map keys MUST match the provider_id charset registered in provider-registration.json (enforced by `propertyNames`). Publishers MUST NOT parse, decode, or transform any chunk's `value` \u2014 each is an opaque URL-safe wire string substituted verbatim into the mapped destination.", + "propertyNames": { + "type": "string", + "pattern": "^[A-Za-z0-9_]+$", + "minLength": 1, + "maxLength": 64 + }, "additionalProperties": { "type": "object", "properties": { - "macros": { + "chunks": { "type": "array", - "description": "Ordered TMPX macro/value pairs for this provider. Names MUST match the provider's registered `tmpx_macros`.", + "description": "Ordered TMPX chunks for this provider. Each entry is a `{slot_id, value}` pair copied verbatim from the provider's `tmpx_chunks`. Ordered-prefix invariant: the sequence of `slot_id`s MUST equal an ordered prefix of the provider's registered `tmpx_slots` \u2014 publishers MAY reject responses whose slot_ids or ordering diverge. Cap of 2 chunks in v1; the cap MAY rise without a shape change.", "items": { - "$ref": "#/$defs/TmpxMacro" + "$ref": "tmpx-chunk.json" }, "minItems": 1, "maxItems": 2 } }, "required": [ - "macros" + "chunks" ], "additionalProperties": false } } }, - "$defs": { - "TmpxMacro": { - "type": "object", - "description": "A single ad-server macro slot and the URL-safe value the publisher substitutes into it.", - "properties": { - "name": { - "type": "string", - "pattern": "^[A-Z][A-Z0-9_]*$", - "minLength": 1, - "maxLength": 64, - "description": "Macro name as configured in the publisher's ad server (e.g. `PIN_TMPX_1`). MUST appear in the emitting provider's registered `tmpx_macros` list. Provider-namespaced so the publisher can target distinct slots per provider." - }, - "value": { - "type": "string", - "minLength": 1, - "maxLength": 1024, - "description": "Opaque, URL-safe wire string the publisher substitutes verbatim into the named macro slot. Publishers MUST NOT parse, decode, or transform this value. The protocol fixes the wire format so platforms interoperate; a platform that can carry raw bytes MAY optimize privately but the wire contract remains the URL-safe string." - } - }, - "required": [ - "name", - "value" - ], - "additionalProperties": false - } - }, "required": [ "type", "request_id", "eligible_package_ids", "serve_window_sec" ], + "not": { + "anyOf": [ + { + "required": [ + "tmpx_chunks" + ] + }, + { + "required": [ + "tmpx_values" + ] + }, + { + "required": [ + "tmpx_macros" + ] + }, + { + "required": [ + "context" + ] + }, + { + "required": [ + "ext" + ] + } + ] + }, "additionalProperties": true } \ No newline at end of file diff --git a/schemas/cache/3.1/trusted-match/provider-identity-match-response.json b/schemas/cache/3.1/trusted-match/provider-identity-match-response.json new file mode 100644 index 000000000..5db105f3a --- /dev/null +++ b/schemas/cache/3.1/trusted-match/provider-identity-match-response.json @@ -0,0 +1,89 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "Identity Match Response (Provider \u2192 Router)", + "description": "Provider-to-router shape of the Identity Match response. An identity agent returns eligibility, the per-package serve-window throttle, and \u2014 when it mints one \u2014 an ordered list of TMPX chunks. Each chunk pairs a provider-local `slot_id` (declared at registration in `tmpx_slots`) with an opaque URL-safe `value`. Publisher-local destination names (ad-server macros, GAM key-values, VAST URL macros, DOOH play-log fields) MUST NOT appear on this hop; the router keys chunks under the emitting `provider_id` and the publisher's deployment configuration resolves `(provider_id, slot_id)` to the local destination (see publisher-tmpx-config.json). Router-hop fields (`tmpx_providers`, `tmpx`) MUST NOT appear on this shape \u2014 a router receiving them from a provider MUST reject the response. Envelope extension fields (`context`, `ext`) are intentionally omitted to prevent data leakage across the identity privacy boundary; they are forbidden by this schema.", + "type": "object", + "allOf": [ + { + "$ref": "../core/version-envelope.json" + }, + { + "$ref": "../core/protocol-envelope.json" + } + ], + "x-status": "experimental", + "properties": { + "type": { + "type": "string", + "const": "identity_match_response", + "description": "Message type discriminator for deserialization. Same const as the router\u2192publisher variant so publisher-facing decoders can key off type before dispatching on shape." + }, + "request_id": { + "type": "string", + "description": "Echoed request identifier from the identity match request." + }, + "eligible_package_ids": { + "type": "array", + "description": "Package IDs the user is eligible for. Packages not listed are ineligible.", + "items": { + "type": "string" + } + }, + "serve_window_sec": { + "type": "integer", + "description": "Per-package single-shot fcap window, in seconds. After serving the user one impression on each eligible package within this window, the publisher MUST re-query Identity Match before serving from those packages again. Not a router response cache TTL \u2014 it is a buyer-asserted serve throttle. Multi-impression frequency caps are handled separately by the buyer's impression tracker. Maximum 300.", + "minimum": 1, + "maximum": 300 + }, + "tmpx_chunks": { + "type": "array", + "description": "Ordered TMPX chunk/value pairs this identity agent mints. Each entry names the provider-local `slot_id` the value fills (from the provider's registered `tmpx_slots` in provider-registration.json). Ordered-prefix invariant: a response that carries fewer chunks than the provider registered MUST emit an ordered prefix of the registered `tmpx_slots` \u2014 routers MUST NOT reorder or fill gaps. The router MUST validate this contract before forwarding: if the provider has no `tmpx_slots` registration, or if the chunk `slot_id` sequence is not an exact non-empty ordered prefix of the registered list (duplicate, reordered, sparse, or unregistered slot IDs), the router MUST drop that provider's chunks atomically and MUST NOT forward them into `tmpx_providers`. Cap of 2 chunks in v1 aligned with the GAM macro-slot budget; the cap MAY rise without a shape change. Omitted when this provider mints no TMPX (e.g. no eligible packages).", + "items": { + "$ref": "tmpx-chunk.json" + }, + "minItems": 1, + "maxItems": 2 + } + }, + "required": [ + "type", + "request_id", + "eligible_package_ids", + "serve_window_sec" + ], + "not": { + "anyOf": [ + { + "required": [ + "tmpx_providers" + ] + }, + { + "required": [ + "tmpx" + ] + }, + { + "required": [ + "tmpx_values" + ] + }, + { + "required": [ + "tmpx_macros" + ] + }, + { + "required": [ + "context" + ] + }, + { + "required": [ + "ext" + ] + } + ] + }, + "additionalProperties": true +} \ No newline at end of file diff --git a/schemas/cache/3.1/trusted-match/provider-registration.json b/schemas/cache/3.1/trusted-match/provider-registration.json index 1f769353e..c1bf224a8 100644 --- a/schemas/cache/3.1/trusted-match/provider-registration.json +++ b/schemas/cache/3.1/trusted-match/provider-registration.json @@ -7,7 +7,7 @@ "properties": { "provider_id": { "type": "string", - "description": "Stable identifier for this provider registration. Used in logs, metrics, cache keys, and as the key in `tmpx_providers` on the identity-match response so the publisher can route each provider's TMPX `macros[]` to that provider's pre-configured ad-server slots (names registered in `tmpx_macros` below \u2014 macro names MUST NOT be derived from `provider_id` at runtime). Publishers assign this \u2014 it is not the provider's agent_url. Charset is constrained to a safe alphanumeric/underscore set so the value can appear in operational surfaces (logs, metrics, dashboards) without quoting.", + "description": "Stable identifier for this provider registration. Used in logs, metrics, cache keys, and as the key in `tmpx_providers` on the identity-match response so the publisher can route each provider's TMPX chunks to that provider's pre-configured ad-server destinations via the publisher's `tmpx_macro_mapping` deployment configuration (see publisher-tmpx-config.json). Publishers assign this \u2014 it is not the provider's agent_url. Charset is constrained to a safe alphanumeric/underscore set so the value can appear in operational surfaces (logs, metrics, dashboards) without quoting.", "pattern": "^[A-Za-z0-9_]+$", "minLength": 1, "maxLength": 64 @@ -64,17 +64,18 @@ "minimum": 0, "default": 0 }, - "tmpx_macros": { + "tmpx_slots": { "type": "array", - "description": "Stable, provider-namespaced ad-server macro names this provider's TMPX response fills, ordered. Publishers traffic these exact names in their ad server (GAM key-values, VAST URL macros, DOOH play-log fields); the router places each provider's TMPX chunks into the matching slots on the identity-match response (`tmpx_providers[provider_id].macros[]`). Names MUST be provider-namespaced so publishers can configure distinct macros per provider (e.g. `PIN_TMPX_1`, `PIN_TMPX_2` for one provider; `NOVA_TMPX_1` for another). Ordered so multi-chunk TMPX values (when the opaque token exceeds one macro slot) are placed deterministically. Capped at 2 entries in v1; the cap MAY be raised in a later version without a shape change. A provider that emits TMPX on its identity-match response (populates `tmpx_macros[]` there) MUST also register this list \u2014 otherwise the router has no slot names to forward \u2014 but the schema cannot enforce this because \"emits TMPX\" is not a schema-visible predicate. Providers that do not emit TMPX omit this field.", + "description": "Stable provider-local slot identifiers for the ordered TMPX chunks this provider mints. Slot IDs are opaque provider-namespaced tokens (e.g. `[\"primary\",\"secondary\"]`), NOT ad-server macro names \u2014 publishers map `(provider_id, slot_id)` \u2192 local destination via `tmpx_macro_mapping` in publisher-tmpx-config.json, so the destination namespace stays publisher-owned and the router never accepts a destination name from an untrusted provider. Distinct providers MAY reuse the same slot_id without collision because publisher lookup is keyed on `(provider_id, slot_id)`. Publishers use this list at startup to validate `tmpx_macro_mapping` covers every slot the provider mints and to detect config drift when the provider's slot contract changes. Ordering carries the ordered-prefix invariant: a provider that emits fewer chunks than it registered MUST emit an ordered prefix of this list \u2014 chunks map to slots in registration order and MUST NOT be shifted, sparse, or reordered. Cap of 2 slots in v1 aligned with the GAM macro-slot budget; the cap MAY rise without a shape change. A provider that emits TMPX (populates `tmpx_chunks` on its identity-match response) MUST register this list; a provider that does not emit TMPX omits it. Schema cannot enforce that predicate because \"emits TMPX\" is not schema-visible.", "items": { "type": "string", - "pattern": "^[A-Z][A-Z0-9_]*$", + "pattern": "^[a-zA-Z][a-zA-Z0-9_]*$", "minLength": 1, "maxLength": 64 }, "minItems": 1, - "maxItems": 2 + "maxItems": 2, + "uniqueItems": true }, "status": { "type": "string", diff --git a/schemas/cache/3.1/trusted-match/publisher-tmpx-config.json b/schemas/cache/3.1/trusted-match/publisher-tmpx-config.json new file mode 100644 index 000000000..bd8d9c942 --- /dev/null +++ b/schemas/cache/3.1/trusted-match/publisher-tmpx-config.json @@ -0,0 +1,40 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "Publisher TMPX Macro Mapping", + "description": "Publisher-owned deployment configuration that maps each identity provider's TMPX slots to the ad-server macro names (or targeting keys, VAST substitutions, DOOH play-log fields) the publisher wants those chunks fired into on this surface. Mapping is authored by the publisher \u2014 the same operator who trafficks the corresponding ad-server line items \u2014 and never travels on the wire between identity provider and router. This keeps macro naming a deployment concern rather than a protocol identifier: providers emit chunks as `{slot_id, value}` pairs (see provider-identity-match-response.json), the router preserves ordering and slot IDs under the emitting `provider_id` (see identity-match-response.json), and this configuration resolves each `(provider_id, slot_id)` to a local destination on the way to the ad server. A publisher may map the same provider to different destinations across surfaces (GAM key-values vs. VAST macros vs. DOOH play-log fields) by carrying one instance of this configuration per surface.", + "x-status": "experimental", + "type": "object", + "properties": { + "tmpx_macro_mapping": { + "type": "object", + "description": "Map from `provider_id` to a slot-keyed map of ad-server destinations (macro names, GAM key-values, VAST URL macro tokens, DOOH play-log field identifiers) for that provider on this surface. The inner map's keys are the provider-local `slot_id` values the provider registered in `tmpx_slots` (see provider-registration.json). At serve time, the publisher's adapter reads `tmpx_providers[provider_id].chunks[]` from the identity-match response and, for each chunk, substitutes the chunk's `value` into `tmpx_macro_mapping[provider_id][chunk.slot_id]`. Publishers use the outer map's keys plus the inner map's keys to validate the mapping at startup \u2014 every `slot_id` a provider registered in `tmpx_slots` SHOULD have a corresponding entry in that provider's inner map, and publishers SHOULD surface any missing entry as a startup warning so the operator can add it before responses begin carrying the unmapped slot. The exact destination string is publisher-local: GAM adopters typically use uppercase snake-case macro names, VAST surfaces use URL macro tokens, DOOH surfaces use play-log field identifiers. Outer-map key charset matches `provider_id` in provider-registration.json (enforced by `propertyNames`). Inner-map key charset matches `slot_id` in tmpx-chunk.json. When a response carries a `slot_id` for a provider that this mapping has no entry for \u2014 the mapping is missing the whole provider, OR the provider is present but the specific `slot_id` is unknown to this surface \u2014 the publisher's adapter MUST fail closed for that provider on that impression: none of that provider's chunks are fired into the ad-serving path and the adapter logs a configuration error. Other providers on the same response are unaffected. A `provider_id` absent from this mapping entirely (e.g. a newly onboarded provider not yet trafficked on this surface) is the same case \u2014 the adapter drops that provider's chunks on this surface rather than firing them into an unconfigured destination. Startup validation and serve-time fail-closed are two stages of a single rule: the warning at startup is the operator's chance to fix the mapping before the serve-time rule catches the missing slot.", + "propertyNames": { + "type": "string", + "pattern": "^[A-Za-z0-9_]+$", + "minLength": 1, + "maxLength": 64 + }, + "additionalProperties": { + "type": "object", + "description": "Map from the provider's registered `slot_id` to the ad-server destination string for that slot on this surface. Opaque to the protocol \u2014 the exact form is publisher-local.", + "propertyNames": { + "type": "string", + "pattern": "^[a-zA-Z][a-zA-Z0-9_]*$", + "minLength": 1, + "maxLength": 64 + }, + "additionalProperties": { + "type": "string", + "minLength": 1, + "maxLength": 128 + }, + "minProperties": 1, + "maxProperties": 2 + } + } + }, + "required": [ + "tmpx_macro_mapping" + ], + "additionalProperties": false +} \ No newline at end of file diff --git a/schemas/cache/3.1/trusted-match/tmpx-chunk.json b/schemas/cache/3.1/trusted-match/tmpx-chunk.json new file mode 100644 index 000000000..a26261bf5 --- /dev/null +++ b/schemas/cache/3.1/trusted-match/tmpx-chunk.json @@ -0,0 +1,27 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "TMPX Chunk", + "description": "A single provider TMPX chunk \u2014 the provider-local `slot_id` (declared at registration in `tmpx_slots`) and its opaque URL-safe `value`. Same shape on both hops of the Identity Match response: providers emit `tmpx_chunks[]` on the provider\u2192router shape, the router forwards them under `tmpx_providers[provider_id].chunks[]` on the router\u2192publisher shape. Publisher-local destination names never appear here \u2014 the publisher's deployment configuration resolves `(provider_id, slot_id)` \u2192 local destination via publisher-tmpx-config.json.", + "x-status": "experimental", + "type": "object", + "properties": { + "slot_id": { + "type": "string", + "pattern": "^[a-zA-Z][a-zA-Z0-9_]*$", + "minLength": 1, + "maxLength": 64, + "description": "Provider-local slot identifier from the emitting provider's registered `tmpx_slots` (provider-registration.json). Opaque provider-namespaced token; publishers map `(provider_id, slot_id)` \u2192 local destination via `tmpx_macro_mapping`. NOT an ad-server macro name." + }, + "value": { + "type": "string", + "minLength": 1, + "maxLength": 1024, + "description": "Opaque, URL-safe wire string the publisher substitutes verbatim into the destination the publisher's mapping resolves for this `(provider_id, slot_id)` pair. Publishers MUST NOT parse, decode, or transform this value." + } + }, + "required": [ + "slot_id", + "value" + ], + "additionalProperties": false +} \ No newline at end of file diff --git a/scripts/post_generate_fixes.py b/scripts/post_generate_fixes.py index c8c9fe94a..762d3bd74 100644 --- a/scripts/post_generate_fixes.py +++ b/scripts/post_generate_fixes.py @@ -1926,14 +1926,36 @@ def _require_identity_match_dimensions(self) -> TmpProviderRegistration1: source = identity_match_response.read_text() if "_validate_tmpx_provider_ids" in source: - print(" trusted_match/identity_match_response.py validators already fixed") + changed = False + version_import = "from ..core.version_envelope import AdcpVersionEnvelope\n" + if "_PROVIDER_ID_PATTERN =" not in source: + source = source.replace( + version_import, + version_import + "\n_PROVIDER_ID_PATTERN = re.compile(r'^[A-Za-z0-9_]{1,64}$')\n", + 1, + ) + changed = True + if "class IdentityMatchResponseRouterPublisher(" in source: + corrected = source.replace( + "def _validate_tmpx_provider_ids(self) -> IdentityMatchResponse:", + "def _validate_tmpx_provider_ids(self) -> IdentityMatchResponseRouterPublisher:", + 1, + ) + changed = changed or corrected != source + source = corrected + if changed: + identity_match_response.write_text(source) + print(" trusted_match/identity_match_response.py validators repaired") + else: + print(" trusted_match/identity_match_response.py validators already fixed") return - source = source.replace( - "from __future__ import annotations\n\n", - "from __future__ import annotations\n\nimport re\n\n", - 1, - ) + if "\nimport re\n" not in source: + source = source.replace( + "from __future__ import annotations\n\n", + "from __future__ import annotations\n\nimport re\n\n", + 1, + ) if "from pydantic import ConfigDict, Field" in source: source = source.replace( "from pydantic import ConfigDict, Field", @@ -1944,17 +1966,25 @@ def _require_identity_match_dimensions(self) -> TmpProviderRegistration1: print(" trusted_match/identity_match_response.py pydantic import shape not found") return + version_import = "from ..core.version_envelope import AdcpVersionEnvelope\n" source = source.replace( - "from ..core.version_envelope import AdcpVersionEnvelope\n\n\n", - "from ..core.version_envelope import AdcpVersionEnvelope\n\n\n_PROVIDER_ID_PATTERN = re.compile(r'^[A-Za-z0-9_]{1,64}$')\n\n\n", + version_import, + version_import + "\n_PROVIDER_ID_PATTERN = re.compile(r'^[A-Za-z0-9_]{1,64}$')\n", 1, ) + response_class_match = re.search( + r"^class (IdentityMatchResponse(?:RouterPublisher)?)\(", source, re.MULTILINE + ) + if response_class_match is None: + print(" trusted_match/identity_match_response.py response class not found") + return + response_class = response_class_match.group(1) source = ( source.rstrip() - + """ + + f""" @model_validator(mode='after') - def _validate_tmpx_provider_ids(self) -> IdentityMatchResponse: + def _validate_tmpx_provider_ids(self) -> {response_class}: if self.tmpx_providers is None: return self invalid = [ @@ -1971,6 +2001,111 @@ def _validate_tmpx_provider_ids(self) -> IdentityMatchResponse: print(" trusted_match/identity_match_response.py: added runtime validators") +def restore_trusted_match_compatibility_aliases() -> None: + """Keep 3.1.8 Trusted Match imports available after the 3.1.10 rename. + + AdCP 3.1.10 replaced provider-supplied macro names with publisher-owned + slot mappings. The new wire types must be primary, but the SDK's public + collision aliases still promise the old ``TmpxMacro`` helper classes and + ``IdentityMatchResponse`` name. Retain those helpers as compatibility + models; they are intentionally not referenced by the 3.1.10 response + fields. + """ + + identity_match_response = OUTPUT_DIR / "trusted_match" / "identity_match_response.py" + if identity_match_response.exists(): + source = identity_match_response.read_text() + changed = False + if "class TmpxMacro(" not in source: + compatibility_model = """ +class TmpxMacro(AdCPBaseModel): + \"\"\"Deprecated 3.1.8 TMPX macro/value compatibility model.\"\"\" + + model_config = ConfigDict( + extra='forbid', + ) + name: Annotated[ + str, + Field(max_length=64, min_length=1, pattern='^[A-Z][A-Z0-9_]*$'), + ] + value: Annotated[str, Field(max_length=1024, min_length=1)] + + +""" + source = source.replace( + "class TmpxProviders(", compatibility_model + "class TmpxProviders(", 1 + ) + changed = True + if ( + "class IdentityMatchResponseRouterPublisher(" in source + and "IdentityMatchResponse = IdentityMatchResponseRouterPublisher" not in source + ): + source = ( + source.rstrip() + + "\n\n\nIdentityMatchResponse = IdentityMatchResponseRouterPublisher\n" + ) + changed = True + if changed: + identity_match_response.write_text(source) + print(" trusted_match/identity_match_response.py: restored compatibility aliases") + else: + print( + " trusted_match/identity_match_response.py compatibility aliases already restored" + ) + + provider_registration = OUTPUT_DIR / "trusted_match" / "provider_registration.py" + if provider_registration.exists(): + source = provider_registration.read_text() + if "class TmpxMacro(" not in source: + compatibility_model = """ +class TmpxMacro(RootModel[str]): + \"\"\"Deprecated 3.1.8 registered macro-name compatibility model.\"\"\" + + root: Annotated[str, Field(max_length=64, min_length=1, pattern='^[A-Z][A-Z0-9_]*$')] + + +""" + source = source.replace("class TmpxSlot(", compatibility_model + "class TmpxSlot(", 1) + provider_registration.write_text(source) + print( + " trusted_match/provider_registration.py: restored TmpxMacro compatibility model" + ) + else: + print( + " trusted_match/provider_registration.py TmpxMacro compatibility model already restored" + ) + + +def fix_publisher_tmpx_mapping_key_constraints() -> None: + """Repair datamodel-codegen's nested ``propertyNames`` key annotation. + + For the publisher TMPX configuration's map-of-maps, the generator emits + the outer key as ``StringConstraints(...)`` instead of + ``Annotated[str, StringConstraints(...)]``. Pydantic then treats the + constraint instance as a dataclass type and cannot build the model. + """ + + target = OUTPUT_DIR / "trusted_match" / "publisher_tmpx_config.py" + if not target.exists(): + print(" trusted_match/publisher_tmpx_config.py not found (skipping)") + return + + source = target.read_text() + broken = ( + " StringConstraints(pattern=r'^[A-Za-z0-9_]+$', " + "min_length=1, max_length=64),\n" + ) + fixed = ( + " Annotated[str, StringConstraints(pattern=r'^[A-Za-z0-9_]+$', " + "min_length=1, max_length=64)],\n" + ) + if broken in source: + target.write_text(source.replace(broken, fixed, 1)) + print(" trusted_match/publisher_tmpx_config.py: fixed outer map key constraint") + else: + print(" trusted_match/publisher_tmpx_config.py outer map key already fixed") + + def fix_wholesale_cache_scope_defaults() -> None: """Default beta 3 wholesale cache scope to public in typed responses.""" targets = [ @@ -3692,6 +3827,8 @@ def main(): fix_unchanged_literal_defaults, fix_protocol_envelope_status_default, fix_trusted_match_runtime_validators, + restore_trusted_match_compatibility_aliases, + fix_publisher_tmpx_mapping_key_constraints, fix_wholesale_cache_scope_defaults, fix_product_publisher_property_model_coercion, fix_mcp_webhook_operation_id_optional, diff --git a/src/adcp/ADCP_VERSION b/src/adcp/ADCP_VERSION index c848fb9cb..c7a249882 100644 --- a/src/adcp/ADCP_VERSION +++ b/src/adcp/ADCP_VERSION @@ -1 +1 @@ -3.1.8 +3.1.10 diff --git a/src/adcp/canonical_formats/registry.py b/src/adcp/canonical_formats/registry.py index bcab15901..c5d6509e9 100644 --- a/src/adcp/canonical_formats/registry.py +++ b/src/adcp/canonical_formats/registry.py @@ -4,9 +4,9 @@ ``registries/v1-canonical-mapping.json``. Two match modes: * **Glob** — exact / wildcard match against a v1 ``format_id.id`` value. - The 3.1.8 registry carries literal entries for observed legacy duration, - dimension, and VAST naming conventions. The matcher handles ``*`` - wildcards anywhere in the pattern so additional literal entries work + The 3.1.10 registry carries literal entries for observed legacy duration, + dimension, VAST, and Retina image naming conventions. The matcher handles + ``*`` wildcards anywhere in the pattern so additional literal entries work without further code change. * **Structural** — match against the v1 format's slot shape, asset types, and VAST/DAAST version constraints. The primary fallback for v1 wire diff --git a/src/adcp/canonical_formats/v1_to_v2.py b/src/adcp/canonical_formats/v1_to_v2.py index 3755323eb..3b2558284 100644 --- a/src/adcp/canonical_formats/v1_to_v2.py +++ b/src/adcp/canonical_formats/v1_to_v2.py @@ -18,12 +18,14 @@ :class:`CanonicalProjectionReference` carrying ``kind``, ``asset_source``, and ``slots_override[]``. Highest priority on the v1→v2 path. Registry-published ``parameters`` for a matching - glob still fill in anything the seller didn't restate. + glob still fill neutral parameters the seller didn't restate, but + registry slot and pixel-density defaults never merge into the + seller-authored declaration. 2. **Registry glob match** (registry step 3). Look up ``v1_format.format_id.id`` in the bundled registry's - ``format_id_glob`` entries. The bundled 3.1.8 registry includes - literal entries for observed legacy duration, dimension, and VAST - naming conventions. + ``format_id_glob`` entries. The bundled 3.1.10 registry includes + literal entries for observed legacy duration, dimension, VAST, and + Retina image naming conventions. 3. **Registry structural match** (registry steps 4 + 5). Match ``v1_format.assets[*].asset_type`` + VAST/DAAST versions + dimensions against the registry's ``structural`` entries. Yields a @@ -65,6 +67,12 @@ FormatId = LegacyFormatId +_SELLER_AUTHORITATIVE_PARAM_KEYS = { + "pixel_ratios", + "required_pixel_ratios", + "slots", +} + @dataclass class V1ToV2Projection: @@ -267,10 +275,10 @@ def project_v1_format_to_declaration( # seller annotations can still pick up registry-published default # ``parameters`` without forcing the seller to restate them on the v1 # file. Step 1 (seller annotation) overrides ``kind`` / - # ``slots_override`` / ``asset_source`` but does NOT clobber the - # registry's parametric defaults — that would lose every parameter - # a registry glob carries (e.g., ``vast_version``, dimensions) when - # a seller annotates only ``{kind: video_vast}``. + # ``slots_override`` / ``asset_source``. Neutral registry parameters + # such as dimensions still fill omitted values, but seller-authored + # declarations must not inherit registry slot or pixel-density + # contracts. registry_params: dict[str, Any] = {} registry_kind: CanonicalFormatKind | None = None for mapping in registry.mappings: @@ -283,15 +291,21 @@ def project_v1_format_to_declaration( # --- Step 1 (registry resolution-order step 2): seller-asserted # ``canonical`` annotation on the v1 file. Annotation wins on - # ``kind`` + ``asset_source`` + ``slots_override``; registry - # parameters fill in anything the seller didn't restate. + # ``kind`` + ``asset_source`` + ``slots_override``; neutral registry + # parameters fill omitted values without importing registry slot or + # pixel-density contracts. annotation = _v1_canonical_annotation(v1_format) if annotation is not None: + seller_params = { + key: value + for key, value in registry_params.items() + if key not in _SELLER_AUTHORITATIVE_PARAM_KEYS + } return V1ToV2Projection( declaration=_build_declaration( kind=annotation.kind, v1_format_id=fid, - params=registry_params, + params=seller_params, canonical_ref=annotation, ) ) diff --git a/src/adcp/types/_generated.py b/src/adcp/types/_generated.py index 6b969a5f9..284a0303e 100644 --- a/src/adcp/types/_generated.py +++ b/src/adcp/types/_generated.py @@ -10,7 +10,7 @@ DO NOT EDIT MANUALLY. Generated from: https://github.com/adcontextprotocol/adcp/tree/main/schemas -Generation date: 2026-07-29 02:08:16 UTC +Generation date: 2026-08-04 09:55:15 UTC """ # ruff: noqa: E501, I001 @@ -2053,15 +2053,22 @@ ) from adcp.types.generated_poc.trusted_match.identity_match_response import ( IdentityMatchResponse, + IdentityMatchResponseRouterPublisher, TmpxProviders, ) from adcp.types.generated_poc.trusted_match.offer import Offer from adcp.types.generated_poc.trusted_match.offer_price import OfferPrice +from adcp.types.generated_poc.trusted_match.provider_identity_match_response import ( + IdentityMatchResponseProviderRouter, +) from adcp.types.generated_poc.trusted_match.provider_registration import ( TmpProviderRegistration, TmpProviderRegistration1, TmpProviderRegistration2, + TmpxSlot, ) +from adcp.types.generated_poc.trusted_match.publisher_tmpx_config import PublisherTmpxMacroMapping +from adcp.types.generated_poc.trusted_match.tmpx_chunk import TmpxChunk # Special imports for name collisions (qualified names for types defined in multiple modules) from adcp.types.generated_poc.core.package import Package as _PackageFromPackage @@ -2894,6 +2901,8 @@ "Identity", "IdentityMatchRequest", "IdentityMatchResponse", + "IdentityMatchResponseProviderRouter", + "IdentityMatchResponseRouterPublisher", "IdentityRef", "IfNotCovered", "Image", @@ -3262,6 +3271,7 @@ "PublisherPropertySelector1", "PublisherPropertySelector2", "PublisherPropertySelector3", + "PublisherTmpxMacroMapping", "PurchaseType", "Purge", "PurgeKind", @@ -3602,7 +3612,9 @@ "TmpProviderRegistration1", "TmpProviderRegistration2", "TmpResponseType", + "TmpxChunk", "TmpxProviders", + "TmpxSlot", "Tone", "Tools", "TotalBudget", diff --git a/src/adcp/types/generated_poc/adagents.py b/src/adcp/types/generated_poc/adagents.py index e87027f91..03b5c62db 100644 --- a/src/adcp/types/generated_poc/adagents.py +++ b/src/adcp/types/generated_poc/adagents.py @@ -1,6 +1,6 @@ # generated by datamodel-codegen: # filename: adagents.json -# timestamp: 2026-07-29T02:07:25+00:00 +# timestamp: 2026-08-04T09:50:23+00:00 from __future__ import annotations @@ -1270,12 +1270,12 @@ class AdcpAgentsAuthorization2( description='Inline structure variant - contains full agent authorization data', examples=[ { - '$schema': '/schemas/3.1.8/adagents.json', + '$schema': '/schemas/3.1.10/adagents.json', 'authoritative_location': 'https://cdn.example.com/adagents/v2/adagents.json', 'last_updated': '2025-01-15T10:00:00Z', }, { - '$schema': '/schemas/3.1.8/adagents.json', + '$schema': '/schemas/3.1.10/adagents.json', 'properties': [ { 'property_id': 'example_site', @@ -1332,7 +1332,7 @@ class AdcpAgentsAuthorization2( 'last_updated': '2025-01-10T12:00:00Z', }, { - '$schema': '/schemas/3.1.8/adagents.json', + '$schema': '/schemas/3.1.10/adagents.json', 'contact': { 'name': 'Meta Advertising Operations', 'email': 'adops@meta.com', @@ -1401,7 +1401,7 @@ class AdcpAgentsAuthorization2( 'last_updated': '2025-01-10T15:30:00Z', }, { - '$schema': '/schemas/3.1.8/adagents.json', + '$schema': '/schemas/3.1.10/adagents.json', 'contact': {'name': 'Tumblr Advertising'}, 'properties': [ { @@ -1429,7 +1429,7 @@ class AdcpAgentsAuthorization2( 'last_updated': '2025-01-10T16:00:00Z', }, { - '$schema': '/schemas/3.1.8/adagents.json', + '$schema': '/schemas/3.1.10/adagents.json', 'contact': { 'name': 'Example Third-Party Sales Agent', 'email': 'sales@agent.example', @@ -1486,7 +1486,7 @@ class AdcpAgentsAuthorization2( 'last_updated': '2025-01-10T17:00:00Z', }, { - '$schema': '/schemas/3.1.8/adagents.json', + '$schema': '/schemas/3.1.10/adagents.json', 'contact': { 'name': 'Premium News Publisher', 'email': 'adops@news.example.com', @@ -1544,7 +1544,7 @@ class AdcpAgentsAuthorization2( 'last_updated': '2025-01-10T18:00:00Z', }, { - '$schema': '/schemas/3.1.8/adagents.json', + '$schema': '/schemas/3.1.10/adagents.json', 'contact': { 'name': 'Polk Automotive Data', 'email': 'partnerships@polk.com', @@ -1629,12 +1629,12 @@ class AdcpAgentsAuthorization(RootModel[AdcpAgentsAuthorization1 | AdcpAgentsAut description='Declaration of authorized agents for advertising inventory and data signals. Hosted at /.well-known/adagents.json on publisher domains (for properties) or data provider domains (for signals). Can either contain the full structure inline or reference an authoritative URL.', examples=[ { - '$schema': '/schemas/3.1.8/adagents.json', + '$schema': '/schemas/3.1.10/adagents.json', 'authoritative_location': 'https://cdn.example.com/adagents/v2/adagents.json', 'last_updated': '2025-01-15T10:00:00Z', }, { - '$schema': '/schemas/3.1.8/adagents.json', + '$schema': '/schemas/3.1.10/adagents.json', 'properties': [ { 'property_id': 'example_site', @@ -1691,7 +1691,7 @@ class AdcpAgentsAuthorization(RootModel[AdcpAgentsAuthorization1 | AdcpAgentsAut 'last_updated': '2025-01-10T12:00:00Z', }, { - '$schema': '/schemas/3.1.8/adagents.json', + '$schema': '/schemas/3.1.10/adagents.json', 'contact': { 'name': 'Meta Advertising Operations', 'email': 'adops@meta.com', @@ -1760,7 +1760,7 @@ class AdcpAgentsAuthorization(RootModel[AdcpAgentsAuthorization1 | AdcpAgentsAut 'last_updated': '2025-01-10T15:30:00Z', }, { - '$schema': '/schemas/3.1.8/adagents.json', + '$schema': '/schemas/3.1.10/adagents.json', 'contact': {'name': 'Tumblr Advertising'}, 'properties': [ { @@ -1788,7 +1788,7 @@ class AdcpAgentsAuthorization(RootModel[AdcpAgentsAuthorization1 | AdcpAgentsAut 'last_updated': '2025-01-10T16:00:00Z', }, { - '$schema': '/schemas/3.1.8/adagents.json', + '$schema': '/schemas/3.1.10/adagents.json', 'contact': { 'name': 'Example Third-Party Sales Agent', 'email': 'sales@agent.example', @@ -1845,7 +1845,7 @@ class AdcpAgentsAuthorization(RootModel[AdcpAgentsAuthorization1 | AdcpAgentsAut 'last_updated': '2025-01-10T17:00:00Z', }, { - '$schema': '/schemas/3.1.8/adagents.json', + '$schema': '/schemas/3.1.10/adagents.json', 'contact': { 'name': 'Premium News Publisher', 'email': 'adops@news.example.com', @@ -1903,7 +1903,7 @@ class AdcpAgentsAuthorization(RootModel[AdcpAgentsAuthorization1 | AdcpAgentsAut 'last_updated': '2025-01-10T18:00:00Z', }, { - '$schema': '/schemas/3.1.8/adagents.json', + '$schema': '/schemas/3.1.10/adagents.json', 'contact': { 'name': 'Polk Automotive Data', 'email': 'partnerships@polk.com', diff --git a/src/adcp/types/generated_poc/brand/__init__.py b/src/adcp/types/generated_poc/brand/__init__.py index 9832926b1..ed8a89814 100644 --- a/src/adcp/types/generated_poc/brand/__init__.py +++ b/src/adcp/types/generated_poc/brand/__init__.py @@ -1,6 +1,6 @@ # generated by datamodel-codegen: # filename: brand.json -# timestamp: 2026-07-29T02:07:25+00:00 +# timestamp: 2026-08-04T09:50:23+00:00 from __future__ import annotations @@ -2021,23 +2021,23 @@ class BrandDiscovery( description='Brand identity and discovery file. Hosted at /.well-known/brand.json on house domains. Contains the full brand portfolio with identity, creative assets, and digital properties. Brands are identified by house + brand_id (like properties are identified by publisher + property_id). Supports variants: house portfolio (full brand data), brand agent (agent provides brand info via MCP), house redirect (pointer to house domain), or authoritative location redirect.', examples=[ { - '$schema': '/schemas/3.1.8/brand.json', + '$schema': '/schemas/3.1.10/brand.json', 'authoritative_location': 'https://adcontextprotocol.org/brand/abc123/brand.json', }, { - '$schema': '/schemas/3.1.8/brand.json', + '$schema': '/schemas/3.1.10/brand.json', 'house': 'nikeinc.com', 'note': 'Redirect to house domain for full brand portfolio', }, { - '$schema': '/schemas/3.1.8/brand.json', + '$schema': '/schemas/3.1.10/brand.json', 'version': '1.0', 'agents': [ {'type': 'brand', 'url': 'https://agent.acme.com/mcp', 'id': 'acme_brand'} ], }, { - '$schema': '/schemas/3.1.8/brand.json', + '$schema': '/schemas/3.1.10/brand.json', 'version': '1.0', 'house': { 'domain': 'pg.com', @@ -2273,7 +2273,7 @@ class BrandDiscovery( 'last_updated': '2026-01-15T10:00:00Z', }, { - '$schema': '/schemas/3.1.8/brand.json', + '$schema': '/schemas/3.1.10/brand.json', 'version': '1.0', 'house': { 'domain': 'nikeinc.com', @@ -2377,7 +2377,7 @@ class BrandDiscovery( 'last_updated': '2026-01-15T10:00:00Z', }, { - '$schema': '/schemas/3.1.8/brand.json', + '$schema': '/schemas/3.1.10/brand.json', 'version': '1.0', 'house': { 'domain': 'mediavine.com', @@ -2420,7 +2420,7 @@ class BrandDiscovery( 'last_updated': '2026-01-15T10:00:00Z', }, { - '$schema': '/schemas/3.1.8/brand.json', + '$schema': '/schemas/3.1.10/brand.json', 'version': '1.0', 'house': { 'domain': 'nikeinc.com', @@ -2444,7 +2444,7 @@ class BrandDiscovery( 'last_updated': '2026-01-15T10:00:00Z', }, { - '$schema': '/schemas/3.1.8/brand.json', + '$schema': '/schemas/3.1.10/brand.json', 'version': '1.0', 'house': {'domain': 'wpp.com', 'name': 'WPP plc'}, 'brand_refs': [ @@ -2463,7 +2463,7 @@ class BrandDiscovery( 'last_updated': '2026-01-15T10:00:00Z', }, { - '$schema': '/schemas/3.1.8/brand.json', + '$schema': '/schemas/3.1.10/brand.json', 'version': '1.0', 'id': 'converse', 'names': [{'en_US': 'Converse'}], @@ -2474,7 +2474,7 @@ class BrandDiscovery( 'last_updated': '2026-01-15T10:00:00Z', }, { - '$schema': '/schemas/3.1.8/brand.json', + '$schema': '/schemas/3.1.10/brand.json', 'version': '1.0', 'id': 'patagonia', 'names': [{'en_US': 'Patagonia'}], diff --git a/src/adcp/types/generated_poc/trusted_match/identity_match_response.py b/src/adcp/types/generated_poc/trusted_match/identity_match_response.py index b9d1ba70e..a69ea425a 100644 --- a/src/adcp/types/generated_poc/trusted_match/identity_match_response.py +++ b/src/adcp/types/generated_poc/trusted_match/identity_match_response.py @@ -1,6 +1,6 @@ # generated by datamodel-codegen: # filename: trusted_match/identity_match_response.json -# timestamp: 2026-07-01T04:30:58+00:00 +# timestamp: 2026-08-04T09:50:23+00:00 from __future__ import annotations @@ -9,53 +9,44 @@ from typing import Annotated, Literal from adcp.types.base import AdCPBaseModel -from pydantic import ConfigDict, Field, model_validator +from pydantic import ConfigDict, Field, model_validator, StringConstraints from ..core.protocol_envelope import ProtocolEnvelope from ..core.version_envelope import AdcpVersionEnvelope - _PROVIDER_ID_PATTERN = re.compile(r'^[A-Za-z0-9_]{1,64}$') +from . import tmpx_chunk + class TmpxMacro(AdCPBaseModel): + """Deprecated 3.1.8 TMPX macro/value compatibility model.""" + model_config = ConfigDict( extra='forbid', ) name: Annotated[ str, - Field( - description="Macro name as configured in the publisher's ad server (e.g. `PIN_TMPX_1`). MUST appear in the emitting provider's registered `tmpx_macros` list. Provider-namespaced so the publisher can target distinct slots per provider.", - max_length=64, - min_length=1, - pattern='^[A-Z][A-Z0-9_]*$', - ), - ] - value: Annotated[ - str, - Field( - description='Opaque, URL-safe wire string the publisher substitutes verbatim into the named macro slot. Publishers MUST NOT parse, decode, or transform this value. The protocol fixes the wire format so platforms interoperate; a platform that can carry raw bytes MAY optimize privately but the wire contract remains the URL-safe string.', - max_length=1024, - min_length=1, - ), + Field(max_length=64, min_length=1, pattern='^[A-Z][A-Z0-9_]*$'), ] + value: Annotated[str, Field(max_length=1024, min_length=1)] class TmpxProviders(AdCPBaseModel): model_config = ConfigDict( extra='forbid', ) - macros: Annotated[ - list[TmpxMacro], + chunks: Annotated[ + list[tmpx_chunk.TmpxChunk], Field( - description="Ordered TMPX macro/value pairs for this provider. Names MUST match the provider's registered `tmpx_macros`.", + description="Ordered TMPX chunks for this provider. Each entry is a `{slot_id, value}` pair copied verbatim from the provider's `tmpx_chunks`. Ordered-prefix invariant: the sequence of `slot_id`s MUST equal an ordered prefix of the provider's registered `tmpx_slots` — publishers MAY reject responses whose slot_ids or ordering diverge. Cap of 2 chunks in v1; the cap MAY rise without a shape change.", max_length=2, min_length=1, ), ] -class IdentityMatchResponse(AdcpVersionEnvelope, ProtocolEnvelope): +class IdentityMatchResponseRouterPublisher(AdcpVersionEnvelope, ProtocolEnvelope): model_config = ConfigDict( extra='allow', ) @@ -86,23 +77,15 @@ class IdentityMatchResponse(AdcpVersionEnvelope, ProtocolEnvelope): description='DEPRECATED in favor of tmpx_providers. Routers MAY continue to populate this field for back-compat with consumers that only know the single-token shape; when both fields are present, tmpx_providers is authoritative. Single HPKE-encrypted exposure token containing the resolved user identity tokens. Wire format: kid.base64url_nopad(ciphertext) — unpadded base64url per RFC 4648 section 5 (no = characters). Publishers MUST treat this value as opaque pass-through data. Removed in 4.0.' ), ] = None - tmpx_macros: Annotated[ - list[TmpxMacro] | None, - Field( - description="Provider-emitted: the identity agent's ordered TMPX chunks paired with the macro name each chunk fills. Macro names MUST be drawn from the provider's registered `tmpx_macros` list (provider-registration.json) and appear in the same order — names are part of operational setup, not protocol-synthesized. Capped at 2 chunks in v1; the cap MAY rise without a shape change. Each `value` is an opaque URL-safe wire string the publisher substitutes verbatim into the matching ad-server macro slot — publishers MUST NOT parse, decode, transform, or choose an encoding. The router collects entries from every provider that emits them into `tmpx_providers`, keyed by provider_id; consumers reading the merged response SHOULD consume `tmpx_providers` and ignore `tmpx_macros` at the root.", - max_length=2, - min_length=1, - ), - ] = None tmpx_providers: Annotated[ - dict[str, TmpxProviders] | None, + dict[Annotated[str, StringConstraints(pattern=r'^[A-Za-z0-9_]+$', min_length=1, max_length=64)], TmpxProviders] | None, Field( - description="Router-populated: TMPX macro/value pairs grouped by the originating identity provider's provider_id, so the publisher fires each provider's tokens through that provider's specific ad-server macros (configured per provider in GAM / VAST URL / DOOH play log). Each entry's `macros[]` is a copy of the provider's emitted `tmpx_macros` ordered list. SHAPE CHANGE: was `Map` in the experimental surface that shipped in #5689; now `Map` to carry exact macro/value pairs and support multi-chunk TMPX. Sanctioned by the experimental contract (`x-status: experimental` on this schema). Required by router conformance when any identity provider emitted TMPX in this request; collapsing per-provider tokens into a single string loses attribution and breaks per-provider impression accounting. Map keys MUST be valid provider_ids registered for this fan-out. Publishers MUST traffic only the macro names the response advertises; macro names MUST NOT be derived from provider_id at runtime." + description="Router-populated: ordered TMPX chunk/value pairs grouped by the originating identity provider's `provider_id`. Each entry's `chunks[]` is a copy of the provider's emitted `tmpx_chunks` list, in the same order. Each chunk carries a provider-local `slot_id` (from the provider's registered `tmpx_slots`) and an opaque URL-safe `value`; the publisher's deployment configuration (see publisher-tmpx-config.json) resolves each `(provider_id, slot_id)` pair to the ad-server macro name, targeting key, VAST substitution, or play-log field for that surface. The protocol carries values and attribution only. Required by router conformance when any identity provider emitted TMPX in this request; collapsing per-provider tokens into a single string loses attribution and breaks per-provider impression accounting. Map keys MUST match the provider_id charset registered in provider-registration.json (enforced by `propertyNames`). Publishers MUST NOT parse, decode, or transform any chunk's `value` — each is an opaque URL-safe wire string substituted verbatim into the mapped destination." ), ] = None @model_validator(mode='after') - def _validate_tmpx_provider_ids(self) -> IdentityMatchResponse: + def _validate_tmpx_provider_ids(self) -> IdentityMatchResponseRouterPublisher: if self.tmpx_providers is None: return self invalid = [ @@ -113,3 +96,6 @@ def _validate_tmpx_provider_ids(self) -> IdentityMatchResponse: if invalid: raise ValueError('tmpx_providers keys must be valid provider_id values') return self + + +IdentityMatchResponse = IdentityMatchResponseRouterPublisher diff --git a/src/adcp/types/generated_poc/trusted_match/provider_identity_match_response.py b/src/adcp/types/generated_poc/trusted_match/provider_identity_match_response.py new file mode 100644 index 000000000..206c0f58e --- /dev/null +++ b/src/adcp/types/generated_poc/trusted_match/provider_identity_match_response.py @@ -0,0 +1,50 @@ +# generated by datamodel-codegen: +# filename: trusted_match/provider_identity_match_response.json +# timestamp: 2026-08-04T09:50:23+00:00 + +from __future__ import annotations + +from typing import Annotated, Literal + +from pydantic import ConfigDict, Field + +from ..core.protocol_envelope import ProtocolEnvelope +from ..core.version_envelope import AdcpVersionEnvelope +from . import tmpx_chunk + + +class IdentityMatchResponseProviderRouter(AdcpVersionEnvelope, ProtocolEnvelope): + model_config = ConfigDict( + extra='allow', + ) + type: Annotated[ + Literal['identity_match_response'], + Field( + description='Message type discriminator for deserialization. Same const as the router→publisher variant so publisher-facing decoders can key off type before dispatching on shape.' + ), + ] = 'identity_match_response' + request_id: Annotated[ + str, Field(description='Echoed request identifier from the identity match request.') + ] + eligible_package_ids: Annotated[ + list[str], + Field( + description='Package IDs the user is eligible for. Packages not listed are ineligible.' + ), + ] + serve_window_sec: Annotated[ + int, + Field( + description="Per-package single-shot fcap window, in seconds. After serving the user one impression on each eligible package within this window, the publisher MUST re-query Identity Match before serving from those packages again. Not a router response cache TTL — it is a buyer-asserted serve throttle. Multi-impression frequency caps are handled separately by the buyer's impression tracker. Maximum 300.", + ge=1, + le=300, + ), + ] + tmpx_chunks: Annotated[ + list[tmpx_chunk.TmpxChunk] | None, + Field( + description="Ordered TMPX chunk/value pairs this identity agent mints. Each entry names the provider-local `slot_id` the value fills (from the provider's registered `tmpx_slots` in provider-registration.json). Ordered-prefix invariant: a response that carries fewer chunks than the provider registered MUST emit an ordered prefix of the registered `tmpx_slots` — routers MUST NOT reorder or fill gaps. The router MUST validate this contract before forwarding: if the provider has no `tmpx_slots` registration, or if the chunk `slot_id` sequence is not an exact non-empty ordered prefix of the registered list (duplicate, reordered, sparse, or unregistered slot IDs), the router MUST drop that provider's chunks atomically and MUST NOT forward them into `tmpx_providers`. Cap of 2 chunks in v1 aligned with the GAM macro-slot budget; the cap MAY rise without a shape change. Omitted when this provider mints no TMPX (e.g. no eligible packages).", + max_length=2, + min_length=1, + ), + ] = None diff --git a/src/adcp/types/generated_poc/trusted_match/provider_registration.py b/src/adcp/types/generated_poc/trusted_match/provider_registration.py index f8a88edff..1828f837e 100644 --- a/src/adcp/types/generated_poc/trusted_match/provider_registration.py +++ b/src/adcp/types/generated_poc/trusted_match/provider_registration.py @@ -1,6 +1,6 @@ # generated by datamodel-codegen: # filename: trusted_match/provider_registration.json -# timestamp: 2026-07-01T04:30:58+00:00 +# timestamp: 2026-08-04T09:50:23+00:00 from __future__ import annotations @@ -18,10 +18,17 @@ class Country(RootModel[str]): root: Annotated[str, Field(pattern='^[A-Z]{2}$')] + class TmpxMacro(RootModel[str]): + """Deprecated 3.1.8 registered macro-name compatibility model.""" + root: Annotated[str, Field(max_length=64, min_length=1, pattern='^[A-Z][A-Z0-9_]*$')] +class TmpxSlot(RootModel[str]): + root: Annotated[str, Field(max_length=64, min_length=1, pattern='^[a-zA-Z][a-zA-Z0-9_]*$')] + + class Status(StrEnum): active = 'active' inactive = 'inactive' @@ -35,7 +42,7 @@ class TmpProviderRegistration1(AdCPBaseModel): provider_id: Annotated[ str, Field( - description="Stable identifier for this provider registration. Used in logs, metrics, cache keys, and as the key in `tmpx_providers` on the identity-match response so the publisher can route each provider's TMPX `macros[]` to that provider's pre-configured ad-server slots (names registered in `tmpx_macros` below — macro names MUST NOT be derived from `provider_id` at runtime). Publishers assign this — it is not the provider's agent_url. Charset is constrained to a safe alphanumeric/underscore set so the value can appear in operational surfaces (logs, metrics, dashboards) without quoting.", + description="Stable identifier for this provider registration. Used in logs, metrics, cache keys, and as the key in `tmpx_providers` on the identity-match response so the publisher can route each provider's TMPX chunks to that provider's pre-configured ad-server destinations via the publisher's `tmpx_macro_mapping` deployment configuration (see publisher-tmpx-config.json). Publishers assign this — it is not the provider's agent_url. Charset is constrained to a safe alphanumeric/underscore set so the value can appear in operational surfaces (logs, metrics, dashboards) without quoting.", max_length=64, min_length=1, pattern='^[A-Za-z0-9_]+$', @@ -89,10 +96,10 @@ class TmpProviderRegistration1(AdCPBaseModel): ge=0, ), ] = 0 - tmpx_macros: Annotated[ - list[TmpxMacro] | None, + tmpx_slots: Annotated[ + list[TmpxSlot] | None, Field( - description='Stable, provider-namespaced ad-server macro names this provider\'s TMPX response fills, ordered. Publishers traffic these exact names in their ad server (GAM key-values, VAST URL macros, DOOH play-log fields); the router places each provider\'s TMPX chunks into the matching slots on the identity-match response (`tmpx_providers[provider_id].macros[]`). Names MUST be provider-namespaced so publishers can configure distinct macros per provider (e.g. `PIN_TMPX_1`, `PIN_TMPX_2` for one provider; `NOVA_TMPX_1` for another). Ordered so multi-chunk TMPX values (when the opaque token exceeds one macro slot) are placed deterministically. Capped at 2 entries in v1; the cap MAY be raised in a later version without a shape change. A provider that emits TMPX on its identity-match response (populates `tmpx_macros[]` there) MUST also register this list — otherwise the router has no slot names to forward — but the schema cannot enforce this because "emits TMPX" is not a schema-visible predicate. Providers that do not emit TMPX omit this field.', + description='Stable provider-local slot identifiers for the ordered TMPX chunks this provider mints. Slot IDs are opaque provider-namespaced tokens (e.g. `["primary","secondary"]`), NOT ad-server macro names — publishers map `(provider_id, slot_id)` → local destination via `tmpx_macro_mapping` in publisher-tmpx-config.json, so the destination namespace stays publisher-owned and the router never accepts a destination name from an untrusted provider. Distinct providers MAY reuse the same slot_id without collision because publisher lookup is keyed on `(provider_id, slot_id)`. Publishers use this list at startup to validate `tmpx_macro_mapping` covers every slot the provider mints and to detect config drift when the provider\'s slot contract changes. Ordering carries the ordered-prefix invariant: a provider that emits fewer chunks than it registered MUST emit an ordered prefix of this list — chunks map to slots in registration order and MUST NOT be shifted, sparse, or reordered. Cap of 2 slots in v1 aligned with the GAM macro-slot budget; the cap MAY rise without a shape change. A provider that emits TMPX (populates `tmpx_chunks` on its identity-match response) MUST register this list; a provider that does not emit TMPX omits it. Schema cannot enforce that predicate because "emits TMPX" is not schema-visible.', max_length=2, min_length=1, ), @@ -129,7 +136,7 @@ class TmpProviderRegistration2(AdCPBaseModel): provider_id: Annotated[ str, Field( - description="Stable identifier for this provider registration. Used in logs, metrics, cache keys, and as the key in `tmpx_providers` on the identity-match response so the publisher can route each provider's TMPX `macros[]` to that provider's pre-configured ad-server slots (names registered in `tmpx_macros` below — macro names MUST NOT be derived from `provider_id` at runtime). Publishers assign this — it is not the provider's agent_url. Charset is constrained to a safe alphanumeric/underscore set so the value can appear in operational surfaces (logs, metrics, dashboards) without quoting.", + description="Stable identifier for this provider registration. Used in logs, metrics, cache keys, and as the key in `tmpx_providers` on the identity-match response so the publisher can route each provider's TMPX chunks to that provider's pre-configured ad-server destinations via the publisher's `tmpx_macro_mapping` deployment configuration (see publisher-tmpx-config.json). Publishers assign this — it is not the provider's agent_url. Charset is constrained to a safe alphanumeric/underscore set so the value can appear in operational surfaces (logs, metrics, dashboards) without quoting.", max_length=64, min_length=1, pattern='^[A-Za-z0-9_]+$', @@ -184,10 +191,10 @@ class TmpProviderRegistration2(AdCPBaseModel): ge=0, ), ] = 0 - tmpx_macros: Annotated[ - list[TmpxMacro] | None, + tmpx_slots: Annotated[ + list[TmpxSlot] | None, Field( - description='Stable, provider-namespaced ad-server macro names this provider\'s TMPX response fills, ordered. Publishers traffic these exact names in their ad server (GAM key-values, VAST URL macros, DOOH play-log fields); the router places each provider\'s TMPX chunks into the matching slots on the identity-match response (`tmpx_providers[provider_id].macros[]`). Names MUST be provider-namespaced so publishers can configure distinct macros per provider (e.g. `PIN_TMPX_1`, `PIN_TMPX_2` for one provider; `NOVA_TMPX_1` for another). Ordered so multi-chunk TMPX values (when the opaque token exceeds one macro slot) are placed deterministically. Capped at 2 entries in v1; the cap MAY be raised in a later version without a shape change. A provider that emits TMPX on its identity-match response (populates `tmpx_macros[]` there) MUST also register this list — otherwise the router has no slot names to forward — but the schema cannot enforce this because "emits TMPX" is not a schema-visible predicate. Providers that do not emit TMPX omit this field.', + description='Stable provider-local slot identifiers for the ordered TMPX chunks this provider mints. Slot IDs are opaque provider-namespaced tokens (e.g. `["primary","secondary"]`), NOT ad-server macro names — publishers map `(provider_id, slot_id)` → local destination via `tmpx_macro_mapping` in publisher-tmpx-config.json, so the destination namespace stays publisher-owned and the router never accepts a destination name from an untrusted provider. Distinct providers MAY reuse the same slot_id without collision because publisher lookup is keyed on `(provider_id, slot_id)`. Publishers use this list at startup to validate `tmpx_macro_mapping` covers every slot the provider mints and to detect config drift when the provider\'s slot contract changes. Ordering carries the ordered-prefix invariant: a provider that emits fewer chunks than it registered MUST emit an ordered prefix of this list — chunks map to slots in registration order and MUST NOT be shifted, sparse, or reordered. Cap of 2 slots in v1 aligned with the GAM macro-slot budget; the cap MAY rise without a shape change. A provider that emits TMPX (populates `tmpx_chunks` on its identity-match response) MUST register this list; a provider that does not emit TMPX omits it. Schema cannot enforce that predicate because "emits TMPX" is not schema-visible.', max_length=2, min_length=1, ), diff --git a/src/adcp/types/generated_poc/trusted_match/publisher_tmpx_config.py b/src/adcp/types/generated_poc/trusted_match/publisher_tmpx_config.py new file mode 100644 index 000000000..5b1c0f5fd --- /dev/null +++ b/src/adcp/types/generated_poc/trusted_match/publisher_tmpx_config.py @@ -0,0 +1,25 @@ +# generated by datamodel-codegen: +# filename: trusted_match/publisher_tmpx_config.json +# timestamp: 2026-08-04T09:50:23+00:00 + +from __future__ import annotations + +from typing import Annotated + +from adcp.types.base import AdCPBaseModel +from pydantic import ConfigDict, Field, StringConstraints + + +class PublisherTmpxMacroMapping(AdCPBaseModel): + model_config = ConfigDict( + extra='forbid', + ) + tmpx_macro_mapping: Annotated[ + dict[ + Annotated[str, StringConstraints(pattern=r'^[A-Za-z0-9_]+$', min_length=1, max_length=64)], + dict[Annotated[str, StringConstraints(pattern=r'^[a-zA-Z][a-zA-Z0-9_]*$', min_length=1, max_length=64)], str], + ], + Field( + description="Map from `provider_id` to a slot-keyed map of ad-server destinations (macro names, GAM key-values, VAST URL macro tokens, DOOH play-log field identifiers) for that provider on this surface. The inner map's keys are the provider-local `slot_id` values the provider registered in `tmpx_slots` (see provider-registration.json). At serve time, the publisher's adapter reads `tmpx_providers[provider_id].chunks[]` from the identity-match response and, for each chunk, substitutes the chunk's `value` into `tmpx_macro_mapping[provider_id][chunk.slot_id]`. Publishers use the outer map's keys plus the inner map's keys to validate the mapping at startup — every `slot_id` a provider registered in `tmpx_slots` SHOULD have a corresponding entry in that provider's inner map, and publishers SHOULD surface any missing entry as a startup warning so the operator can add it before responses begin carrying the unmapped slot. The exact destination string is publisher-local: GAM adopters typically use uppercase snake-case macro names, VAST surfaces use URL macro tokens, DOOH surfaces use play-log field identifiers. Outer-map key charset matches `provider_id` in provider-registration.json (enforced by `propertyNames`). Inner-map key charset matches `slot_id` in tmpx-chunk.json. When a response carries a `slot_id` for a provider that this mapping has no entry for — the mapping is missing the whole provider, OR the provider is present but the specific `slot_id` is unknown to this surface — the publisher's adapter MUST fail closed for that provider on that impression: none of that provider's chunks are fired into the ad-serving path and the adapter logs a configuration error. Other providers on the same response are unaffected. A `provider_id` absent from this mapping entirely (e.g. a newly onboarded provider not yet trafficked on this surface) is the same case — the adapter drops that provider's chunks on this surface rather than firing them into an unconfigured destination. Startup validation and serve-time fail-closed are two stages of a single rule: the warning at startup is the operator's chance to fix the mapping before the serve-time rule catches the missing slot." + ), + ] diff --git a/src/adcp/types/generated_poc/trusted_match/tmpx_chunk.py b/src/adcp/types/generated_poc/trusted_match/tmpx_chunk.py new file mode 100644 index 000000000..56433e437 --- /dev/null +++ b/src/adcp/types/generated_poc/trusted_match/tmpx_chunk.py @@ -0,0 +1,33 @@ +# generated by datamodel-codegen: +# filename: trusted_match/tmpx_chunk.json +# timestamp: 2026-08-04T09:50:23+00:00 + +from __future__ import annotations + +from typing import Annotated + +from adcp.types.base import AdCPBaseModel +from pydantic import ConfigDict, Field + + +class TmpxChunk(AdCPBaseModel): + model_config = ConfigDict( + extra='forbid', + ) + slot_id: Annotated[ + str, + Field( + description="Provider-local slot identifier from the emitting provider's registered `tmpx_slots` (provider-registration.json). Opaque provider-namespaced token; publishers map `(provider_id, slot_id)` → local destination via `tmpx_macro_mapping`. NOT an ad-server macro name.", + max_length=64, + min_length=1, + pattern='^[a-zA-Z][a-zA-Z0-9_]*$', + ), + ] + value: Annotated[ + str, + Field( + description="Opaque, URL-safe wire string the publisher substitutes verbatim into the destination the publisher's mapping resolves for this `(provider_id, slot_id)` pair. Publishers MUST NOT parse, decode, or transform this value.", + max_length=1024, + min_length=1, + ), + ] diff --git a/tests/conformance/signing/vector_manifest.json b/tests/conformance/signing/vector_manifest.json index ade79781c..adc405152 100644 --- a/tests/conformance/signing/vector_manifest.json +++ b/tests/conformance/signing/vector_manifest.json @@ -1,7 +1,7 @@ { "$comment": "Completeness pin for the vendored AdCP request-signing conformance vectors. Generated by `python -m tests.conformance.signing.vectors --write`; do not hand-edit. Graded by tests/conformance/signing/test_vector_completeness.py.", - "spec_version": "3.1.8", - "source": "adcontextprotocol/adcp @ v3.1.8 -- dist/compliance/3.1.8/test-vectors/request-signing/", + "spec_version": "3.1.10", + "source": "adcontextprotocol/adcp @ v3.1.10 -- compliance/test-vectors/request-signing/", "files": { "README.md": "74977dcb44eef69aee2b45e78e9fc111625e101d7e8646ed9f44b521aee396e8", "canonicalization.json": "83a15584bebb0ff006ffd99a4080f5a922ea56e9e590d516ee87becaaf15ad1b", diff --git a/tests/test_canonical_formats_registry.py b/tests/test_canonical_formats_registry.py index 232075ad7..99b6c0d4d 100644 --- a/tests/test_canonical_formats_registry.py +++ b/tests/test_canonical_formats_registry.py @@ -63,16 +63,16 @@ def _structural_pattern( raise AssertionError(f"No structural mapping found for canonical={canonical!r}") -def test_registry_has_literal_entries_plus_seven_structural_fallbacks() -> None: - """3.1.8 ships literal mappings plus 7 structural fallback entries. +def test_registry_has_retina_literals_plus_seven_structural_fallbacks() -> None: + """3.1.10 ships Retina literals plus 7 structural fallback entries. A change to these counts is a vocabulary-governance event.""" registry = load_default_registry() structural = [m for m in registry.mappings if hasattr(m.v1_pattern, "structural")] literal = [m for m in registry.mappings if hasattr(m.v1_pattern, "format_id_glob")] - assert registry.version == "1.2.0" - assert len(registry.mappings) == 29 - assert len(literal) == 22 + assert registry.version == "1.3.0" + assert len(registry.mappings) == 43 + assert len(literal) == 36 assert len(structural) == 7 diff --git a/tests/test_canonical_formats_v1_to_v2.py b/tests/test_canonical_formats_v1_to_v2.py index 467b4aa8e..ec3426d39 100644 --- a/tests/test_canonical_formats_v1_to_v2.py +++ b/tests/test_canonical_formats_v1_to_v2.py @@ -80,6 +80,59 @@ def test_slots_override_threads_into_params() -> None: assert slots[0]["asset_group_id"] == "image_main" +def test_seller_slots_override_registry_retina_slot_contract() -> None: + v1 = { + "format_id": { + "agent_url": "https://creative.adcontextprotocol.org", + "id": "display_300x250_image_1x_2x", + }, + "canonical": { + "kind": "image", + "slots_override": [ + { + "asset_group_id": "seller_image", + "asset_type": "image", + "required": True, + } + ], + }, + } + + result = project_v1_format_to_declaration(v1) + + assert result.declaration is not None + assert result.declaration.params == { + "width": 300, + "height": 250, + "slots": [ + { + "asset_group_id": "seller_image", + "asset_type": "image", + "required": True, + "consumed_for_production": True, + } + ], + } + assert result.advisories == [] + + +def test_seller_kind_does_not_inherit_registry_retina_contract() -> None: + v1 = { + "format_id": { + "agent_url": "https://creative.adcontextprotocol.org", + "id": "display_300x250_image_1x_2x", + }, + "canonical": {"kind": "html5"}, + } + + result = project_v1_format_to_declaration(v1) + + assert result.declaration is not None + assert result.declaration.format_kind is CanonicalFormatKind.html5 + assert result.declaration.params == {"width": 300, "height": 250} + assert result.advisories == [] + + # --------------------------------------------------------------------------- # Step 2 — registry glob match (no explicit canonical) # --------------------------------------------------------------------------- @@ -119,6 +172,74 @@ def test_registry_literal_mappings_project_canonical_params( assert result.advisories == [] +RETINA_DISPLAY_SIZES = [ + ("300x250", 300, 250), + ("728x90", 728, 90), + ("320x50", 320, 50), + ("160x600", 160, 600), + ("336x280", 336, 280), + ("300x600", 300, 600), + ("970x250", 970, 250), +] + + +@pytest.mark.parametrize(("size", "width", "height"), RETINA_DISPLAY_SIZES) +def test_retina_only_registry_mappings_preserve_pixel_ratio( + size: str, width: int, height: int +) -> None: + result = project_v1_format_to_declaration( + { + "format_id": { + "agent_url": "https://creative.adcontextprotocol.org", + "id": f"display_{size}_image_2x", + } + } + ) + + assert result.declaration is not None + assert result.declaration.format_kind is CanonicalFormatKind.image + assert result.declaration.params == { + "width": width, + "height": height, + "pixel_ratios": [2], + } + assert result.advisories == [] + + +@pytest.mark.parametrize(("size", "width", "height"), RETINA_DISPLAY_SIZES) +def test_retina_rendition_set_registry_mapping_preserves_slot_contract( + size: str, width: int, height: int +) -> None: + result = project_v1_format_to_declaration( + { + "format_id": { + "agent_url": "https://creative.adcontextprotocol.org", + "id": f"display_{size}_image_1x_2x", + } + } + ) + + assert result.declaration is not None + assert result.declaration.format_kind is CanonicalFormatKind.image + assert result.declaration.params == { + "width": width, + "height": height, + "pixel_ratios": [1, 2], + "slots": [ + { + "asset_group_id": "image_main", + "asset_type": "image", + "required": True, + "min": 2, + "max": 2, + "pixel_ratios": [1, 2], + "required_pixel_ratios": [1, 2], + } + ], + } + assert result.advisories == [] + + # --------------------------------------------------------------------------- # Step 3 — registry structural match (no explicit canonical) # --------------------------------------------------------------------------- diff --git a/tests/test_trusted_match_validation.py b/tests/test_trusted_match_validation.py index 2c59f3487..a9cf39044 100644 --- a/tests/test_trusted_match_validation.py +++ b/tests/test_trusted_match_validation.py @@ -4,9 +4,15 @@ from adcp.types.generated_poc.trusted_match.identity_match_response import ( IdentityMatchResponse, ) +from adcp.types.generated_poc.trusted_match.provider_identity_match_response import ( + IdentityMatchResponseProviderRouter, +) from adcp.types.generated_poc.trusted_match.provider_registration import ( TmpProviderRegistration, ) +from adcp.types.generated_poc.trusted_match.publisher_tmpx_config import ( + PublisherTmpxMacroMapping, +) def test_provider_registration_requires_identity_dimensions_when_identity_match_enabled(): @@ -46,14 +52,14 @@ def test_provider_registration_accepts_valid_identity_registration(): def test_identity_match_response_rejects_invalid_tmpx_provider_ids(): - with pytest.raises(ValidationError, match="tmpx_providers keys"): + with pytest.raises(ValidationError, match="String should match pattern"): IdentityMatchResponse.model_validate( { "request_id": "request_1", "eligible_package_ids": [], "serve_window_sec": 60, "tmpx_providers": { - "bad provider!": {"macros": [{"name": "PIN_TMPX_1", "value": "abc"}]} + "bad provider!": {"chunks": [{"slot_id": "primary", "value": "abc"}]} }, } ) @@ -65,9 +71,40 @@ def test_identity_match_response_accepts_valid_tmpx_provider_ids(): "request_id": "request_1", "eligible_package_ids": [], "serve_window_sec": 60, - "tmpx_providers": {"provider_1": {"macros": [{"name": "PIN_TMPX_1", "value": "abc"}]}}, + "tmpx_providers": {"provider_1": {"chunks": [{"slot_id": "primary", "value": "abc"}]}}, } ) assert response.tmpx_providers is not None assert "provider_1" in response.tmpx_providers + + +def test_provider_identity_match_response_accepts_tmpx_chunks(): + response = IdentityMatchResponseProviderRouter.model_validate( + { + "request_id": "request_1", + "eligible_package_ids": [], + "serve_window_sec": 60, + "tmpx_chunks": [{"slot_id": "primary", "value": "abc"}], + } + ) + + assert response.tmpx_chunks is not None + assert response.tmpx_chunks[0].slot_id == "primary" + + +def test_publisher_tmpx_mapping_validates_provider_and_slot_keys(): + mapping = PublisherTmpxMacroMapping.model_validate( + {"tmpx_macro_mapping": {"provider_1": {"primary": "PIN_TMPX_1"}}} + ) + assert mapping.tmpx_macro_mapping["provider_1"]["primary"] == "PIN_TMPX_1" + + with pytest.raises(ValidationError, match="String should match pattern"): + PublisherTmpxMacroMapping.model_validate( + {"tmpx_macro_mapping": {"bad provider!": {"primary": "PIN_TMPX_1"}}} + ) + + with pytest.raises(ValidationError, match="String should match pattern"): + PublisherTmpxMacroMapping.model_validate( + {"tmpx_macro_mapping": {"provider_1": {"bad slot!": "PIN_TMPX_1"}}} + )