Skip to content

types: ship a strict canonical format_kind validator alongside the open string #1438

Closed

Description

@bokelley

Summary

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.

Activity

  1. added
    claude-triagingTriage routine is actively working on this issue (1-3 min)
    on Oct 7, 2026
  2. bokelley commented on Oct 7, 2026

    @bokelley
    ContributorAuthor

    Triage

    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/.
    • Required checks: pytest tests/, mypy src/, ruff check ..
    • 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.

    Triaged by Claude Code. Session: https://claude.ai/code/session_01Hk5h6LenLn17kK5cfLgdmY


    Generated by Claude Code

  3. added
    enhancementNew feature or request
    and removed
    claude-triagingTriage routine is actively working on this issue (1-3 min)
    on Oct 7, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions