spec(3.1): add capability_ids[] to PackageRequest for V2-native authoring#4845
Merged
Conversation
…ring Closes #4842. The V2 mental model (`Product.format_options[]` → V2-tagged `creative-manifest` with `capability_id`) broke at the `create_media_buy` boundary because `PackageRequest` only carried v1 `format_ids[]`. Buyers authoring against `format_options[]` had to translate back through `v1_format_ref[]` just to write a create call. Adds optional `capability_ids: string[]` (array, parity with the existing `format_ids[]` shape — a package may activate multiple `format_options[]` entries even though the 90% case is `[one]`). Closed-set validation: sellers MUST reject with `UNSUPPORTED_FEATURE` when an entry doesn't resolve, when the product is v1-only, or when the product's `format_options[]` entries don't publish `capability_id` values (latter case carries `error.details.reason: capability_ids_not_published` so buyers can fall back to `format_ids[]`). Dual-emission of `format_ids` alongside `capability_ids` is SHOULD for V2-native SDKs — v1-only sellers ignore the unknown field per `additionalProperties: true` and would otherwise silently default to all-formats. When both are present, `capability_ids` wins and the resolving seller doesn't validate `format_ids` for consistency. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Contributor
|
The automated review encountered an issue (possibly reached max turns, timed out, or failed to post the final This is an automated message from the Argus AI review workflow. |
CI schema validation failed parsing `error.details.reason: "..."` — the inner double-quotes broke the JSON string. Use backticks around the enum-value reference instead.
Contributor
There was a problem hiding this comment.
Approving. Right shape, internally consistent, closes the V2-authoring gap without breaking v1 callers.
Things I checked
- Field shape at
static/schemas/source/media-buy/package-request.json:26-33— array,items.type: string,minItems: 1. Mirrorsformat_ids[]. Asymmetry vs singularcreative-manifest.capability_id(static/schemas/source/core/creative-manifest.json:16) is principled: one manifest = one declaration, one package can activate multiple declarations. - Resolution precedence and dual-emission rule are unambiguous in both
static/schemas/source/media-buy/package-request.json:28anddocs/media-buy/task-reference/create_media_buy.mdx:188-189. The "neither sent → all formats supported by the product" default is restated three times (schema, table row, Format Specification prose at:946) without drift. UNSUPPORTED_FEATUREis real (static/schemas/source/enums/error-code.json:104).FORMAT_INCOMPATIBLEis not — PR body flags the pre-existing phantom row as out-of-scope.additionalProperties: trueatstatic/schemas/source/media-buy/package-request.json:208confirmed — v1-only sellers silently drop the field. Back-compat claim holds.- Changeset present,
minoris correct for a purely additive optional field. format_idsRequiredYes → Noin the docs table atdocs/media-buy/task-reference/create_media_buy.mdx:188is fixing latent drift, not loosening a contract: the schemarequiredarray atstatic/schemas/source/media-buy/package-request.json:203-207was always[product_id, budget, pricing_option_id]. The docs row was wrong.
Follow-ups (non-blocking — file as issues)
- Error-code choice for the third failure mode. When the product carries
format_options[]but no entry publishes acapability_id, the PR usesUNSUPPORTED_FEATUREwitherror.details.reason: "capability_ids_not_published". That case is structurallyFORMAT_CAPABILITY_UNRESOLVED— already in the enum atstatic/schemas/source/enums/error-code.json:166for theadagents.json/placement-definition.jsonside. Either broaden that code's applicability tocreate_media_buy, or mint aPACKAGE_CAPABILITY_UNRESOLVEDanalog. Editorial, not breaking — but worth picking the convention before the next PR copies the sub-discriminator pattern. - Seller obligation is prose-only. "Sellers MUST publish
capability_idon eachformat_options[]entry it expects buyers to select" lives only in the new field description and docs.static/schemas/source/core/product-format-declaration.json:10-12keepscapability_idoptional with the existing "only required when multiple entries shareformat_kind" rule. A seller can publish V2 products that are unauthorable on the V2 path and only fail atcreate_media_buytime. Future PR: either tighten the declaration schema or add aget_adcp_capabilitiesflag so buyers can discover V2-package-authorability before eating anUNSUPPORTED_FEATURE. - Phantom
FORMAT_INCOMPATIBLErow in the error table atdocs/media-buy/task-reference/create_media_buy.mdx:921predates this PR. File the cleanup issue per the PR body. - Missing example for the
capability_ids_not_publishedbranch. The new V2 invalid-capability example atdocs/media-buy/task-reference/create_media_buy.mdx:1057-1067usessupported_capability_idsas a sibling ofcode/message/field, matching the page's v1supported_formatsconvention but not exercising the schema-prescribederror.details.reason: "capability_ids_not_published"branch. Add a second example showing thedetails.reasonshape — that's the only branch where the schema prescribes a specificdetailspayload, and the docs should demonstrate it.
Minor nits (non-blocking)
- Changeset wording. Call out the incidental
format_ids: Yes → Nocorrection in.changeset/package-request-capability-ids.md. It IS a fix to latent drift, not a contract change — but SDK authors regenerating types from this release will see the change in the generated shape and the changeset doesn't currently mention it. - Schema-description size. The new
capability_idsdescription atstatic/schemas/source/media-buy/package-request.json:28is ~1.5 KB of normative prose inside a JSONdescription. Codegen will dump that verbatim into TS / Pydantic doc comments and into the bundled-schema artifact. Consider trimming the schema description to a short summary plus a link tocreate_media_buy.mdx, and let the page carry the normative resolution-rule + failure-mode block. Not a correctness issue.
Two precedents land in this PR — error.details.reason as a sub-discriminator, and ~1.5 KB of normative wire rules living in a JSON description field. Worth locking down the conventions before the next three PRs copy them.
LGTM. Follow-ups noted below.
This was referenced May 20, 2026
bokelley
added a commit
that referenced
this pull request
May 20, 2026
…RE (#4860) The `create_media_buy` docs referenced `FORMAT_INCOMPATIBLE` in the error table and two JSON response examples, but the code was never defined in `error-code.json`. SDKs that validate `errors[].code` against the published enum would reject responses built from the docs literally. Migrated all three references to `UNSUPPORTED_FEATURE` — semantics match ("a requested feature or field is not supported by this seller" = "format not in the product's accepted set"). The error-table row was also merged with the sibling `UNSUPPORTED_FEATURE` row added in #4845 (v2 `capability_ids[]` failure modes), so a single row now spans both v1 `format_ids[]` and v2 `capability_ids[]` mismatch cases. Closes #4852. Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
bokelley
added a commit
that referenced
this pull request
May 20, 2026
…ry (#4861) #4845 added `PackageRequest.capability_ids[]` so V2-mental-model buyers can author `create_media_buy` without translating back through `v1_format_ref[]`. That path needs sellers to publish `capability_id` on the `format_options[]` entries the buyer targets — but the field is currently REQUIRED only when entries share a `format_kind`. For single-entry products (the 90% case), it's optional, and V2 authoring is silently unreachable. Add a SHOULD: sellers SHOULD set `capability_id` on every entry, not just when forced by a collision. Co-located with the buyer-side change in the same minor so 3.1 release-notes readers see the buyer capability and the seller obligation together. Description-text only — no structural change. The 4.0 cutover will tighten SHOULD → MUST (tracked in #4857). Closes #4856. Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
bokelley
added a commit
that referenced
this pull request
May 22, 2026
…TURE in create_media_buy (#4854) FORMAT_INCOMPATIBLE appeared in the error table and two JSON examples in create_media_buy.mdx but was never present in error-code.json. SDKs validating errors[].code against the enum would treat it as unknown, defeating structured recovery. Fixes: remove FORMAT_INCOMPATIBLE row; fold v1-path guidance into the existing UNSUPPORTED_FEATURE row (which already covers the v2/capability_ids path); replace FORMAT_INCOMPATIBLE with UNSUPPORTED_FEATURE in both JSON examples; update field path in both v1 examples to packages[0].format_ids[0] for element-level precision, consistent with the v2 example's packages[0].capability_ids[0]. Closes #4852. Surfaced during review of #4845. https://claude.ai/code/session_01MVUhgB3tVFtW85wDQ1MATy Co-authored-by: Claude <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Closes #4842.
The V2 mental model breaks at the
create_media_buyboundary today:PackageRequestonly carries v1format_ids[]. A buyer readingProduct.format_options[](the V2 path) has to translate back throughv1_format_ref[]just to write a create call — exactly where the buyer commits budget.Adds optional
capability_ids: string[]toPackageRequest. Resolution rules:capability_idswins; the resolving seller routes by it and MUST NOT validateformat_idsfor consistency (the v1-compat hint is for intermediaries on the wire path).capability_idsonly. Seller resolves against the product'sformat_options[]; uses each declaration'sv1_format_ref[]when projecting to v1-wire surfaces.format_idsonly. Unchanged v1 behavior.Failure modes — seller MUST reject with
UNSUPPORTED_FEATURE(pathpackages[i].capability_ids[j]) when an entry doesn't resolve, when the product is v1-only (noformat_options[]at all), or when the product'sformat_options[]entries don't publishcapability_idvalues. The last case setserror.details.reasontocapability_ids_not_publishedso V2 buyers know to fall back toformat_ids[].Dual emission — V2-native buyer SDKs targeting a heterogeneous seller population SHOULD emit
format_idsalongsidecapability_idsso v1-only sellers — which ignore the unknown field peradditionalProperties: true— still receive an explicit format set rather than silently defaulting to all-formats.Shape — array, not singular. Parity with
format_ids[]. A package may legitimately activate multipleformat_options[]entries even though the 90% case is[one]. Per-creativecreative-manifestkeeps its singularcapability_idbecause one manifest = one declaration — the asymmetry is intentional.Files
static/schemas/source/media-buy/package-request.json— new optional fielddocs/media-buy/task-reference/create_media_buy.mdx— Package Object row, V2 example in Format Specification, Format Workflow diagram updated (no longer says formats are REQUIRED), error table row, v2-path error example.changeset/package-request-capability-ids.md—minor(additive optional field on the spec)Doc correction (incidental)
The Package Object row for
format_idswas previously documented asRequired: Yes. The schema'srequiredlist has always been[product_id, budget, pricing_option_id]only —format_idswas always optional with a default of "all formats supported by the product." This PR corrects the row toRequired: Noto match the schema and to make the newcapability_idssemantics consistent (either-or-neither, never both required).Out of scope
FORMAT_INCOMPATIBLE, which isn't actually instatic/schemas/source/enums/error-code.json— this PR usesUNSUPPORTED_FEATUREfor the new failure modes and leaves the pre-existing row untouched. Worth filing separately.product-format-declaration.jsonto requirecapability_idalways is a separate design call; this PR documents the seller obligation in the new field's description instead.Test plan
🤖 Generated with Claude Code