Repository navigation
fix(compat): infer display_tag and every 3.2 asset type from the asset key - #1628
Conversation
…t key coerce_legacy_assets() / infer_asset_type() let an exact type-name key win over field presence, but the type names came from a hand-kept list of 14 that predated AdCP 3.2. An untyped asset under `display_tag` was inferred as text, url or image from its other keys. Derive the vocabulary from the generated AssetVariant union instead, so the key list is the 21 asset types the pinned schema declares (adds display_tag, zip, card, published_post, pixel_tracker, vast_tracker, daast_tracker) and a schema bump extends it in the same regeneration. Imported lazily on first use. Fixes #1624 Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
There was a problem hiding this comment.
Ladon verdict: Approve
Approve — clean fix with no blocking findings.
Checked: replaces the stale 14-entry hand-kept _KNOWN_ASSET_TYPES in src/adcp/types/_legacy_assets.py with a vocabulary derived lazily and cached from the generated AssetVariant union (21 arms), so a schema bump extends key inference during regeneration. This directly addresses the repo's "hand-written vocabulary beside a generated union" concern — the derivation now tracks the generated source rather than drifting. Derivation handles both AdCPBaseModel arms and the RootModel multi-shape arms (display_tag, vast, daast, published_post); all 14 prior entries are retained with no existing-key regression. The fix(compat) semver signal is correct: the behavior change (untyped card/zip keys now infer their named type) is a documented spec-correct bug fix, not a published-contract break — no public export removed/renamed, no required↔optional flip, no enum member removal. The new cross-check test ties the legacy-derived vocabulary to format's emitted _KNOWN_BASE_INDIVIDUAL_ASSET_TYPES, preventing drift between the two generated lists.
No Critical/High/Medium findings. high_risk is false, gated_paths is false, no author team gate. Decision table rows 1–8 do not fire; falls through to row 9 (approve). Note: review_decision is REVIEW_REQUIRED, but since gated_paths is false, row 2 does not apply.
Fixes #1624 (part 1:
display_taginference; part 2,normalize_urlwhitespace, is a separate PR)Problem
coerce_legacy_assets/infer_asset_typelet an exact type-name key win over field presence. The type names came from a hand-kept list of 14 that predates AdCP 3.2, so an untyped asset underdisplay_tagwas inferred astext,urlorimagefrom its other keys:Fix
The vocabulary is now derived from the generated
AssetVariantunion (adcp.types.domains.core.assets.asset_union), the canonical creative-asset union. This follows #1501's derived format vocabulary. It is read lazily on first call and cached, so importing the legacy helpers still doesn't build the asset graph. A schema bump that adds an asset type extends key inference in the same regeneration.Checking the full 3.2 vocabulary found 7 types missing from the hand list, not just
display_tag. All are now inferred from an exact key:display_tag,zip,card,published_post,pixel_tracker,vast_tracker,daast_tracker.Judgement call: this applies only when
asset_typeis absent and the key is exactly a type name. That is the precedenceinfer_asset_typealready documents; the list had just gone stale. An untyped asset keyed exactlycardorzipthat used to be inferred astext/urlis now inferred as its named type. That is the spec-correct reading, and the same change the issue asks for ondisplay_tag.Tests
display_tagexample, with bothcontentandurlassets._KNOWN_BASE_INDIVIDUAL_ASSET_TYPES) is inferred from its key, so the two generated vocabularies can't drift apart.make lint,make typecheck-allandmake testwere run locally. One unrelated A2A integration test (test_a2a_context_id) flakes under local-n 8. It fails the same way on the #1619 branch and passed in #1626's CI.🤖 Generated with Claude Code