Skip to content

Generated response types can't represent the protocol envelope #1678

Open

Description

@KonstantinMirin

adcontextprotocol/adcp#8547 fixes the root cause in the spec. Task response schemas now compose core/protocol-envelope.json, closed ones included, so every response accepts and declares the envelope fields: status, task_id, context_id, message, timestamp, replayed, adcp_error, push_notification_config, governance_context, adcp_version and adcp_major_version. A 3.2.x backport with the same design is coming. Background: adcontextprotocol/adcp#8518.

Because the old schemas didn't compose the envelope, the generated types can't represent a conforming response:

  1. Generated types are missing envelope fields. ListProductsResponse in src/adcp/types/v32.pyi:29289 has replayed, context and ext, because those were copied into the schema by hand. It has no status, adcp_version, task_id, timestamp or message. Typed code can't read or set fields that every conforming response carries. The same applies to every response type generated from a schema that didn't compose the envelope.
  2. Validation rejects conforming responses. VersionedSchemaModel (src/adcp/types/versioned.py:228) validates against the exact bundled schema. Against the 3.2.7 bundle, a conforming list_products response that carries status and the adcp_version echo fails validation.

What needs to change:

  • Regenerate types from the composed schemas once #8547 and the 3.2.x backport land. Check that codegen follows root allOf into protocol-envelope (and through it into version-envelope), so every response type carries the envelope fields.
  • Rebundle the 3.2 schemas from the backport release.
  • Review the places that pop status from responses (src/adcp/server/mcp_tools.py:3946, src/adcp/compat/versions.py:961). They're only correct when converting to wire versions where status meant something else. For 3.1 and later, status is required on every response.

Activity

  1. KonstantinMirin commented on Oct 28, 2026

    @KonstantinMirin
    CollaboratorAuthor

    A correction to the "check that codegen follows allOf" item: it already does. GetMediaBuysResponse composes the envelope, and its generated type carries every envelope field (status, adcp_version, task_id, timestamp, …). So the missing fields come entirely from the schemas, and regenerating from adcontextprotocol/adcp#8547 (and the 3.2.x backport, once released) should be enough. The status pops in mcp_tools.py and compat/versions.py still need checking: they're only correct when the served release is 3.0.

  2. bokelley commented on Oct 29, 2026

    @bokelley
    Contributor

    Readiness check for the regeneration this issue needs, measured on 2026-10-29 by running scripts/generate_types.py against adcp#8547's schema tree (fix/compose-protocol-envelope-on-task-responses at dc66f234, overlaid onto a scratch copy of the 3.3.0-beta.1 cache with bundle-style refs; nothing committed).

    Codegen follows the composition. With #1705 (the #1680 fix) applied, the post-generation passes run to completion and the staged tree has class ProtocolEnvelope(AdcpVersionEnvelope) and class ListProductsResponse1(AdcpResponse, ProtocolEnvelope); 117 response arms inherit ProtocolEnvelope and none the old (AdcpVersionEnvelope, ProtocolEnvelope) pair. The envelope fields (status, task_id, context_id, message, timestamp, replayed, adcp_error, push_notification_config, governance_context, adcp_version, adcp_major_version) reach every response type through the base, so point 1 resolves by regeneration alone once the composed bundle is released.

    One blocker surfaces at export consolidation. The new schema set changes the import graph so that core/creative_assets.py evaluates asset_union.AssetVariant in its AdCPRootModel[list[...]] base while core/assets/asset_union.py is still initializing (error_details/__init__ → core/__init__ → asset_union → video_brief_asset → creative/__init__ → get_creative_delivery_response → core/creative_variant → creative_manifest → creative_assets). AttributeError: partially initialized module ... has no attribute 'AssetVariant'. Today's 3.3.0-beta.1 tree does not hit it from any of those entry points, so it is a regeneration-time fix: either order the domain __init__ imports so asset_union completes first, or make the root model's element reference lazy.

    Point 2 (VersionedSchemaModel validating against the exact bundled schema) resolves with the rebundle from the 3.2.x backport / 3.3 release; no SDK change until then.

    The status pops (server/mcp_tools.py legacy-adapter path and compat/versions.py downgrade step) are both version-gated: the first fires only for a legacy adapter, the second only when converting downward to a wire version where status meant something else and records a ConversionLoss. They stay correct for 3.1+ and need no change for this issue.

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

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions