Background
Surfaced during expert review of #3996 (3.0.6 cherry-picks). The wire-placement guidance for `GOVERNANCE_DENIED` (and the parallel rule for `CreativeRejected`) is now MUST-language in `enumDescriptions` and `error-handling.mdx`:
Case 1. Task response defines a structured rejection arm. The arm IS the canonical denial shape. The seller populates `reason` and does NOT additionally emit `GOVERNANCE_DENIED` in `errors[]` or `adcp_error`. The rejection arms enforce this at the schema layer: e.g., `AcquireRightsRejected` and `CreativeRejected` both declare `not: { required: [errors] }`, so dual-emission is already a schema violation.
Case 2. Task response has no rejection arm. The seller populates `errors[].code: GOVERNANCE_DENIED` in the payload AND `adcp_error.code: GOVERNANCE_DENIED` on the envelope.
Today the only mechanism enforcing "rejection arm AND `errors[]` is a violation" is the schema-layer `not: { required: [errors] }` constraint. Conformant agents are protected at validation time, but no storyboard exercises both arms of the rule end-to-end. A seller that relaxes `additionalProperties` (or that runs ahead of the schema constraint via a hand-rolled response shape) can drift without detection until a buyer's runtime trips on the dual emission.
What this issue tracks
Add a storyboard that exercises the wire-placement rule on both arms:
-
Case-1 path (`acquire_rights` with `AcquireRightsRejected`) — the agent returns the rejection arm. Storyboard asserts:
- `status: 'rejected'` discriminator present
- `reason` populated
- `errors[]` absent (or empty)
- `adcp_error` absent
- Transport-level success markers retained (HTTP 200 / MCP `isError: false` / A2A `succeeded`)
-
Case-2 path (`create_media_buy` with no rejection arm — denial returned via `errors[]` + `adcp_error`) — the agent returns a failed task. Storyboard asserts:
- `errors[].code: GOVERNANCE_DENIED` present
- `adcp_error.code: GOVERNANCE_DENIED` present
- Transport-level failure markers flipped (HTTP 4xx / MCP `isError: true` / A2A `failed`)
-
Negative case (intentional violation) — a fixture variant that populates BOTH the rejection arm AND `errors[].code: GOVERNANCE_DENIED`. Storyboard asserts the agent's schema validation rejects the response.
Why now
The wire-placement guidance just shipped to `main` (#3929) and is being cherry-picked to 3.0.6 via #3996. Without a storyboard, the rule is asserted only in prose — adopters reading the long-form `GOVERNANCE_DENIED` description have no executable conformance check, and `@adcp/sdk` storyboard runners can't surface drift to a seller during onboarding.
Refs
🤖 Generated with Claude Code
Background
Surfaced during expert review of #3996 (3.0.6 cherry-picks). The wire-placement guidance for `GOVERNANCE_DENIED` (and the parallel rule for `CreativeRejected`) is now MUST-language in `enumDescriptions` and `error-handling.mdx`:
Today the only mechanism enforcing "rejection arm AND `errors[]` is a violation" is the schema-layer `not: { required: [errors] }` constraint. Conformant agents are protected at validation time, but no storyboard exercises both arms of the rule end-to-end. A seller that relaxes `additionalProperties` (or that runs ahead of the schema constraint via a hand-rolled response shape) can drift without detection until a buyer's runtime trips on the dual emission.
What this issue tracks
Add a storyboard that exercises the wire-placement rule on both arms:
Case-1 path (`acquire_rights` with `AcquireRightsRejected`) — the agent returns the rejection arm. Storyboard asserts:
Case-2 path (`create_media_buy` with no rejection arm — denial returned via `errors[]` + `adcp_error`) — the agent returns a failed task. Storyboard asserts:
Negative case (intentional violation) — a fixture variant that populates BOTH the rejection arm AND `errors[].code: GOVERNANCE_DENIED`. Storyboard asserts the agent's schema validation rejects the response.
Why now
The wire-placement guidance just shipped to `main` (#3929) and is being cherry-picked to 3.0.6 via #3996. Without a storyboard, the rule is asserted only in prose — adopters reading the long-form `GOVERNANCE_DENIED` description have no executable conformance check, and `@adcp/sdk` storyboard runners can't surface drift to a seller during onboarding.
Refs
🤖 Generated with Claude Code