Summary
The compliance harness (and other internal callers) appear to construct PackageRequest objects using pre-3.0 shape:
packages[].product_ids: string[] — plural array
packages[].budget: { total, currency } — object
Per the AdCP 3.0 spec (static/schemas/source/media-buy/package-request.json in adcontextprotocol/adcp), the required 3.0 shape is:
packages[].product_id: string (singular)
packages[].budget: number
packages[].pricing_option_id: string
request-normalizer.ts::normalizePackageParams (compiled at dist/lib/utils/request-normalizer.js:23-46) currently translates only:
optimization_goal → optimization_goals (scalar → array, safe rename)
catalog → catalogs (scalar → array, safe rename)
context.buyer_ref → buyer_ref (4.15+ → pre-4.15 compat)
It does NOT translate the pre-3.0 product_ids[] / object-budget shapes, so 3.0-strict sellers reject the request.
Why fail closed rather than translate
product_ids[] → product_id is data loss: which id wins? budget: { total, currency } → budget: number is data loss: which currency does the seller bill in? These aren't renames; the safe answer is to refuse the request and tell the caller to supply 3.0 shape.
Per v2 sunset policy: v2 unsupported as of 3.0 GA (April 2026), security-only until Aug 1 2026. No remaining obligation to translate pre-3.0 shapes.
Repro
Comply run against Wonderstruck. Wonderstruck's MCP schema enforces 3.0 PackageRequest. Outcome:
INVALID_REQUEST: create_media_buy failed:
packages.0.product_id: Field required
packages.0.budget: Input should be a valid number
packages.0.pricing_option_id: Field required
Affected comply scenarios (10): idempotency/missing_key, pagination_integrity_list_accounts, schema_validation/temporal_validation, v3_envelope_integrity, proposal_finalize/brief_with_proposals, media_buy_state_machine/state_transitions + 2 cascades, media_buy_state_machine/terminal_enforcement + 3 cascades, error_compliance/error_responses (× 2 steps), error_compliance/version_negotiation.
Fix
In normalizePackageParams:
if (Array.isArray(normalized.product_ids)) {
throw new ADCPValidationError(
'packages[].product_ids is a pre-3.0 shape. Use product_id (singular) per AdCP 3.0.'
);
}
if (normalized.budget && typeof normalized.budget === 'object') {
throw new ADCPValidationError(
'packages[].budget as object is a pre-3.0 shape. Use budget as a number per AdCP 3.0.'
);
}
Then update the comply harness to emit 3.0 shape directly.
Cross-link
Same Wonderstruck probe as #1676 (account fabrication). Full findings in adcontextprotocol/adcp's .context/wonderstruck-findings.md.
Summary
The compliance harness (and other internal callers) appear to construct
PackageRequestobjects using pre-3.0 shape:packages[].product_ids: string[]— plural arraypackages[].budget: { total, currency }— objectPer the AdCP 3.0 spec (
static/schemas/source/media-buy/package-request.jsonin adcontextprotocol/adcp), the required 3.0 shape is:packages[].product_id: string(singular)packages[].budget: numberpackages[].pricing_option_id: stringrequest-normalizer.ts::normalizePackageParams(compiled atdist/lib/utils/request-normalizer.js:23-46) currently translates only:optimization_goal → optimization_goals(scalar → array, safe rename)catalog → catalogs(scalar → array, safe rename)context.buyer_ref → buyer_ref(4.15+ → pre-4.15 compat)It does NOT translate the pre-3.0
product_ids[]/ object-budget shapes, so 3.0-strict sellers reject the request.Why fail closed rather than translate
product_ids[]→product_idis data loss: which id wins?budget: { total, currency }→budget: numberis data loss: which currency does the seller bill in? These aren't renames; the safe answer is to refuse the request and tell the caller to supply 3.0 shape.Per v2 sunset policy: v2 unsupported as of 3.0 GA (April 2026), security-only until Aug 1 2026. No remaining obligation to translate pre-3.0 shapes.
Repro
Comply run against Wonderstruck. Wonderstruck's MCP schema enforces 3.0 PackageRequest. Outcome:
Affected comply scenarios (10):
idempotency/missing_key,pagination_integrity_list_accounts,schema_validation/temporal_validation,v3_envelope_integrity,proposal_finalize/brief_with_proposals,media_buy_state_machine/state_transitions+ 2 cascades,media_buy_state_machine/terminal_enforcement+ 3 cascades,error_compliance/error_responses(× 2 steps),error_compliance/version_negotiation.Fix
In
normalizePackageParams:Then update the comply harness to emit 3.0 shape directly.
Cross-link
Same Wonderstruck probe as #1676 (account fabrication). Full findings in adcontextprotocol/adcp's
.context/wonderstruck-findings.md.