Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 9 additions & 0 deletions .changeset/fix-format-assets-oneof-discriminator.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
---
"adcontextprotocol": patch
---

Restructure `core/format.json` `assets[].items` from a flat 16-variant `oneOf` to a two-tier discriminated union: outer discriminator on `item_type` (`individual` | `repeatable_group`), inner discriminator on `asset_type` across the 15 individual asset variants. Wire payload set is unchanged; Ajv `discriminator` mode (requires `{ discriminator: true }` initialization) now routes correctly without scanning all variants.

**Codegen note:** Consumers auto-generating SDK types (quicktype, ts-json-schema-generator, etc.) will see a new intermediate `IndividualAsset` wrapper type on regeneration. The wire contract is unchanged; regenerate and verify call sites.

**Discriminator semantics:** The `discriminator` keyword is an OAS 3.x / Ajv extension and is advisory for standard JSON Schema draft-07 validators. Standard validators continue to use full `oneOf` evaluation; only validators initialized with discriminator support benefit from the routing optimization.
5 changes: 0 additions & 5 deletions scripts/oneof-discriminators.baseline.json
Original file line number Diff line number Diff line change
Expand Up @@ -191,11 +191,6 @@
"variants": 3,
"note": "0:[exemplars] | 1:[evaluator_id] | 2:[agent_url]"
},
"core/format.json##/properties/assets/items/oneOf": {
"kind": "dangerous",
"variants": 16,
"note": "shared-required=[∅]; 0:req=[∅] | 1:req=[∅] | 2:req=[∅] | 3:req=[∅] | 4:req=[∅] | 5:req=[∅] | 6:req=[∅] | 7:req=[∅] | 8:req=[∅] | 9:req=[∅] | 10:req=[∅] | 11:req=[∅] | 12:req=[∅] | 13:req=[∅] | 14:req=[∅] | 15:req=[item_type,asset_group_id,required,min_count,max_count,assets]"
},
"core/format.json##/properties/renders/items/oneOf": {
"kind": "narrowable",
"variants": 2,
Expand Down
2 changes: 1 addition & 1 deletion server/src/billing/stripe-client.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2027,7 +2027,7 @@ function parseStripeInvoice(
}

const dueDate = invoice.due_date ? new Date(invoice.due_date * 1000) : null;
const status = (invoice.status === 'draft' || invoice.status === 'open') ? invoice.status : 'open';
const status: 'draft' | 'open' = (invoice.status === 'draft' || invoice.status === 'open') ? invoice.status as 'draft' | 'open' : 'open';
return {
id: invoice.id,
status,
Expand Down
318 changes: 173 additions & 145 deletions static/schemas/source/core/format.json
Original file line number Diff line number Diff line change
Expand Up @@ -205,154 +205,182 @@
"type": "array",
"description": "Array of all assets supported for this format. Each asset is identified by its asset_id, which must be used as the key in creative manifests. Use the 'required' boolean on each asset to indicate whether it's mandatory.",
"items": {
"discriminator": { "propertyName": "item_type" },
"oneOf": [
{
"title": "IndividualImageAsset",
"description": "Image asset",
"allOf": [{ "$ref": "#/$defs/baseIndividualAsset" }],
"properties": {
"item_type": { "const": "individual" },
"asset_type": { "const": "image" },
"requirements": { "$ref": "/schemas/core/requirements/image-asset-requirements.json" }
}
},
{
"title": "IndividualVideoAsset",
"description": "Video asset",
"allOf": [{ "$ref": "#/$defs/baseIndividualAsset" }],
"properties": {
"item_type": { "const": "individual" },
"asset_type": { "const": "video" },
"requirements": { "$ref": "/schemas/core/requirements/video-asset-requirements.json" }
}
},
{
"title": "IndividualAudioAsset",
"description": "Audio asset",
"allOf": [{ "$ref": "#/$defs/baseIndividualAsset" }],
"properties": {
"item_type": { "const": "individual" },
"asset_type": { "const": "audio" },
"requirements": { "$ref": "/schemas/core/requirements/audio-asset-requirements.json" }
}
},
{
"title": "IndividualTextAsset",
"description": "Text asset",
"allOf": [{ "$ref": "#/$defs/baseIndividualAsset" }],
"properties": {
"item_type": { "const": "individual" },
"asset_type": { "const": "text" },
"requirements": { "$ref": "/schemas/core/requirements/text-asset-requirements.json" }
}
},
{
"title": "IndividualMarkdownAsset",
"description": "Markdown asset",
"allOf": [{ "$ref": "#/$defs/baseIndividualAsset" }],
"properties": {
"item_type": { "const": "individual" },
"asset_type": { "const": "markdown" },
"requirements": { "$ref": "/schemas/core/requirements/markdown-asset-requirements.json" }
}
},
{
"title": "IndividualHtmlAsset",
"description": "HTML asset",
"allOf": [{ "$ref": "#/$defs/baseIndividualAsset" }],
"properties": {
"item_type": { "const": "individual" },
"asset_type": { "const": "html" },
"requirements": { "$ref": "/schemas/core/requirements/html-asset-requirements.json" }
}
},
{
"title": "IndividualCssAsset",
"description": "CSS asset",
"allOf": [{ "$ref": "#/$defs/baseIndividualAsset" }],
"properties": {
"item_type": { "const": "individual" },
"asset_type": { "const": "css" },
"requirements": { "$ref": "/schemas/core/requirements/css-asset-requirements.json" }
}
},
{
"title": "IndividualJavaScriptAsset",
"description": "JavaScript asset",
"allOf": [{ "$ref": "#/$defs/baseIndividualAsset" }],
"properties": {
"item_type": { "const": "individual" },
"asset_type": { "const": "javascript" },
"requirements": { "$ref": "/schemas/core/requirements/javascript-asset-requirements.json" }
}
},
{
"title": "IndividualZipAsset",
"description": "Zip-bundled asset (HTML5 banner bundles, etc.)",
"allOf": [{ "$ref": "#/$defs/baseIndividualAsset" }],
"properties": {
"item_type": { "const": "individual" },
"asset_type": { "const": "zip" }
}
},
{
"title": "IndividualVastAsset",
"description": "VAST asset",
"allOf": [{ "$ref": "#/$defs/baseIndividualAsset" }],
"properties": {
"item_type": { "const": "individual" },
"asset_type": { "const": "vast" },
"requirements": { "$ref": "/schemas/core/requirements/vast-asset-requirements.json" }
}
},
{
"title": "IndividualDaastAsset",
"description": "DAAST asset",
"allOf": [{ "$ref": "#/$defs/baseIndividualAsset" }],
"properties": {
"item_type": { "const": "individual" },
"asset_type": { "const": "daast" },
"requirements": { "$ref": "/schemas/core/requirements/daast-asset-requirements.json" }
}
},
{
"title": "IndividualUrlAsset",
"description": "URL asset",
"allOf": [{ "$ref": "#/$defs/baseIndividualAsset" }],
"properties": {
"item_type": { "const": "individual" },
"asset_type": { "const": "url" },
"requirements": { "$ref": "/schemas/core/requirements/url-asset-requirements.json" }
}
},
{
"title": "IndividualWebhookAsset",
"description": "Webhook asset",
"allOf": [{ "$ref": "#/$defs/baseIndividualAsset" }],
"properties": {
"item_type": { "const": "individual" },
"asset_type": { "const": "webhook" },
"requirements": { "$ref": "/schemas/core/requirements/webhook-asset-requirements.json" }
}
},
{
"title": "IndividualBriefAsset",
"description": "Brief asset",
"allOf": [{ "$ref": "#/$defs/baseIndividualAsset" }],
"properties": {
"item_type": { "const": "individual" },
"asset_type": { "const": "brief" }
}
},
{
"title": "IndividualCatalogAsset",
"description": "Catalog asset",
"allOf": [{ "$ref": "#/$defs/baseIndividualAsset" }],
"title": "IndividualAsset",
"description": "Individual asset — discriminated further by asset_type",
"type": "object",
"properties": {
"item_type": { "const": "individual" },
"asset_type": { "const": "catalog" },
"requirements": { "$ref": "/schemas/core/requirements/catalog-requirements.json" }
}
"item_type": { "type": "string", "const": "individual", "description": "Discriminator indicating this is an individual asset" }
},
"required": ["item_type", "asset_type"],
"discriminator": { "propertyName": "asset_type" },
"oneOf": [
{
"title": "IndividualImageAsset",
"description": "Image asset",
"allOf": [{ "$ref": "#/$defs/baseIndividualAsset" }],
"properties": {
"item_type": { "type": "string", "const": "individual" },
"asset_type": { "type": "string", "const": "image" },
"requirements": { "$ref": "/schemas/core/requirements/image-asset-requirements.json" }
},
"required": ["asset_type"]
},
{
"title": "IndividualVideoAsset",
"description": "Video asset",
"allOf": [{ "$ref": "#/$defs/baseIndividualAsset" }],
"properties": {
"item_type": { "type": "string", "const": "individual" },
"asset_type": { "type": "string", "const": "video" },
"requirements": { "$ref": "/schemas/core/requirements/video-asset-requirements.json" }
},
"required": ["asset_type"]
},
{
"title": "IndividualAudioAsset",
"description": "Audio asset",
"allOf": [{ "$ref": "#/$defs/baseIndividualAsset" }],
"properties": {
"item_type": { "type": "string", "const": "individual" },
"asset_type": { "type": "string", "const": "audio" },
"requirements": { "$ref": "/schemas/core/requirements/audio-asset-requirements.json" }
},
"required": ["asset_type"]
},
{
"title": "IndividualTextAsset",
"description": "Text asset",
"allOf": [{ "$ref": "#/$defs/baseIndividualAsset" }],
"properties": {
"item_type": { "type": "string", "const": "individual" },
"asset_type": { "type": "string", "const": "text" },
"requirements": { "$ref": "/schemas/core/requirements/text-asset-requirements.json" }
},
"required": ["asset_type"]
},
{
"title": "IndividualMarkdownAsset",
"description": "Markdown asset",
"allOf": [{ "$ref": "#/$defs/baseIndividualAsset" }],
"properties": {
"item_type": { "type": "string", "const": "individual" },
"asset_type": { "type": "string", "const": "markdown" },
"requirements": { "$ref": "/schemas/core/requirements/markdown-asset-requirements.json" }
},
"required": ["asset_type"]
},
{
"title": "IndividualHtmlAsset",
"description": "HTML asset",
"allOf": [{ "$ref": "#/$defs/baseIndividualAsset" }],
"properties": {
"item_type": { "type": "string", "const": "individual" },
"asset_type": { "type": "string", "const": "html" },
"requirements": { "$ref": "/schemas/core/requirements/html-asset-requirements.json" }
},
"required": ["asset_type"]
},
{
"title": "IndividualCssAsset",
"description": "CSS asset",
"allOf": [{ "$ref": "#/$defs/baseIndividualAsset" }],
"properties": {
"item_type": { "type": "string", "const": "individual" },
"asset_type": { "type": "string", "const": "css" },
"requirements": { "$ref": "/schemas/core/requirements/css-asset-requirements.json" }
},
"required": ["asset_type"]
},
{
"title": "IndividualJavaScriptAsset",
"description": "JavaScript asset",
"allOf": [{ "$ref": "#/$defs/baseIndividualAsset" }],
"properties": {
"item_type": { "type": "string", "const": "individual" },
"asset_type": { "type": "string", "const": "javascript" },
"requirements": { "$ref": "/schemas/core/requirements/javascript-asset-requirements.json" }
},
"required": ["asset_type"]
},
{
"title": "IndividualZipAsset",
"description": "Zip-bundled asset (HTML5 banner bundles, etc.)",
"allOf": [{ "$ref": "#/$defs/baseIndividualAsset" }],
"properties": {
"item_type": { "type": "string", "const": "individual" },
"asset_type": { "type": "string", "const": "zip" }
},
"required": ["asset_type"]
},
{
"title": "IndividualVastAsset",
"description": "VAST asset",
"allOf": [{ "$ref": "#/$defs/baseIndividualAsset" }],
"properties": {
"item_type": { "type": "string", "const": "individual" },
"asset_type": { "type": "string", "const": "vast" },
"requirements": { "$ref": "/schemas/core/requirements/vast-asset-requirements.json" }
},
"required": ["asset_type"]
},
{
"title": "IndividualDaastAsset",
"description": "DAAST asset",
"allOf": [{ "$ref": "#/$defs/baseIndividualAsset" }],
"properties": {
"item_type": { "type": "string", "const": "individual" },
"asset_type": { "type": "string", "const": "daast" },
"requirements": { "$ref": "/schemas/core/requirements/daast-asset-requirements.json" }
},
"required": ["asset_type"]
},
{
"title": "IndividualUrlAsset",
"description": "URL asset",
"allOf": [{ "$ref": "#/$defs/baseIndividualAsset" }],
"properties": {
"item_type": { "type": "string", "const": "individual" },
"asset_type": { "type": "string", "const": "url" },
"requirements": { "$ref": "/schemas/core/requirements/url-asset-requirements.json" }
},
"required": ["asset_type"]
},
{
"title": "IndividualWebhookAsset",
"description": "Webhook asset",
"allOf": [{ "$ref": "#/$defs/baseIndividualAsset" }],
"properties": {
"item_type": { "type": "string", "const": "individual" },
"asset_type": { "type": "string", "const": "webhook" },
"requirements": { "$ref": "/schemas/core/requirements/webhook-asset-requirements.json" }
},
"required": ["asset_type"]
},
{
"title": "IndividualBriefAsset",
"description": "Brief asset",
"allOf": [{ "$ref": "#/$defs/baseIndividualAsset" }],
"properties": {
"item_type": { "type": "string", "const": "individual" },
"asset_type": { "type": "string", "const": "brief" }
},
"required": ["asset_type"]
},
{
"title": "IndividualCatalogAsset",
"description": "Catalog asset",
"allOf": [{ "$ref": "#/$defs/baseIndividualAsset" }],
"properties": {
"item_type": { "type": "string", "const": "individual" },
"asset_type": { "type": "string", "const": "catalog" },
"requirements": { "$ref": "/schemas/core/requirements/catalog-requirements.json" }
},
"required": ["asset_type"]
}
]
},
{
"title": "RepeatableGroupAsset",
Expand Down