Skip to content

Remove envelope workarounds: status stripped from four tools, every response root relaxed #3481

Closed

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.

The SDK has workarounds for the old schemas, and they become wrong once the fix lands:

  1. status is stripped from four tools. genericResponse() (src/lib/server/create-adcp-server.ts:2910) deletes status from structuredContent for STATUS_FREE_SYNC_RESPONSE_TOOLS (list_products, decline_proposals, list_collections, list_proposals, defined in src/lib/utils/envelope-status-compat.ts:54). Line :4433 skips the default status injection for the same tools, and envelope-status-compat.ts:123 returns early for them. The envelope makes status REQUIRED on every task response, so servers built on the SDK now send non-conforming responses for these four tools. The AdCP training agent's tenant-smoke list_products test fails for exactly this reason.
  2. Every response root is relaxed. relaxResponseRoot() (src/lib/validation/schema-loader.ts:706) sets additionalProperties: true on every response root and on its oneOf/anyOf/allOf branches. Once the envelope is composed, closed schemas already accept envelope fields, so the relaxation only hides real drift at the root.

What needs to change:

  • Emit status on every task response, and delete STATUS_FREE_SYNC_RESPONSE_TOOLS.
  • Drop relaxResponseRoot() for schema bundles built with the composed envelope.
  • Where compat is still needed for released schemas that predate the fix (3.2.7 and earlier), choose it by the served version, not by tool name.

Activity

  1. KonstantinMirin commented on Oct 28, 2026

    @KonstantinMirin
    ContributorAuthor

    Adding the reason this change isn't optional: AdCP 3.x is additive-only.

    status has been REQUIRED on every task response since 3.1 (core/protocol-envelope.json). 3.2 doesn't say otherwise anywhere. No doc or changeset makes compact responses status-free. The only source is that the closed 3.2.7 compact schemas didn't compose the envelope, so they never declared status. STATUS_FREE_SYNC_RESPONSE_TOOLS turned that gap into intent ("3.2 synchronous response arms that intentionally forbid task-envelope status", added in e0d722b) and deletes a required field inside a minor version. If it were ever meant to go, it would have had to stay present and deprecated until 4.0. This also regresses #1897 ("Envelope status missing on every sync wire response").

    3.2.x is affected too. rc.53 strips status from list_products and decline_proposals. With adcontextprotocol/adcp#8547 and its 3.2.x backport, the AdCP training agent fails nine storyboard steps on exactly this, across compact_direct_buy_lifecycle, compact_product_lifecycle, declined_proposal_refinement and declined_proposal_execution. We're not working around it on the training-agent side, so both PRs stay red on these steps until the SDK sends status again.

  2. bokelley commented on Oct 28, 2026

    @bokelley
    Contributor

    Fix in progress: #3493.

    Approach (per served release, DR-0024). Konstantin is right that status is REQUIRED on every task response since 3.1 and that the 3.2.7 compact schemas only dropped it by being closed. Two further facts shaped the fix:

    • Every 3.2.x release (and the published 3.3.0-beta.0) publishes list_products closed with no status property, and the decline_proposals success arm carries not: required status. A valid 3.2.x response is therefore invalid under #8547's 3.3 schema, and the reverse. A blanket "always send status" would break strict validation against 3.2.x.
    • So the SDK no longer decides this with a hardcoded tool list. The served release's own published schema decides (omitsEnvelopeStatusForRelease): status is kept for list_products, decline_proposals, list_collections and list_proposals whenever that release composes core/protocol-envelope.json, and omitted only where the release's schema for the tool has no status (3.2.x). When the 3.2.x backport of #8547 ships, the answer flips without a code change. STATUS_FREE_SYNC_RESPONSE_TOOLS is gone.
    • relaxResponseRoot() is removed. A bundle that composes the envelope is validated exactly as published, status required, nothing filled in. For closed pre-composition roots (3.2.7 and earlier) the validator accepts only the envelope fields that release's own protocol-envelope.json defines, on the closed nodes; body typos are still rejected and no envelope field is added or removed.

    Verified against #8547 (head 3da19611): with the PR's schema root registered, the SDK passes compact_direct_buy_lifecycle, compact_product_lifecycle, declined_proposal_refinement, declined_proposal_execution, outcome_target_list_products_inert, product_coverage_filters, sales_dooh and availability_windows (0 failed steps). Unmodified main fails the same steps with must have required property 'status'.

    Caveat. The SDK pin stays on the published 3.3.0-beta.0 bundle for now (it forbids status on these arms), so a seller on the default pin keeps omitting it until the pin moves to beta.1 or a composed bundle. #8547's training agent opts into the composed contract by registering its built schema root; I'll leave the exact change on #8547.

  3. KonstantinMirin commented on Oct 29, 2026

    @KonstantinMirin
    ContributorAuthor

    Thanks. #3493 is in 17.0.0-beta.6, and #8547 is moving to it now.

    The 3.2.x side still needs it. adcontextprotocol/adcp#8567 (the 3.2.x backport of the envelope fix, shipping in 3.2.9) runs the training agent on @adcp/sdk 14.0.0-rc.53. Every SDK release a 3.2.x seller can use still has STATUS_FREE_SYNC_RESPONSE_TOOLS: 14.0.0-rc.53, 16.5.0 (adcp-3.2) and 16.6.1 (latest). So #8567's compact_direct_buy_lifecycle step stays red, and sellers on 3.2.9 would keep losing status on list_products and decline_proposals.

    Could #3493 be backported to the 3.2 line (the adcp-3.2 dist-tag)? Its gating on the served release's schema already covers the transition. Against 3.2.8's published schemas it keeps omitting status. Once 3.2.9 publishes schemas that compose the envelope, it keeps it, with no code change. Once that release is out, #8567 will bump to it.

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