You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
types: ship a strict canonical format_kind validator alongside the open string #1438
9.0 makes format_kind / format_kinds open strings everywhere and offers is_canonical_format_kind() for callers that need to be strict. That works, but a seller that serves only specific spec versions (where canonical_format_kind is a closed enum) has to restore the check on every inheriting model by hand.
The Embedded Sales Agent serves AdCP 3.1 and 3.2 and must refuse unknown kinds at the boundary. On 9.0.0b1 it needed a mixin with field_validator("format_kind", "format_kinds", check_fields=False) on seven subclasses: CreativeAsset, Creative, Package, PackageRequest, AffectedPackage, Format and ProductFilters. Missing one silently accepts free-form kinds on that path.
Ask
Ship the strict variant alongside the open one, for example:
an Annotated type (CanonicalFormatKindStr, optionally parameterized by vocabulary) adopters can use when they redeclare a field, and/or
a mixin or validator factory (require_canonical_format_kind(vocabulary=CanonicalFormatKind)) that applies to both field names and to lists.
That would answer the "where does the producer-side constraint belong" question from #1140 with a supported one-liner.
Classification: Feature request Bucket(s): validation (validation label not found in repo — gap flagged) Status: ready-to-implement
What the experts said:
ad-tech-protocol-expert: APPROVE — purely additive surface over the existing is_canonical_format_kind(vocabulary=...); producer-side enforcement placed at the caller boundary is correct per the AdCP open-enum spec; no protocol objection.
code-reviewer: APPROVE — Annotated[str, AfterValidator(is_canonical_format_kind)] is the idiomatic form; list[CanonicalFormatKindStr] handles format_kinds plural fields for free; three implementation notes: (1) None-safety on optional fields, (2) closure capture if factory variant used, (3) helpers must not be applied to SDK model fields.
My take: Both experts converge on a clean, non-breaking additive feature. The PR authorization gate is not met (no /triage execute, no auto-pr-ok), so this is ready-to-implement. Comment /triage execute on this issue to authorize a draft PR.
Implementation brief:
Scope: Add CanonicalFormatKindStr (Annotated[str, AfterValidator(is_canonical_format_kind)]) to src/adcp/types/canonical_creative.py, co-located with is_canonical_format_kind(); export via _eager.py → __init__.py.
Likely files:src/adcp/types/canonical_creative.py, src/adcp/types/_eager.py, new tests in tests/.
Non-breaking: Purely additive — no existing symbol renamed or type changed; SDK model format_kind: str | None fields are untouched.
None-safety: All seven affected model fields are str | None; guard for None — either document CanonicalFormatKindStr is for required fields only, or provide a nullable companion. is_canonical_format_kind(None) returns False and will reject None in an AfterValidator.
SDK model constraint: Docstring must explicitly prohibit applying these helpers to SDK model fields — open-vocabulary is a hard SDK constraint.
Activity
bokelley commentedon Oct 7, 2026
Triage
Classification: Feature request
Bucket(s): validation (
validationlabel not found in repo — gap flagged)Status: ready-to-implement
What the experts said:
is_canonical_format_kind(vocabulary=...); producer-side enforcement placed at the caller boundary is correct per the AdCP open-enum spec; no protocol objection.Annotated[str, AfterValidator(is_canonical_format_kind)]is the idiomatic form;list[CanonicalFormatKindStr]handlesformat_kindsplural fields for free; three implementation notes: (1)None-safety on optional fields, (2) closure capture if factory variant used, (3) helpers must not be applied to SDK model fields.My take: Both experts converge on a clean, non-breaking additive feature. The PR authorization gate is not met (no
/triage execute, noauto-pr-ok), so this is ready-to-implement. Comment/triage executeon this issue to authorize a draft PR.Implementation brief:
CanonicalFormatKindStr(Annotated[str, AfterValidator(is_canonical_format_kind)]) tosrc/adcp/types/canonical_creative.py, co-located withis_canonical_format_kind(); export via_eager.py→__init__.py.src/adcp/types/canonical_creative.py,src/adcp/types/_eager.py, new tests intests/.pytest tests/,mypy src/,ruff check ..format_kind: str | Nonefields are untouched.None-safety: All seven affected model fields arestr | None; guard forNone— either documentCanonicalFormatKindStris for required fields only, or provide a nullable companion.is_canonical_format_kind(None)returnsFalseand will rejectNonein anAfterValidator.Triaged by Claude Code. Session: https://claude.ai/code/session_01Hk5h6LenLn17kK5cfLgdmY
Generated by Claude Code