Skip to content

format_kind typing: suggest CanonicalFormatKind | str, and a question about where the producer-side constraint belongs #1140

Description

@KonstantinMirin

This is a suggestion and a question rather than a bug report. The second half asks a specification-design question that an SDK cannot answer alone.

Suggested typing for the consumer side

core/canonical-format-kind.json makes the enum asymmetric on purpose:

Open-enum semantics (normative). … Consumer SDKs MUST treat this enum as open at parse time: an unknown format_kind value MUST be retained as-is on the in-memory object (not silently dropped or rewritten to "custom") and MUST NOT cause the surrounding payload to fail validation. … The producer-side enum stays closed …

The generated field is the bare enum, so a canonical promoted in a later minor release fails validation of the whole payload. Reproduced against adcp==6.6.0:

CreativeAsset2.model_validate({"creative_id": "c", "name": "n", "assets": {},
                               "format_kind": "a_future_canonical_from_3_2"})
# ValidationError: [{'type': 'enum', ...}]

CanonicalFormatKind already subclasses StrEnum, so a union costs little and round-trips correctly:

TypeAdapter(CanonicalFormatKind | str).validate_python("image")     # -> CanonicalFormatKind.image ('image')
TypeAdapter(CanonicalFormatKind | str).validate_python("future_x")  # -> 'future_x'

A known value keeps its enum member, and because the member subclasses str, comparison and serialization behave as before. An unknown value survives as a str, which is what the MUST requires. The change applies wherever the generator emits format_kind: creative-asset, product-format-declaration, creative-manifest, and package-request.

This typing change is not validation. It makes the SDK forward-compatible, and it constrains no producer. That distinction leads to the question.

Open question: where the producer-side constraint belongs

The producer rule in the specification is strict. Sellers "MUST NOT mint ad-hoc format_kind values — use format_kind: "custom" with format_shape + format_schema", and both format_shape and format_schema are "REQUIRED when format_kind: "custom"; otherwise MUST be absent."

Nothing enforces either rule. Measured against ProductFormatDeclaration:

ProductFormatDeclaration.model_validate({"format_kind": "custom", "params": {}})
# ACCEPTED - carries neither format_shape nor format_schema

ProductFormatDeclaration.model_validate({"format_kind": "image", "params": {}, "format_shape": "roadblock"})
# ACCEPTED - carries format_shape on a non-custom kind

So the SDK is strict in the one place the specification mandates openness, and permissive in the place the specification constrains producers. Fixing the typing leaves the second half open.

Here is why I am asking rather than filing a bug. A closed enum that ships a custom escape, whose own requirements go unvalidated, combines the costs of both models: consumers cannot treat the enum as exhaustive, and producers get no enforcement that custom carries the schema that makes it interpretable. If custom is a first-class extension point, then the conditional that makes it usable — format_shape plus format_schema — is the part that most needs validating. If custom is not an extension point, then the twelve canonicals plus the promotion queue in #3666 make a simpler contract.

Do you intend the seller's own boundary to validate this conditional rather than an SDK? If so, please state that normatively: no tool in the chain grades the conditional, so each seller lands somewhere different. I am happy to move this half to adcontextprotocol/adcp if that repository suits it better. The typing suggestion stands on its own either way.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions