# AdCP — Advertising Context Protocol

> What the Advertising Context Protocol (AdCP) is, what 3.2 changes and what claiming it asks of a 3.1 integration — domains, signals, governance, and the 3.1→3.2 and 3.0→3.1 checklists.

- Canonical: https://nofluffadvisory.com/standards/adcp/
- Standards last validated: 2026-10-13

---

*Standards & Protocols*

Reference

A practical guide to the open protocol layer for agentic advertising workflows: discovery, planning, buying, creative, signals, governance, accounts, and measurement.

AdCP gives advertising agents a shared task and schema layer. It helps buyers, sellers, platforms, data providers, and creative systems communicate through standardized advertising actions rather than bespoke dashboard workflows and one-off integrations.

*Figure: AdCP sits over MCP / A2A transport: a task layer above execution surfaces, with a governance rail.*

AdCP is not a replacement for OpenRTB, clean rooms, or human judgment. It is a protocol layer for making advertising work discoverable, executable, governable, and auditable by agents.

**Standard readiness (validate before build)**

- **AdCP 3.2** — GA · v3.2.4 · Oct 2026 [status: ga]
- **AdCP 3.1** — maintained · v3.1.27 · Oct 2026 [status: ga]
- **AdCP 3.0** — maintained · v3.0.28 · Oct 2026 [status: ga]
- **v2** — deprecated Aug 1, 2026 [status: deprecating]
- **Sponsored Intelligence** — experimental [status: rc] 

Part of [AdCP on No Fluff Advisory](/adcp/) — the spec explainer

## Fast read

- **What it is:** An open agentic advertising protocol that defines domain-specific tasks and schemas for advertising agents.
- **What it does:** Helps agents discover inventory, set up accounts, buy media, manage creative, activate signals, apply governance, and report results through standardized calls.
- **What it is not:** Not a media exchange, identity graph, DSP, SSP, clean room, or replacement for OpenRTB.
- **Why it matters:** Agentic workflows need repeatable, machine-readable actions. Without a shared protocol, every agent has to learn every platform separately.
- **Current state:** AdCP 3.2 is the general-availability line, wire pin "3.2": GA release v3.2.1 (the docs date it September 30, 2026; the GitHub release was published October 1 at 05:54 UTC), patched to v3.2.2 on October 4 (17:19 UTC; two documentation changes — account references before provisioning, and the trust-and-verification pages aligned with the spec) and to v3.2.3 on October 7 at 20:38 UTC, security errata for advisory GHSA-2pm6-6mc8-8xcm (adcp#7820; medium severity, published 11:45 UTC on October 8). Over A2A, <code>request_signing.required_for</code> was not enforced, so a seller that required signatures accepted unsigned <code>create_media_buy</code> and other spend-committing calls; 3.2.3 matches <code>required_for</code>, <code>supported_for</code> and <code>warn_for</code> against the AdCP operation resolved from the request (the tool name over MCP, the <code>skill</code> of the sole DataPart in an A2A message), fails closed when a request does not resolve to exactly one operation, and also carries storyboard fixes. v3.2.4 followed at 09:29 UTC on October 12, a patch of conformance and schema fixes: new request-signing vectors (negatives 029 to 031, positive guards 013 to 015, and profile-3.2 mirrors of every remaining root vector but 018, for verifiers that require content-digest coverage, which every 3.2 verifier does), negative 026 now expecting <code>request_target_uri_malformed</code>, four URL-canonicalization vectors, five storyboard fixes, a <code>requires: [controller]</code> gate on storyboards that seed fixtures through the test controller, a <code>REVISION_UNREADABLE</code> issue code on the experimental Reliable Reporting surface and bundled schemas about a fifth smaller. 3.2.0 was never released — an accidental cut on June 30 committed 3.2.0 from 3.1-era main, #5769 reverted it within hours, and its signed artifacts stay on the CDN under immutable caching, so the number is withdrawn and the first stable 3.2 is 3.2.1. Since the September 30 flip the docs call 3.1 a maintained line (security and critical fixes on 3.1.x for a maintainer-decided window) and 3.0 Maintained too (compatibility and security patches for existing integrations); both took a patch on October 1 at 14:15 UTC — v3.1.25 (five media-buy compliance storyboards seed non-guaranteed fixture products, backported from #7770 and #7756) and v3.0.27 (a default governance_agent_url in the 3.0 governance storyboards) — and more since: v3.0.28 (October 7, 14:13 UTC; a 3.0 storyboard fix that keeps deterministic media-buy phases independent of the Sponsored Intelligence session phase), v3.1.26 (October 7, 17:30 UTC; the creative evaluator-auth storyboard no longer fails every agent that declares creative.evaluator, and the four 3.1 media-buy governance scenarios take the hosted grader’s buyer brand from #7803) and v3.1.27 (October 8, 11:48 UTC; macro-bearing URL validation backported from 3.2, so VAST, DAAST, URL and tracker assets accept ad-server tokens such as %%CACHEBUSTER%% without pre-encoding their delimiters; #8004, fixing #7993). Neither these nor v3.2.2 to v3.2.4 are in the versions reference on main or on the published docs site as of 22:15 UTC on October 13 (both name 3.2.1, 3.1.24 and 3.0.26). 3.2 is additive over 3.1 apart from a recorded exception list; the two with the widest impact are that body-level <code>status</code> is gone from <code>create_media_buy</code> and <code>update_media_buy</code> success (read <code>media_buy_status</code>), and that a 3.2 signing endpoint requires <code>content-digest</code> coverage on every signed body and RFC 8941 padded Base64, with the profile selected by the endpoint rather than the request pin, so a 3.1-profile signer is rejected by a shared endpoint that advertises 3.2 even on a "3.1" pin. The docs say <code>@adcp/sdk</code> 14.0.0 and <code>adcp</code> 8.0.0 ship alongside 3.2.1, and both shipped on October 1: 14.0.0 reached npm at 12:39 UTC and 8.0.0 reached PyPI at 18:12 UTC. Since then npm <code>latest</code> has moved through 14.1.0 (October 4), 14.2.0 (October 5), 14.3.0 and 14.4.0 (both October 6) and on to 15.0.0 at 00:27 UTC on October 7, a new SDK major whose breaking change is OAuth issuer binding, not the protocol, and 15.2.0 at 16:35 UTC that day, the SDK-side fix for the same A2A signing gap; every one of these declares 3.2.1 and bundles the 3.0.25, 3.1.24 and 3.2.1 compliance lines, and <code>adcp-3.2</code> points at 14.4.0 as of 22:15 UTC on October 13, a build the advisory lists as affected. 15.2.1 (02:01 UTC on October 8) was the first build to declare 3.2.3 and bundle the 3.2.3 line, and every build after it through 15.8.1 declares 3.2.3 too: <code>latest</code> moved through 15.3.0 and 15.4.0 on October 8 and 15.5.0 and 15.6.0 on October 9 to 15.7.0 at 23:59 UTC that day, 15.7.1 (October 10) and 15.8.0 and 15.8.1 (October 11) followed, and 15.2.2 sits under a new <code>sdk-15.2</code> tag; 15.9.0 (02:41 UTC on October 13), <code>latest</code> as of 22:15 UTC on October 13, is the first build to declare 3.2.4 and bundle the 3.2.4 line, while <code>rc</code> stays on 14.0.0 and <code>adcp-3.1</code> on 13.1.3 (declares 3.1.24). The PyPI default moved to 8.1.0 on October 6 and to 8.1.1 at 11:33 UTC on October 8, which adopts the signed 3.2.3 bundle, beside 9.0.0b1, 9.0.0b2 and 9.0.0b3 prereleases, all as of 22:15 UTC on October 13. The newest tagged Go module, adcp/v3.2.1, still embeds rc.1, though adcp-go main took the final 3.2.2 schema bundle at 10:24 UTC on October 7, not in any tagged module and not moved on to 3.2.3 or 3.2.4, and Java has no released SDK, as of 22:15 UTC on October 13; the docs list Go and Java support for final 3.2 as planned follow-ups. Hosted grading moved to 3.2.1 with #7841 (merged 14:58 UTC on October 1: an agent that advertises 3.2 is graded on the 3.2 bundle, a 3.1-only agent stays on 3.1.24, and the badge lines are now 3.2, 3.1 and 3.0) and its runner to the stable 14.0.0 from 17:00 UTC, then to 14.2.0 from 16:20 UTC on October 6, to 15.0.0 from 10:39 UTC on October 9, after #7968 (merged 09:04 UTC that day) moved the registry to SDK 15.0.0, to 15.2.0 from 16:32 UTC that day, after #8012 (merged 12:23 UTC) moved it to SDK 15.2.0, and to 15.8.1 from 10:36 UTC on October 12, after #8148 (merged 09:38 UTC that day) moved it to SDK 15.8.1. The first public run on a 3.2 bundle followed the same evening, at 21:48 UTC on October 1 — one registered agent, gotom.io's dev-demo endpoint, on 3.2.1, then on 3.2.2 from October 5, on 3.2.3 from 17:57 UTC on October 8 and on 3.2.4 from 19:50 UTC on October 13, the day after each of those tags, the hosted grader loading its bundles from the adcp repo, not from the runner package (whose 15.8.1 build bundles 3.2.3), and #8153, merged 12:41 UTC on October 13, registering 3.2.4 there — and between October 2 and 22:15 UTC on October 13 the registry shows 459 public runs (the daily count fell from 56 on October 3 to 23 on October 11, was 31 on October 12 and 36 on October 13 by 22:15 UTC): 435 on 3.1.24, 14 on the 3.2 bundles (five on 3.2.1, three on 3.2.2, five on 3.2.3, one on 3.2.4, all from that one agent), 10 on 3.0.25, the last all on October 2 and 3 on the two TeqBlaze agents, which the grader has run on 3.1.24 since (the registry does not publish what an agent advertises on the wire). This site's two agents stay on "3.1" (the sales agent advertises only "3.1" and rejects a "3.2" pin; the signals agent advertises "3.0" and "3.1"). Claiming 3.2 would mean advertising and echoing "3.2", status-free create and update success bodies, error.recovery on every error and the tightened request rules; the compact tools stay optional, the signing profile binds only agents that support request signing, which since October 10 includes the signals agent (it verifies signed requests and advertises <code>covers_content_digest</code> "either", where a 3.2 endpoint advertises "required") but not the sales agent, and since #7841 a 3.2 badge is open to any agent that advertises 3.2 and passes on the 3.2 bundle.
- **Best next step:** Understand the domains, then decide which workflow your company should expose or consume first.

*Definition*

## What AdCP is.

AdCP is a shared advertising task layer for AI agents. It defines what agents can ask for, what systems should return, and how actions move through the advertising workflow.

| Layer | Job | Example |
| --- | --- | --- |
| Transport | Carries messages | `MCP / A2A` |
| AdCP | Defines advertising tasks and schemas | `get_products, create_media_buy, get_signals, activate_signal` |
| Execution system | Performs the action | `publisher, SSP, DSP, creative system, data provider` |
| Governance | Controls authority and audit | `approvals, signatures, idempotency, audit logs` |
| Existing ad standards | Power underlying objects and transactions | `OpenRTB, AdCOM, OpenDirect, Deals API` |

*Rationale*

## Why AdCP exists.

- **Fragmented workflows** — Media buying, creative, data activation, accounts, and reporting still live across disconnected systems and dashboards.
- **Agents need actions, not screens** — An agent cannot scale by clicking through every platform UI. It needs task-level interfaces.
- **Common schemas reduce ambiguity** — Natural-language briefs need to resolve into structured, auditable requests.
- **Human oversight needs architecture** — Agentic buying requires approvals, limits, audit logs, and accountability built into the flow.
- **Platform participation needs standards** — Publishers, data providers, creative systems, and ad platforms need a shared way to expose what agents are allowed to do.

*Version watch*

## What’s new in 3.2 — and what claiming it asks of a 3.1 adopter.

AdCP 3.2 is the current general-availability line (source: AdCP — GitHub release v3.2.1 (published October 1, 2026, 05:54 UTC; the docs date the release September 30); CHANGELOG.md 3.2.1 preamble on the withdrawn 3.2.0 (accidental cut 5dbe4ae on June 30, reverted by #5769); docs/reference/versions.mdx, migration/3-1-to-3-2.mdx and whats-new-in-3-2.mdx on the adcp main branch, flipped to GA September 30 at 16:24 UTC (#7775); GitHub releases v3.2.2 (October 4, 17:19 UTC), v3.2.3 (October 7, 20:38 UTC; advisory GHSA-2pm6-6mc8-8xcm, published October 8) and v3.2.4 (October 12, 09:29 UTC; contents per CHANGELOG.md 3.2.4); the maintenance tags v3.1.25 / v3.0.27 (October 1, 14:15 UTC), v3.0.28 and v3.1.26 (October 7) and v3.1.27 (October 8); npm, PyPI, the adcp-go tags and the registry grader re-checked 22:15 UTC on October 13) (GA release v3.2.1, patched to v3.2.2 on October 4, to v3.2.3, security errata for request signing over A2A, on October 7 and to v3.2.4, conformance fixes, on October 12; wire pin "3.2"; 3.2.0 was never released), additive over 3.1 apart from a recorded exception list. 3.1 is a maintained line at v3.1.27 (October 8): a seller that stays on "3.1" keeps serving 3.2 buyers, and the docs say keep the pin as long as you need. Separate what shipped from the obligations claiming 3.2 brings, from what is experimental, and from what Go and Java had not delivered as of 22:15 UTC on October 13.

**(GA · v3.2.4 — additive over 3.1 with recorded exceptions · 3.1 maintained at v3.1.27)**

**Confirmed — AdCP 3.2 (GA · v3.2.4):**

- AdCP 3.2 went GA as v3.2.1 — the docs date it September 30, 2026, the GitHub release was published October 1 at 05:54 UTC, and the wire pin is "3.2". 3.2.0 is a withdrawn number: an accidental Version Packages cut on June 30 (09:13 UTC) committed 3.2.0 from 3.1-era main, #5769 reverted it about four hours later (merged 13:37 UTC) and the tag and GitHub release were deleted, but its signed schema, compliance and protocol artifacts remain on the artifact CDN under immutable caching, so GA ships as 3.2.1 and anything at a 3.2.0 URL is 3.1-era content not to be used. The versions reference, the 3.1→3.2 migration guide and the What's New page on main flipped to GA at 16:24 UTC on September 30 (#7775), and as of 22:15 UTC on October 13 the published docs site, which serves the v3.2.3 snapshot (its versions page resolves under /dist/docs/3.2.3/; the v3.2.4 snapshot, #8150, is an open PR), shows the same stable rows as main: Active 3.2 (3.2.1), Maintained 3.1 (3.1.24) and 3.0 (3.0.26), 4.0 planned for early 2027 (main has also listed 3.3 as a pending beta since October 6, #7952; the published versions table does not show that row yet, though the 3.2.3 snapshot, #7999, merged 08:48 UTC on October 8, added a 3.3 preview group to the published navigation: What’s new in 3.3, the 3.3 beta program and the 3.2→3.3 migration guide) — the version tables are eight tags behind GitHub and the site’s own snapshot one (v3.2.4), where v3.2.2 (October 4, a Version Packages cut with two documentation patches; its docs snapshot landed the same evening, #7920, without touching the version tables), the v3.2.3 security errata (October 7), the v3.2.4 conformance patch (October 12) and the maintenance patches v3.1.25 to v3.1.27 and v3.0.27 to v3.0.28 (October 1 to 8) are already published.
- What 3.2 is for, in the docs' own framing: agents run media with the full power of the platform (seller-optimized shared budgets with a capability per control, hard daily budget caps, outcome targets with an optional cost-per target, and availability-horizon planning), a MediaBuy-level frequency cap counted across packages, Reliable Reporting as a discoverable contract (experimental), data collaboration, where products declare how audience data reaches them, clean rooms included (experimental, media_buy.audience_activation), a compact seven-tool lifecycle — list_products, request_proposals, refine_proposals, decline_proposals, buy_products, accept_proposal, control_media_buy — with the subset a seller serves advertised through media_buy.lifecycle_tools while get_products, create_media_buy and update_media_buy stay as 3.x facades, and runtime hardening: error.recovery on every 3.2 error, integer retry_after, 28 new standard error codes, identity never derived from Mcp-Session-Id, and idempotency ledgers that outlive the resources they create (COMMITTED_RESOURCE_PURGED). By the docs' numbers, 3.1.0 → 3.2.1: manifested tools 64 → 78, specialisms 21 → 31, standard error codes 92 → 120, source JSON Schema files 648 → 1,017, compliance YAML files 137 → 237.
- Additive over 3.1 apart from a recorded exception list: the ratified removal of body-level status from create_media_buy and update_media_buy success (DR-0011; read media_buy_status), the request-signing profile correction (3.2 endpoints that support signing require content-digest coverage on every signed body and RFC 8941 padded Base64; the endpoint selects the profile, so a 3.1-profile signer is rejected by a shared endpoint that advertises 3.2 even when the request pins "3.1"), eight tightened request rules (among them: create_media_buy takes exactly one of explicit packages or proposal_id plus total_budget; total_budget.currency must be uppercase ISO; sync_governance registers Bearer as the only authentication scheme; preview_creative takes creative_manifest or creative_id, not both) and three producer-side tightenings. The same section clarifies that delivery dates are calendar dates in the products' reporting timezone, echoed in reporting_period.timezone, and that a dated request spanning two reporting timezones is rejected with VALIDATION_ERROR (a "3.1" pin may keep 3.1 behaviour). A structural diff of the 3.1.24 and 3.2 schemas found no other stable-surface change that rejects a 3.1-valid payload (widened response shapes that a strict 3.1 parser may reject are listed separately in the migration guide, #7718); experimental surfaces changed under their own notice contract and are not exceptions.
- The SDKs caught up on October 1. The versions reference, the migration guide and the What's New page all say @adcp/sdk 14.0.0 (the What's New page and the migration guide add: npm latest) and adcp 8.0.0 ship alongside 3.2.1 and embed it. 14.0.0 was published at 12:39 UTC on October 1 (npm latest, rc and adcp-3.2 all pointed at it that day; its package.json declares adcp_version 3.2.1) and 8.0.0 at 18:12 UTC (the PyPI default until 8.1.0 on October 6), after a morning on which the newest builds were still 14.0.0-rc.53 and 8.0.0rc3 on the 3.2.0-rc.7 bundle; adcp-3.1 is on 13.1.3 (declares 3.1.24) as of 22:15 UTC on October 13, and npm latest moved through 14.1.0 (October 4), 14.2.0 (October 5), 14.3.0 and 14.4.0 (both October 6), then to 15.0.0 at 00:27 UTC on October 7, a new SDK major for an OAuth issuer-binding change, and 15.2.0 that afternoon, the SDK-side fix for the A2A signing advisory, while adcp-3.2 is on 14.4.0 as of 22:15 UTC on October 13; every one of these declares 3.2.1 and bundles the 3.0.25, 3.1.24 and 3.2.1 lines; none of these builds bundles 3.2.2. 15.2.1 (02:01 UTC on October 8) moved the pinned bundle to 3.2.3, and latest moved on through 15.3.0 and 15.4.0 (October 8) and 15.5.0 and 15.6.0 (October 9) to 15.7.0 (23:59 UTC on October 9), all declaring 3.2.3, as do 15.7.1 (October 10) and 15.8.0 and 15.8.1 (October 11), with 15.2.2 under a new sdk-15.2 tag; 15.9.0 (02:41 UTC on October 13), latest as of 22:15 UTC on October 13, moved the pinned bundle to 3.2.4. On PyPI the default moved to 8.1.0 on October 6, a backport of provisioning-aware accounts and signing fixes, and to 8.1.1 on October 8, which adopts the signed 3.2.3 bundle, with 9.0.0b1, 9.0.0b2 and 9.0.0b3 prereleases published October 6, 8 and 10. The newest Go module, adcp/v3.2.1 (September 5), embeds 3.2.0-rc.1 and defaults to the "3.1" pin — the guide says it is not AdCP 3.2.1 — and Go and Java support for final 3.2 are planned follow-ups; adcp-go main took the final 3.2.2 schema bundle at 10:24 UTC on October 7, not in any tagged module and not moved on to 3.2.3 or 3.2.4, as of 22:15 UTC on October 13.
- AdCP 3.1 is a maintained line since the September 30 flip, 3.0 the other: GA at v3.1.0 (June 18, 2026); v3.1.3 (July 13) withdrawn four days later for adding a stable schema field in a patch and an incorrect publisher-domain filter; patched through v3.1.24 (September 23, 2026), v3.1.25 (October 1; five media-buy compliance storyboards seed non-guaranteed fixture products so sales-non-guaranteed sellers no longer fail create_media_buy, backported from #7770 and #7756), v3.1.26 (October 7; the creative evaluator-auth storyboard no longer fails every agent that declares creative.evaluator, and the four media-buy governance scenarios take the hosted grader’s buyer brand from #7803) and v3.1.27 (October 8; macro-bearing URL validation backported from 3.2, #8004 for #7993), none of these three in the versions reference as of 22:15 UTC on October 13; 3.1.24 is eight conformance-suite changes — the governance scenarios gated on media_buy.governance_aware (#7625) and routed with the synchronized plan_id (#7555, resolving #7547, filed from here), the universal lifecycle and non-governance specialisms kept ungoverned on isolated account keys (#7627, from #7585, also filed from here) and the sales baselines likewise (#7665 resolving #7628), provenance tool prerequisites (#7586), agent_url canonicalization (#7367, partial), format_kind in the creative-generative storyboard, and VERSION_UNSUPPORTED recovery fatal → correctable (#7376 backport). Per the versions reference it receives security and critical fixes on 3.1.x for a maintainer-decided window (the versioning page still says older 3.x releases get no routine backports); the versions FAQ gives 3.0 an explicit floor of at least 12 months after 4.0 GA, the previous-major policy states that floor for the 3.x generation as security patches only, and nothing names a 3.1-specific window. Existing "3.1" sellers keep working: a 3.2 buyer downshifts to an advertised 3.1 release and the 3.x facades, and the docs say keep the pin as long as you need; the guide's buyer-side exceptions are signed requests to a seller that has added 3.2 on the same endpoint, and strict parsers on 3.2 shapes.
- Feature detail here is sourced from the official What's New in 3.2, the 3.1→3.2 migration guide and the versioning reference on the adcp main branch, plus the repo CHANGELOG — the GitHub release body is the string "AdCP 3.2.1".

**Obligations when you claim 3.2:**

- Advertise "3.2" in supported_versions only when you serve the 3.2 contract, keep advertising every earlier release you still serve, and echo the release actually served: the 3.2 grader makes a missing supported_versions or a missing echo a blocking failure, even though both fields stay schema-optional. A prerelease pin ("3.2-rc.N") never resolves to "3.2".
- Emit media_buy_status, and no body-level status, on 3.2 create and update success; keep the 3.0/3.1 handlers and the get_products / create_media_buy / update_media_buy facades. Emit error.recovery on every error and an integer retry_after.
- If you advertise request signing, advertise covers_content_digest: "required" and verify RFC 8941 padded Base64 on 3.2 endpoints. Decide how signed 3.1 callers keep working before you add "3.2" to a shared URL: AdCP has no capability field pointing from one endpoint to another (a second endpoint is published as its own agents[] entry), so the options are a separate endpoint or a coordinated cutover.
- Declare only the capabilities you implement — media_buy.lifecycle_tools, aggregate_frequency_capping, anonymous_discovery, seller_optimized_budget and its sub-capabilities, and specialisms — and reject an undeclared root frequency_cap, seller-optimized package control or outcome target (media_buy.outcome_target, the key the 3.2.1 storyboard gates on) with UNSUPPORTED_FEATURE rather than dropping it.
- Buyers: upgrade to a 3.2-capable SDK with the pin still at "3.1"; sign with the 3.2 profile for any endpoint that advertises 3.2, including requests you still pin to "3.1"; gate compact tools on lifecycle_tools and the root frequency_cap on aggregate_frequency_capping; send budget_allocation explicitly (omission still means fixed allocation); never infer 3.2 from a major-only declaration.
- Report delivery dates in the products' reporting timezone and echo reporting_period.timezone, report currency at media-buy or package grain, and stop producing new aggregated_totals. Discover creative through format_options[] and creative.supported_formats[]: list_creative_formats is compatibility-only and plural format_ids are deprecated for removal in 4.0.

**Experimental and dated in 3.2:**

- Experimental in 3.2, each under its own notice contract, includes campaign governance (governance.campaign), Trusted Match (trusted_match.core), audience activation (media_buy.audience_activation), product identity (media_buy.product_identity), execution requirements (media_buy.execution_requirements), Reliable Reporting (media_buy.reporting_delivery, reliable_reporting_version "1.0"), principals (protocol.principal), the account change feed (account.change_feed, RFC #6810 open), measurement.core and measurement.gateway, the static OOH delivery block, and the seller_rendered_stateful_display and coordinated_placements formats. Two changed in 3.2 under that contract per the What's New page, governance and Trusted Match; the release notes also record changes to brand rights and audience activation, and the experimental-status registry lists more surfaces (brand rights, verified identity, sponsored intelligence, two creative surfaces).
- Dated: sync_reporting_status is opt-in in 3.2 and becomes required Core in the next eligible minor, no earlier than October 24, 2026. Since #7841 (merged 14:58 UTC on October 1) hosted grading grades an agent that advertises 3.2 on the 3.2 compliance bundle, and 3.2 badges are issued only from those runs, with a "3.2" advertisement and echo; prerelease runs stay diagnostic. Further stable 3.x minors come at least eight weeks apart; patches are not bound by that.
- Still open as of 22:15 UTC on October 13: the spec does not state normatively that a seller serving "3.1" must emit 3.1-valid response shapes — the migration guide lists six 3.2 shapes that fail a strict 3.1 validator and the release notes name more (#7718; on October 12 the working group decided that a seller MUST shape a response to the negotiated release or stop advertising that release (milestone 3.3.0), recorded as DR-0024 in the open PR #8117); post-acceptance commercials (invoicing, payment rails, FX, makegoods, disputes) are deferred to the 3.3 commercial-completion workstream (#7064, still on the Spec Backlog milestone); per-account execution readiness is a 3.3 candidate in working-group review (#7763, on the 3.3.0 milestone), whose decision brief proposes draft #7934, an opt-in experimental execution_readiness map on get_products kept outside the cache layer.
- How it got here: a beta cycle from August 17 (beta.0, the protocol-first input) to beta.11 on September 3, rc.0 the same day, seven published candidates to rc.7 on September 27 (rc.5 withheld), the docs flipped to GA on September 30 and the tag followed on October 1.

**Watch next (the 3.3 beta, 4.0 and beyond):**

- 3.3 runs a short beta cycle. Since October 6 the versions reference on main lists 3.3 as a pending beta (#7952): beta.0 publishes the signed protocol bundle first, the SDKs then ingest it, and beta.1 converges protocol and SDKs, with exact prerelease wire pins such as "3.3-beta.0" for development and staging only. As of 22:15 UTC on October 13 no v3.3.0-beta.0 tag exists and the published docs site does not show the 3.3 row in its versions table yet, though since the 3.2.3 snapshot (#7999, merged 08:48 UTC on October 8) its navigation carries a 3.3 preview group with What’s new in 3.3, the 3.3 beta program and the 3.2→3.3 migration guide. Milestone assignment marks a candidate for the 3.3 line, not a commitment: the 3.3.0 milestone carries per-account execution readiness (#7763) and the seller-shape gap this site reported (#6303), for which draft #7963 proposes a sales-fixed-rate specialism, marked preview on October 9 until the working group ratifies its name and hold gating. The A2A signing question was settled for 3.2 by the 3.2.3 errata (#7820, closed October 8), whose hardening rules are SHOULD on 3.2.x and MUST from 3.3.
- The 4.0 deprecation set carries 3.2 additions, among them plural format_ids, the list_creative_formats pricing request fields and media-buy account field (the tool itself is compatibility-only and on its own schedule), cross-buy delivery aggregates, targeting-like product filters, bid_price and max_bid, and 3.1 terms_ref, with inline asset-access credentials to follow at 4.0 or later; alongside Format.pricing_options, legacy SignalId / flat signal targeting and data_provider_signals. Request signing becomes required for spend-committing operations in 4.0.
- Release policy: majors at least 18 months apart, 4.0 targeted for early 2027, a previous major receiving security patches for at least 12 months after its successor, and deprecations announced at least six months before removal.
- AdCP Verified independent auditing, signals-protocol maturity, registry adoption, SDKs, and reference implementations.

### Migrating 3.1 → 3.2 — the checklist

A 3.1 seller keeps working untouched: 3.2 is additive apart from the recorded exceptions, and a 3.2 buyer downshifts to an advertised 3.1 release. The guide names two buyer-side exceptions, signed requests to an endpoint that adds 3.2 and strictly typed 3.1 parsers on 3.2 shapes. “Migrating” means *claiming* 3.2; each step below comes from the upgrade checklist in the 3.1→3.2 migration guide (source: AdCP official 3.1→3.2 migration guide on main (GA revision, September 30, 2026) and the versioning reference’s “3.2 exceptions to 3.x compatibility”), where the hard requirements are exact advertisement and echo, media_buy_status, the 3.2 signing profile, error.recovery and integer retry_after, and the rollout order and reporting changes are its recommended practice. The one step to settle before you claim anything is signing: adding "3.2" to a shared endpoint changes the verifier for every signed caller on it.

- **Upgrade the SDK, keep the pin —** Move to a 3.2 SDK line with the wire pin still at "3.1", deploy and verify, then opt into "3.2" one peer at a time after each peer advertises it; existing "3.1" traffic keeps working.
- **Advertise and echo exactly —** Sellers advertise "3.2" in supported_versions only when they serve it, keep every earlier release they still serve, and echo the served release; buyers send "3.2" only to peers that advertise it and replace any "3.2-rc.N" pin, which never resolves to "3.2".
- **Read media_buy_status —** Create and update success carry media_buy_status and no body-level status; root status is the task-envelope state.
- **Re-encode signatures —** On any endpoint that advertises 3.2 and supports signing, every signed request with a body covers content-digest, and Signature and Content-Digest values are RFC 8941 padded Base64. The endpoint selects the profile, so a 3.1-profile signer is rejected there even on a "3.1" pin: separate the endpoint or coordinate the cutover first.
- **Make errors self-describing —** error.recovery on every error and an integer retry_after; buyers classify on recovery, fall back to the code registry when it is absent, and apply retry_after only to transient errors.
- **Gate the new controls —** Compact tools on media_buy.lifecycle_tools, the root frequency_cap on aggregate_frequency_capping, shared budgets on seller_optimized_budget and its sub-capabilities, outcome targets on media_buy.outcome_target (the key the 3.2.1 storyboard gates on); reject an undeclared frequency cap, package control or outcome target with UNSUPPORTED_FEATURE.
- **Fix the shapes 3.2 rejects —** create_media_buy takes packages, or proposal_id plus total_budget, not both and not neither; total_budget.currency is uppercase ISO; preview_creative takes a manifest or a creative_id; sync_governance registers Bearer as the only authentication scheme; a dated or windowed delivery request spanning more than one reporting timezone is rejected with VALIDATION_ERROR, and dates read as calendar dates in the echoed reporting timezone.
- **Certify on the 3.2 bundle —** Grade 3.2 claims against the 3.2 compliance bundle — 3.2.1 per the guide; the registry's one 3.2 agent was graded on 3.2.2 from October 5, on 3.2.3 from October 8 and on 3.2.4 from October 13. The docs name @adcp/sdk 14.0.0 or adcp 8.0.0 for it, both published on October 1 (npm adcp-3.2 is 14.4.0, still declaring 3.2.1 and listed as affected by the 3.2.3 advisory, and latest 15.9.0, declaring 3.2.4, as of 22:15 UTC on October 13), and hosted grading has graded agents that advertise 3.2 on the 3.2 bundle since #7841 (merged 14:58 UTC that day); the first public 3.2 run landed at 21:48 UTC on October 1.

### Migrating 3.0 → 3.1 — the checklist (still the floor for the 3.1 line)

A 3.0 integration keeps working untouched — 3.1 is additive at the wire. “Migrating” means *claiming* 3.1, and each step below is a real obligation (per the 3.0→3.1 migration guide (source: AdCP official 3.0→3.1 migration guide + adcp-go SDK release notes)), not optional polish. Backward compatibility is “mostly”: 3.0 clients are not broken, but adoption plus the Go SDK upgrade impose real changes — plan it.

- **Advertise versions —** Return supported_versions[] from get_adcp_capabilities and echo the served version at the envelope root; make transports tolerate unknown envelope-root fields (this replaces prior reject-on-unknown validation).
- **Sign brand verification —** If you implement verify_brand_claim(s), return a signed (JWS) response bound to the task, resolved tenant, agent URL, and freshness window.
- **Adopt canonical creative —** Move creative metadata to the canonical format_kind set and discover build units through the new list_transformers catalog; format-attached pricing moves to the transformer.
- **Fix typed fields —** trademarks[].status must be a typed enum and trademarks[].countries ISO 3166-1 alpha-2 — former free-text values now error; add the now-required cache_scope on get_products and get_signals.
- **Require idempotency —** Send idempotency_key on every state-mutating request (sellers may reject missing keys there; reads keep it optional as of v3.1.21); treat IDEMPOTENCY_IN_FLIGHT as transient rather than minting a fresh key.
- **Upgrade the SDK, then certify —** The Go SDK (adcp-go) has breaking type changes — re-decode against the new shapes; it is not a drop-in. Then pass the 3.1 compliance storyboard bundle to earn the 3.1 badge.

*From the implementer seat*

## Contributions to the protocol.

This page is written from inside the work: No Fluff Advisory builds and operates a [live AdCP signals agent](https://nofluffadvisory.com/building/adcp-signals-adaptor/) (listed in the AAO registry) with all-pass conformance runs across the AdCP 3.0 and 3.1 GA suites (58 of 58 scenarios on the tracks run in the hosted 3.1.24 grade of 13:13 UTC on October 13), and co-leads the Signals & Measurement working group. For the live state of the registry itself — every registered agent, its actual tool catalog, and real request/response captures — see the [AdCP Ecosystem Tracker](https://nofluffadvisory.com/adcp-registry/). For the buy side of the same protocol run end to end — discovery, audience targeting, brief, media buy, creatives, the human gate, delivery reporting — with every call copy-pasteable against a live seller agent, see the [AdCP Buyer’s Guide](https://nofluffadvisory.com/adcp-buyers-guide/).

### Merged into the protocol & tooling

- **last_updated on signal-definition** — schema field for verifiable signal-record freshness ([#5248](https://github.com/adcontextprotocol/adcp/issues/5248) → [PR #5249](https://github.com/adcontextprotocol/adcp/pull/5249), in the 3.1.0 line since 3.1.0-rc.7).
- **Root-cause diagnostics for the conformance runner** — a schema-invalid `get_adcp_capabilities` response used to surface as N unrelated track failures with nothing linking them; reported it ([#6254](https://github.com/adcontextprotocol/adcp/issues/6254)) and wrote the protocol-side contract, which now defines the `capabilities_response_schema_invalid` notice and an RFC 6901 `capability_pointer` field so one cause is reported once, ahead of the results it explains ([PR #6256](https://github.com/adcontextprotocol/adcp/pull/6256), merged August 8, 2026).
- **Runtime signal-quality attestations** — our RFC for verifier-signed signal-quality evidence on check_governance ([#5418](https://github.com/adcontextprotocol/adcp/issues/5418)) landed in the protocol's 3.2 line: `runtime_attestations[]` consuming the shared attestation primitive ([#4529](https://github.com/adcontextprotocol/adcp/issues/4529)), scoped to signal activation with GDPR/CCPA deactivation exempt, with response-side evaluations and binding digests ([PR #6218](https://github.com/adcontextprotocol/adcp/pull/6218), merged August 6, 2026).
- **Compliance-grader fix** — all-pass single-protocol runs rendered “Degraded” by a rollup regression; root-caused to the introducing commit, filed ([#5429](https://github.com/adcontextprotocol/adcp/issues/5429), triaged P0) and fixed ([PR #5444](https://github.com/adcontextprotocol/adcp/pull/5444), merged).
- **RFC 9421 webhook-signing default** — the inventory ([#4270](https://github.com/adcontextprotocol/adcp/issues/4270)) and draft PRs ([#4273](https://github.com/adcontextprotocol/adcp/pull/4273)/ [#4275](https://github.com/adcontextprotocol/adcp/pull/4275), closed in favor of the triage-generated PR the maintainer merged) that drove the 3.0.9 realignment away from the deprecated HMAC framing. The migration tracker ([#4205](https://github.com/adcontextprotocol/adcp/issues/4205)) closed completed on August 13, 2026: reframed as an on-ramp problem rather than an adoption threshold, with the docs and signing guide leading with RFC 9421 and no separate DRI left to assign.
- **A dense vector on the rung that means “don’t share the content”** — `context_signals.embedding` is the one field on Trusted Match's classified-output tier that can be partially inverted back to a user's own words, and on an `ai_assistant` property the “content environment” is one person's conversation turn. Filed against v3.1.21 with the inversion literature and two additive text edits ([#7393](https://github.com/adcontextprotocol/adcp/issues/7393)); shipped in [#7396](https://github.com/adcontextprotocol/adcp/pull/7396), which took the stricter route — a flat prohibition rather than the demonstrate-on-request carve-out I proposed — and added policy-filtering rules on `keywords` and `summary` that the issue had not asked for.
- **Context Match over-caching** — split out of the embedding issue at the triage's request, since it carried no privacy dependency: the recommended cache key was placement-only while responses vary with artifact, classified signals and geo, so a router could serve one session's decision against another's context ([#7414](https://github.com/adcontextprotocol/adcp/issues/7414)). The collision was fixed in [#7397](https://github.com/adcontextprotocol/adcp/pull/7397), which replaced the key with `{provider_id, context_hash}`, a SHA-256 over the forwarded request minus `$schema` and `request_id`. That PR was not a response to #7414. It closes [#7395](https://github.com/adcontextprotocol/adcp/issues/7395), which was filed under the maintainer’s account from the same #7393 review. Both were opened on September 10, 2026, more than 18 hours before I filed #7414. A bot-triage note marked #7414 blocked on #7397 four minutes after I filed it, and the issue was closed as not planned on September 13 with no comment. The `cache_ttl: 0` line did ship, by another route: the #7395 bot triage listed it, my September 10 review of #7397 flagged it as missing, and it was added on September 11. It went in as a hit-rate note (geo or per-session signals produce many distinct hashes), not the correctness SHOULD #7414 proposed, and the 3.1.x backport ([#7425](https://github.com/adcontextprotocol/adcp/pull/7425)) carried the same sentence into v3.1.22. The docs release-notes page goes further. Its Version 3.1.22 section, added by #7451 and first tagged in v3.1.23 (September 14, 2026), says Context Match router operators “affected by unsafe response caching MUST bypass or disable that caching until the router implements both request-aware partitioning and a trusted namespace for every result-affecting security and provider-configuration context.” Main [#7446](https://github.com/adcontextprotocol/adcp/pull/7446) would add that namespace as `cache_namespace`, with October 25, 2026 as the earliest date its enforcement can publish. On September 22, 2026 it was held out of the 3.2 RC5 cut for that reason: its own notice rules out enforcement before October 25, and RC5 comes first. The maintainer named two paths from here — a later 3.x minor once the notice period has run, or reshaping it into a notice-only or additive change — and on September 23, 2026 it was routed to 3.3.0 — bringing its minor changeset into the 3.2 candidate would have held GA until the notice floor, against a now-frozen train. We reviewed it independently at the maintainer’s request; with read-only permission here, that review could not clear the required-approval gate, and the hold does not turn on it.
- **Radio & static-OOH measurement parity** — scoped the two channels the delivery contract had no shape for ([#6138](https://github.com/adcontextprotocol/adcp/issues/6138), with Chris Williams), then filed the asks that came out of it: radio delivery-currency, meaning row-level `measurement_source` plus `nielsen_audio` notation ([#6139](https://github.com/adcontextprotocol/adcp/issues/6139)), and spot-level as-run for linear ([#5682](https://github.com/adcontextprotocol/adcp/issues/5682)). Every ratified decision is merged — `measurement_source` on delivery rows ([PR #6241](https://github.com/adcontextprotocol/adcp/pull/6241)), `nielsen_audio` with notation-vs-provider language and the radio reconciliation guide ([PR #6836](https://github.com/adcontextprotocol/adcp/pull/6836), field-name correction [PR #6856](https://github.com/adcontextprotocol/adcp/pull/6856)), reporting cadence extended to measured channels and then promoted to a normative MUST ([PR #6240](https://github.com/adcontextprotocol/adcp/pull/6240), [PR #6860](https://github.com/adcontextprotocol/adcp/pull/6860)), and spot-level as-run reporting ([PR #6574](https://github.com/adcontextprotocol/adcp/pull/6574)). Taxonomy graduation criteria split out to [#6261](https://github.com/adcontextprotocol/adcp/issues/6261) and closed when media channels went stable ([PR #6542](https://github.com/adcontextprotocol/adcp/pull/6542)). Implementations were maintainer-authored.
- **Eligibility you can read off the API** — `verified` was a bare boolean computed from badge rows, so a seller could not tell “declare specialisms” from “fix storyboards” from “membership tier” ([#6374](https://github.com/adcontextprotocol/adcp/issues/6374), split from #6363 because the bot triage there flagged it as a separate API-contract issue). Filed August 11, 2026 with our agent as the reproduction: zero failing storyboards, `verified: false`, and the real first-guard blocker — no declared specialisms, the #6303 taxonomy gap — surfaced by no public field. It sat ready-to-implement for six weeks and shipped on September 21, 2026 as [PR #7639](https://github.com/adcontextprotocol/adcp/pull/7639). It covers all three legs the filing named, with one design choice stricter than asked: the compliance response now carries an `eligibility` block with agent-level blockers (`no_declared_specialisms`) and per-role blockers (`storyboards_failing`, `storyboards_partial`, `storyboards_untested`), plus a versioned `criteria_version`; the membership-tier leg is split into a separate owner-scoped `eligibility_owner` that returns `eligible: null` to anyone else, since tier is commercial information. It is live, and on our own card it now reads exactly what the filing traced by hand through source: `blockers: [no_declared_specialisms]`, `roles: {}`. What it cannot do is make the blocker removable. The specialism we would need to declare does not exist — #6303, the gap for a publisher-direct, human-gated, fixed-price seller, has been on the 3.3.0 milestone since October 6, 2026, with draft #7963 proposing a `sales-fixed-rate` specialism for 3.3 — so the card now states the reason correctly and the reason still stands.

### Conformance suite, hardened

- Signals-only agents now skip non-applicable media-buy gating and gained dedicated error-handling / schema-validation storyboards ([#2916](https://github.com/adcontextprotocol/adcp/issues/2916), [#3350](https://github.com/adcontextprotocol/adcp/issues/3350), [#4009](https://github.com/adcontextprotocol/adcp/issues/4009) — fixed in the 3.1.0 suite; earlier [#2535](https://github.com/adcontextprotocol/adcp/issues/2535), [#3999](https://github.com/adcontextprotocol/adcp/issues/3999), [#4065](https://github.com/adcontextprotocol/adcp/issues/4065)).
- **An assertion no signals-only agent can satisfy** — `webhook_emission` 's synthetic `assert_contribution` step grades a branch set whose only contributors require `get_products`; a signals-only agent's contributors correctly skip as `missing_tool`, and the assertion then fails on the empty set as a `[core]` failure nothing on the agent side can clear. The storyboard's own `grading.pass_criteria` says those steps grade not-applicable, and a sibling storyboard already guards its assertion phase with `skip_if` ([adcp-client#2862](https://github.com/adcontextprotocol/adcp-client/issues/2862), filed with the runner's machine-readable failure record — `expected: [synchronous_completion_handled], actual: []` — as the reproduction). Fixed September 14, 2026 in [#7504](https://github.com/adcontextprotocol/adcp/pull/7504), which gated all three phases of the synchronous webhook-emission branch family on `media_buy.buying_modes` carrying `wholesale` and added a regression asserting that a signals-only agent grades the whole branch family `not_applicable` — the grading contract the filing argued from. Note where it landed: the runner's `assert_contribution` behaviour is preserved and the storyboard was gated instead, so the fix rides the spec repo rather than the SDK.
- **Reviewed with wire data** — the signal-definition epistemic / provenance layer ([#5017](https://github.com/adcontextprotocol/adcp/pull/5017), opened under the maintainer account): backed a progressive-disclosure concern that another reviewer had already raised, with three things: wire sizes from our signals agent (88,590 bytes for 5 signals against the 64 KB probe ceiling, pretty-printed — an estimated 60 KB compact — and carrying our own `x_*` extension blocks, most of each signal’s bytes by our posted breakdown, but none of #5017’s new fields), an estimate that those fields would add 3–5 KB per signal, and three ways to split discovery from lookup. Before the merge, the maintainer account added compact-by-default guidance and a `fields` selector on `get_signals`. Our field-level schema notes followed about an hour after the merge; the follow-up ([#5190](https://github.com/adcontextprotocol/adcp/pull/5190), merged May 30, 2026) addressed them, not always as proposed. Neither the pre-merge commits nor #5190 cites our comments, though the maintainer account introduced the selector commit as a follow-up “based on the progressive-disclosure discussion”, which our comment was part of.
- **A shared reference primitive that stayed a draft** — the signal epistemic-model RFC, opened under the maintainer account ([#4616](https://github.com/adcontextprotocol/adcp/issues/4616)), listed three decisions for the working group to make once. The first: should one reference primitive be reused across markets, ID graphs, taxonomies, measurement currencies and panel frames, or should each get its own per-dimension type? I filed a draft PR for the shared option, described in its own text as a discussion artifact rather than a merge bid. It proposed one `{system, value, version?, name?}` reference for values defined in external identity, taxonomy, geographic and measurement systems, plus a per-deployment fidelity enum and a conversion descriptor ([#4622](https://github.com/adcontextprotocol/adcp/pull/4622), opened May 16, 2026). One reviewer approved its second revision round the same day, after I folded in their suggestions; five more rounds followed. Review comments under the maintainer account on May 25, 2026 questioned the premise: calling these “systems” is confusing, “Not clear to me how this generalized system helps us”, and the conversion is not per-signal but happens at activation, across graphs held by several parties, with no one knowing how many times. One comment’s stated main point was to separate “what is this signal” from how it is connected to the delivery surface. The same day I narrowed the descriptions in a seventh round and offered to drop the conversion descriptor, or to close the PR if the rows it targeted turned out to need one dominant system each. The next comment under the maintainer account was the closing one, on May 30, 2026. It called the PR a discussion artifact rather than a merge candidate, said the system-reference idea “remains relevant” for concrete row-level work and should come back as a fresh, narrow PR once one of those rows is ready to adopt it, and said it “was not closed by #5017”, which had handled signal-definition enrichment without adopting these primitives. It was never merged, and none of its three schemas is on `main` as of September 16, 2026. Separately, on May 28 and 29, I had written on #5017 that “the per-dimension shape vs. shared-primitive question is resolved” and that its per-dimension direction was “the right one”. #4616 was closed on August 16, 2026 as completed, with a comment calling it superseded framing and saying the actionable signal epistemic decisions are now owned by concrete signal RFCs and implementation issues. Its text has marked the third decision “decided for 3.2” since August 4, 2026, and has never marked the reference-shape question decided.
- **Wholesale cache-scope isolation** — found that conditional-fetch tokens pass the suite even when a global token leaks across `cache_scope` layers; filed ([#5739](https://github.com/adcontextprotocol/adcp/issues/5739), bot-triaged ready-to-implement and milestoned 3.2.0) and implemented the fix — scope-isolation storyboards for signals and products, the schema MUST-NOTs, and the reference-agent correction ([PR #5748](https://github.com/adcontextprotocol/adcp/pull/5748), merged August 3, 2026).
- **Grader reliability** — evaluate_agent_quality returning identical scores across four runs including a force_refresh pass; filed with live wire evidence ([#6206](https://github.com/adcontextprotocol/adcp/issues/6206), bot-triaged same day: the silently-dropped `force_refresh` parameter confirmed as a real grader bug; the score-staleness root cause resolved agent-side, follow-up scoping in [#6233](https://github.com/adcontextprotocol/adcp/issues/6233)).
- **Storyboard-runner account resolution** — advertising `list_accounts` silently switches the runner into discovery mode, which then hard-fails as “ambiguous” on any multi-tenant roster instead of falling back to the natural-key path that exists a few lines above ([#6242](https://github.com/adcontextprotocol/adcp/issues/6242), triaged P0 and fixed — schema-default account routing and agency-operated brand matching shipped in `@adcp/sdk` 13.0.0-rc.11 via [adcp-client#2488](https://github.com/adcontextprotocol/adcp-client/issues/2488), with runner guidance in [#6289](https://github.com/adcontextprotocol/adcp/issues/6289); two implementers hit it independently), and the amplification pattern behind it — one schema-invalid capabilities response surfacing as N unrelated track failures ([#6254](https://github.com/adcontextprotocol/adcp/issues/6254); I first filed the link between the two as a separate issue by mistake, [#6255](https://github.com/adcontextprotocol/adcp/issues/6255), and closed it 98 seconds later on August 6, 2026 in favour of [a comment on #6242](https://github.com/adcontextprotocol/adcp/issues/6242#issuecomment-5209202619)).
- **3.1.11 harness regression** — the dynamic creative-asset directive shipped without its expansion step ordered ahead of the runner's own outbound validation, so conformant sellers were graded down on requests their agents never received ([#6267](https://github.com/adcontextprotocol/adcp/issues/6267), fixed; the affected track returned to a full pass on the first post-deploy regrade). Filed alongside the contract gap behind it — unbuildable asset slots were charged to the agent, and the storyboard contract contradicted itself on whether to fail the step or skip it — which resolved in the seller's favour: runner-owned coverage gaps now grade not-applicable rather than counting as failures, with the fixture set widened and slot-content guessing prohibited ([#6269](https://github.com/adcontextprotocol/adcp/issues/6269), fixed). Registry card rendering a stale tool count fixed alongside ([#6268](https://github.com/adcontextprotocol/adcp/issues/6268)).
- **Compliance reporting that hides its own verdict** — the badge is gated on storyboard-level results, but the API returned the summary count with an empty breakdown ([#6291](https://github.com/adcontextprotocol/adcp/issues/6291)) and a track could display every scenario passing while the verdict that actually gates the badge disagreed ([#6292](https://github.com/adcontextprotocol/adcp/issues/6292)) — both fixed and shipped together. Found while diagnosing why a live agent sat at 132/138 scenarios and no badge. Once the breakdown shipped it showed the card reporting a declared specialism as *failing* while the underlying record read untested with zero steps attempted and zero failures ([#6302](https://github.com/adcontextprotocol/adcp/issues/6302)) — a storyboard that had never run once being displayed as one that ran and failed.
- **A badge panel that names the wrong blocker** — the AAO Verified panel tells a seller to “fix the failing storyboards in this card” over a record reading 13 passing, 4 partial, 18 untested, and zero failing: every non-passing state renders as “failing” ([#6363](https://github.com/adcontextprotocol/adcp/issues/6363), bot-triaged as a classification bug, then fixed by a maintainer PR — the panel now names the actual blocking state).
- **Registry-migration QA — five filings in one morning** — probing the agenticadvertising.org migration surfaced: verified media-buy agents rendering “Not Verified” badges ([#6376](https://github.com/adcontextprotocol/adcp/issues/6376) — our hyphen/underscore hypothesis was superseded by the bot triage citing migration 502, which does bulk-revoke every 3.1 badge pending GA — the real cause, a migration that bulk-revoked every 3.1 badge pending GA); an unstructured badge-role error and an OpenAPI description still advertising roles that don’t exist, `sales` included ([#6377](https://github.com/adcontextprotocol/adcp/issues/6377), corrected mid-flight — the 400 does carry a body; our first probe read only the status code); the 200-plus-grey embed contract for unverified agents ([#6378](https://github.com/adcontextprotocol/adcp/issues/6378), resolved documented-intentional, with the `onerror` embed pattern to be deprecated in favour of the gate-on-verification pattern this site already ships); the hosted grader still running a superseded spec line hours after release — the operational sibling of #6321 ([#6379](https://github.com/adcontextprotocol/adcp/issues/6379)); and the CLI producing silent mixed-line runs, kit from 3.1.13 while storyboards resolve from bundled 3.1.11 with no consistency check ([#6380](https://github.com/adcontextprotocol/adcp/issues/6380), reproduced as a two-run diff that cost a full grading pass). A sixth followed the same afternoon when a requeue ran the 3.0.18 cache against this 3.1-only agent and flipped the public card to failing before any scenario executed: sellers migrating 3.0 → 3.1 have no self-serve way to update the compliance target, with the proposed fix of resolving it from advertised `supported_versions` on every health check ([#6383](https://github.com/adcontextprotocol/adcp/issues/6383)). All six closed within a day: the badge trio via [PR #6387](https://github.com/adcontextprotocol/adcp/pull/6387), the grader deployment after a version-manifest root-cause (#6379), the mixed-line CLI defect with a fail-closed line-inference fix ([adcp-client#2518](https://github.com/adcontextprotocol/adcp-client/pull/2518)), and the compliance-target trap with owner re-detection plus registry safeguards that refuse verdicts against untrusted fallback targets (#6422/#6426, closing #6383).
- **One runner deployment, six defects — attributed by controlled experiment** — a grader failure that would not reproduce locally was run to ground with a differential wire test: the same `get_products` call against the same database in the same minute returns the correct USD-pruned result with `filters.pricing_currencies` present and reproduces the grader's failure byte for byte without it, so the deployed runner is dropping the filter ([#6439](https://github.com/adcontextprotocol/adcp/issues/6439), carrying the runner-half question #6379's closure left open). The same stripping family surfaced `brand` sent on `list_accounts` while the published request schema defines no such field — the registry noticing agents for omitting a field the spec never told them exists ([#6437](https://github.com/adcontextprotocol/adcp/issues/6437)) — and the SDK validating capabilities against a 3.1.0-beta.7 enum that rejects scenario names its own 3.1.13 storyboards gate on ([adcp-client#2524](https://github.com/adcontextprotocol/adcp-client/issues/2524)). A dropped `sandbox` flag rounded out the family: the same account identity hashed to a second, configless account, root-caused by recomputing the tenancy-triple hash for field-subset variants and closed agent-side by seeding the triple from the resolved principal. Four runner defects, one deliberate decline, zero unattributed failures on the card.
- **SDK test-fixture bug** — the @adcp/sdk scenario suite's sync_creatives fixture fails the SDK's own request validation ([adcp-client#2443](https://github.com/adcontextprotocol/adcp-client/issues/2443), bot-triaged with a corrected fix and regression-test ask, both shipped in adcp-client#2463/#2473; blast radius scoped to the local scenario suite in [#6233](https://github.com/adcontextprotocol/adcp/issues/6233)).
- **Conformance steps no seller can pass** — three findings from taking one live agent from 147 to 240 passing steps. The storyboards mark validations `severity: advisory` and the spec says an advisory failure does not fail the step, but the runner implements none of that contract, so every validation on the stale-cache step is advisory and the step is unpassable by construction ([#6320](https://github.com/adcontextprotocol/adcp/issues/6320), triaged P0); a second instance of the same skip-graded-as-failure pattern turns up in the idempotency rate-limit step, which is doubly unreachable because its test kit is sandbox-scoped while the graded URL is production ([#6344](https://github.com/adcontextprotocol/adcp/issues/6344)). And a seller who declares `supported_billing: ['operator']` is asked for an error code that means the opposite of what is true — `BILLING_NOT_PERMITTED_FOR_AGENT` implies the mode exists and this agent may not use it, where the honest answer is that the mode is not offered at all ([#6343](https://github.com/adcontextprotocol/adcp/issues/6343)) — the same shape as the specialism gap below.
- **Grades sellers cannot reproduce** — the hosted grader ran compliance cache `3.1.12` while no published SDK carried it: `latest` shipped 3.1.5, the release candidate 3.1.11, and a step that passed locally failed on the grader with no way to see the storyboard that failed it ([#6321](https://github.com/adcontextprotocol/adcp/issues/6321), triaged P0; the merged fix gated the version resolver on published bundles). Found alongside a registry state machine that locks honest sellers out of grading entirely: a completed run rewrites the requested compliance target to whatever it just ran, so an agent that narrows its advertised `supported_versions` to the one version it actually supports then fails pre-flight against the older cache and is graded on nothing at all. Narrowing was the honest move and it took the public card from *degraded* to *failing*.
- **A storyboard that fails the path the spec prescribes** — a seller with no task layer is told by the spec to allocate the media buy id at commit and return synchronous success with `confirmed_at: null`, then the async storyboard grades that seller on a submitted-task envelope it was never meant to emit ([#6345](https://github.com/adcontextprotocol/adcp/issues/6345)). Triage first assumed omitting the controller scenario made the storyboard grade not-applicable; a live reproduction showed the force step grades not-applicable while the dependent step runs anyway and fails. Fixed: the storyboard now gates on the forcing scenario's advertisement and skips before any phase executes ([PR #6368](https://github.com/adcontextprotocol/adcp/pull/6368), merged), with the skip-misclassification the review surfaced corrected downstream in the SDK ([adcp-client#2511](https://github.com/adcontextprotocol/adcp-client/issues/2511)).
- **One filing withdrawn** — an argument that the audit-observation contract forced sellers to relay a verifier's verdict they never obtained ([#6322](https://github.com/adcontextprotocol/adcp/issues/6322)). The premise was wrong: the schema already separates the two, carrying what a submission *claimed* in one field and what a verifier *observed* in others, and the only permitted code says `CLAIMED`. Retracted with the correct reading ([#6323](https://github.com/adcontextprotocol/adcp/issues/6323)) and the feature built the honest way instead — recording the claim, attributing the observation to this agent, and leaving every verdict field empty.
- **53 of 62 failing steps on two public cards were ungradable** — the hosted grader admits a storyboard when *any* one of its `required_tools` is present, while the suite selector then required all of them, so `canonical_format_validate_input` was selected for agents with no `validate_input` and failed all 17 of its steps on each card. Separately, steps the SDK marks `not_applicable` were graded as failures on the hosted runner but skipped locally. Filed with both runner source lines and a local reproduction ([#7404](https://github.com/adcontextprotocol/adcp/issues/7404), bot-triaged P0); this was the second time the OR gate was fixed. The first was [#6773](https://github.com/adcontextprotocol/adcp/issues/6773) in August — `billing_gate_dispatch` listing `get_adcp_capabilities` beside `sync_accounts`, which every conformant agent satisfies, so signals-only agents were admitted and failed the first step instead of skipping. [#6774](https://github.com/adcontextprotocol/adcp/pull/6774) merged inside fourteen hours and review widened the one-line deletion to 17 storyboards. It landed on main only: the 3.1.x cherry-pick its own PR body called warranted was never made, so the storyboards kept mis-selecting on the 3.1.20 line the hosted grader ran until September 22, 2026. The September fix is that backport finally arriving — the storyboard half merged on September 14, 2026, [#7405](https://github.com/adcontextprotocol/adcp/pull/7405) on main and the 3.1.x backport [#7406](https://github.com/adcontextprotocol/adcp/pull/7406) twenty-one seconds later, this one written from here rather than upstream — and shipped the same afternoon in v3.1.23, whose changelog names the filing: agents without `validate_input` now take a coverage-gap skip. The second half has since moved. [#7454](https://github.com/adcontextprotocol/adcp/pull/7454), merged September 13, 2026 and linked in the thread that day, grades `fixture_seed_unsupported` and similar skip reasons as not applicable. On the signals card the two storyboards filed under this half, `deterministic_testing` and `idempotency`, have read `untested` at 0/0 since September 14. They are no longer failures, though not the passes the local SDK reports either. The September 14–16 runs also report `sdk_version` 14.0.0-rc.35, while #7454 was built against rc.33, so the shift cannot be credited to #7454 alone. A follow-up on September 15 missed that and argued the public feed could not represent a skipped step at all. The feed already could, and [a correction on September 16](https://github.com/adcontextprotocol/adcp/issues/7404#issuecomment-5695786953) says so. The issue was retitled at 10:15 UTC on September 16, 2026, three minutes after that correction, to “Hosted grader: 11 failing steps remain on two cards after #7454/#7405/#7406 (sales 10, signals 1); budget-truncated runs still published as complete grades”. The count matched both cards’ latest runs at the time; how much of the drop those three PRs caused is less clear. The sales card showed the 3.1.20 bundle (published September 2, before #7405 and #7406 merged) until 23:15 UTC on September 29, when an owner test re-graded it on 3.1.24 (see the governance entry below); it had not run since September 17, five days before the grader moved 3.1-line agents to 3.1.23. The signals card was re-graded by a heartbeat run at 20:56 UTC on September 29, on bundle 3.1.24 under @adcp/sdk 14.0.0-rc.50: 10 of its 38 storyboards passing, the other 28 untested, none partial or failing; `billing_gate_dispatch`, the last signals failure in this thread’s count (one step, in the September 16 retitle), reads `untested` at 0/0 steps. None of the ten sales failures is in a storyboard the filing named, and the 17 `canonical_format_validate_input` failures on the sales card cleared because this agent now implements `validate_input`. On truncation, the filing’s third report: the sales card’s two short runs on September 9 and 10, at 130 and 124 scenarios against 193 in a full run, still read `complete` and authoritative in the public history feed. [PR #7453](https://github.com/adcontextprotocol/adcp/pull/7453), merged September 13, 2026, stops runs the SDK marks `timed_out` from replacing the public grade; [PR #7506](https://github.com/adcontextprotocol/adcp/pull/7506), which would have done the same for runs that report no completeness at all, was closed unmerged on September 23, 2026, as superseded by [PR #7622](https://github.com/adcontextprotocol/adcp/pull/7622) (merged September 21). The gap it targeted is still open: on main, a run that reports no completeness is still recorded as `complete`.
- **Grades that cannot be attributed** — two heartbeats of the same agent build, with no deploy between them, disagreed by a scenario. Nothing in the public compliance feed identified the grader that ran them, so a runner that changed under you and a runner that is simply non-deterministic looked identical from outside. Asked for one field on each history entry ([#7429](https://github.com/adcontextprotocol/adcp/issues/7429)). It arrived by another route. [#7454](https://github.com/adcontextprotocol/adcp/pull/7454), merged September 13, 2026, writes a provenance block on each new history entry, including the exact SDK version, the compliance bundle and a grading-policy version. Runs graded before it was deployed carry none. [#7433](https://github.com/adcontextprotocol/adcp/pull/7433), a separate PR to persist the runner version, merged September 24, 2026 and closed #7429; history entries have carried `runner_capability_version` since.
- **A control that reports success and leaves no trace** — an owner requeue on September 7 produced no run and no history row, and the feed’s newest `owner_test` entry predated the click by 24 days. Filed as a two-way fork, silent no-op or ran-and-discarded-as-unchanged ([#7428](https://github.com/adcontextprotocol/adcp/issues/7428), bot-triaged bug and P1 eight minutes after filing). Closed as verified on September 15, 2026 with a third answer. *Requeue comply* only schedules the next heartbeat, by design; the click fell inside a 19.4-day window, August 19 to September 8, in which the registry graded the agent not at all, and on September 16, 2026 the feed still showed those 465.6 hours with no rows; and a fresh click with devtools open put three runs through admission to completion on September 13, which the maintainer confirmed end-to-end. The original click left no retained HTTP evidence, so its cause is unrecoverable, and the confirmation fixes triage scoped, a `last_rechecked_at` on the card and a flash that does not auto-dismiss, did not ship with the closure. One thing this filing should not claim: the requeue semantics were not a discovery. They were written down in [#4265](https://github.com/adcontextprotocol/adcp/pull/4265)’s body in May 2026 — the fix our own [#4253](https://github.com/adcontextprotocol/adcp/issues/4253) was closed against — where the endpoint is described as clearing `last_checked_at` so the agent is eligible on the next tick. We filed four months later against behaviour already documented in a thread we opened.
- **One gate, two meanings** — `required_tools` is read by two code paths that disagree: the suite selector excludes a storyboard when any listed tool is missing, the per-storyboard runner admits it when any listed tool is present. A storyboard naming two tools against an agent holding one is therefore skipped by the first and admitted-then-failed by the second. Filed after the same defect recurred on a line an earlier data fix had not reached — [adcp-client#2652](https://github.com/adcontextprotocol/adcp-client/issues/2652) was closed on the strength of a storyboard-side change, and `billing_gate_dispatch` mis-selected again four weeks later on 3.1.20 ([adcp-client#2882](https://github.com/adcontextprotocol/adcp-client/issues/2882), bot-triaged bug / conformance / ready-for-human). The bot triage confirmed the divergence against published 13.0.2 and the convergence already written in `comply.ts`, and put the choice of semantic to the maintainer, who shipped any-of rather than all-of, which is only safe because the storyboard-side fixes strip the universal capability tool from `required_tools` first. It shipped in 13.0.4 on September 14, 2026 (`comply.js:600` now reads `required.some(…)`) and the issue closed the same day. Against the sales agent the change is measurable: 305 storyboards selected on 13.0.2 became 348 on 13.0.4 with byte-identical caches, so the delta is the selector alone, and four of the newly admitted storyboards fail.
- **A grader that disagrees with itself between two of its own commands** — since `@adcp/sdk` 13.0.3, `storyboard run` grades every `response_schema` check on a `comply_test_controller` step as failed with `no_schema_registered`, while `storyboard step` passes the identical step seconds later on the same SDK with the schema id resolved. The agent's response is conformant either way — the controller arms and echoes the forced task id ([adcp-client#2867](https://github.com/adcontextprotocol/adcp-client/issues/2867)). It was the reason both of our agents stayed pinned to 13.0.2 rather than tracking `latest` — the newer build could not grade its own controller surface. Root-caused by the bot triage to `isExternalResponseSchemaAuthoritative` treating a test-harness tool like a protocol tool, fixed in adcp-client#2894 on the 13.x line, released in 13.0.4 on September 14 and closed the same day. Both agents moved to 13.0.4; on September 29 the sales agent’s local runner moved on to 13.1.2, the first stable build to bundle 3.1.24, and the signals adaptor followed to 13.1.3 on October 6, 2026, re-running the suite on 3.1.24 (55 of 55 scenarios, 0 failed steps).
- **A gate graded by the wrong principal** — the hosted grader’s September 29, 2026 owner test reported `comply_controller_mode_gate`: expected `FORBIDDEN` for the live-mode account check, received `NOT_FOUND`. The gate was right. Production answers the storyboard’s declared live kit with `FORBIDDEN` and echoes the correlation id, verified by direct call; the hosted *suite* path substitutes the run’s own sandbox bearer into the run-level test kit, and the SDK’s `resolveDeclaredTestKit` never loads a storyboard’s declared kit when a run-level one is present, so the step ran as a sandbox principal and found no creative. [#6735](https://github.com/adcontextprotocol/adcp/issues/6735) had fixed the four single-storyboard call sites and left the suite path alone. Filed as [#7772](https://github.com/adcontextprotocol/adcp/issues/7772) on September 30 at 01:35 UTC, with a regression test on our side that pins the transport-level cause ([nofluffadvisory#79](https://github.com/EvgenyAndroid/nofluffadvisory/pull/79)) rather than a change to a gate that was already correct. Triaged P0 nine minutes later; the bot’s code reviewer corrected the proposed server-side fix — the suite iterates storyboards inside the SDK, so there was no per-storyboard hook to mirror — which we accepted, offering an SDK rule (a declared `sandbox: false` kit wins over the run-level kit) as the smaller change. The maintainer shipped a server-side route instead: [#7808](https://github.com/adcontextprotocol/adcp/pull/7808) adds `liveModeTestKitRoute`, which sends a storyboard’s `from_test_kit` steps with the declared live-mode kit’s key against the agent under test, with a unit test named for this issue, merged October 1 at 11:05 UTC, thirty-three and a half hours from filing to merged fix. The public card lists the storyboard as untested before and after, an optional phase it never counted; the receipt that carried the wrong verdict is owner-only.
- **A warning the graded line prints and the hosted grader does not** — moving the signals adaptor to `@adcp/sdk` 13.1.3 (the current `adcp-3.1` build; 3.1.24 bundled since 13.1.2) opened the run with a schema advisory: `compliance_testing.scenarios` “must be one of” the six 3.0 controller scenarios, rejecting `force_get_signals_arm` and `force_task_completion`, which the runner’s own signals storyboard requires and the 3.1 schema explicitly allows. The cause is not the schema. The 13.x discovery probe runs with a major-only envelope, its transport-level validator therefore selects the 3.0 line, and it prints the result unconditionally; the profile-level check re-validates the same payload against 3.1.24 and passes, so the structured result is clean, and the hosted grader’s lines — 14.x, then 15.0.0 and 15.2.0 from October 9 and 15.8.1 from October 12 (as of 22:15 UTC on October 13) — discover pinned-first and gate that output, which a 14.2.0 run confirmed by printing nothing. Filed as [adcp-client#3124](https://github.com/adcontextprotocol/adcp-client/issues/3124) on October 6, 2026 with a one-hunk ask: backport to 13.x the console gate and version label that [adcp-client#2603](https://github.com/adcontextprotocol/adcp-client/pull/2603) put on `main` in August. Worth recording how the filing changed under verification: the first draft called it a spec enum gap and blamed the hosted grader; three verification passes showed the enum is the 3.0 line’s own, that [adcp-client#3042](https://github.com/adcontextprotocol/adcp-client/pull/3042) kept the selection deliberately, with a code comment saying so, and that only the console output on 13.x was ever wrong. Triaged fourteen minutes after filing: a bug, ready to implement, the one-hunk backport accepted as written and the response-driven selection to be scoped separately, which it now is as [adcp-client#3125](https://github.com/adcontextprotocol/adcp-client/issues/3125): change only the local validation line in `validateResponseSchema`, take it from the response’s own `adcp_version`, and leave the function the triage flagged alone.
- **A Strict grade that failed on one optional step, and two rollups no agent can pass** — the registry’s Strict Spec grading profile, which an owner can select in place of Legacy, failed this site’s signals agent on a single step: `deny_live_caller` in the universal `comply_controller_mode_gate` storyboard. Since #7808 (October 1), the fix for our #7772 above, the hosted grader sends that step with the storyboard’s declared live-mode test-kit key, and a single-endpoint seller that exposes `comply_test_controller` MUST refuse it with `FORBIDDEN`; the signals agent answered 401 at its auth gate. The phase is optional and the public card never counted it (the storyboard reads untested, 0 of 0, before and after the fix), but Strict fails on any recorded step failure in a universal storyboard. The live-caller refusal shipped on October 9, 2026 ([adcp-signals-adaptor#340](https://github.com/EvgenyAndroid/adcp-signals-adaptor/pull/340)): the live-mode key now gets `FORBIDDEN`, and the owner diagnostics for the 17:53 UTC owner test that followed list no failures. As of 22:15 UTC on October 13 Strict cannot read passing for any agent: two bugs we filed the same day, both open, each block every agent on their own. The universal bundles that contain no storyboards (three on 3.1.24, six on 3.2.3) always roll up untested ([adcp-client#3185](https://github.com/adcontextprotocol/adcp-client/issues/3185)), and a storyboard that never touches a lifecycle resource (a media buy, creative, account and the like) is capped at partial even when every step passes, which catches `capability_discovery` for every agent and the signals baseline for every signals agent ([adcp-client#3186](https://github.com/adcontextprotocol/adcp-client/issues/3186)). Fixing both would still leave this agent short, as #3186 itself notes: a storyboard whose required tools the agent lacks is graded partial outright, which caps 20 of the 38 universal bundles on its run. Both were triaged as bugs, ready to implement, within five minutes of filing. A third filing from that afternoon, [adcp-client#3181](https://github.com/adcontextprotocol/adcp-client/issues/3181), was triaged the same way fourteen minutes after it went up: the storyboard request builder adds a `bid_price` to fixed-price CPM creates, which is why the draft `sales-fixed-rate` storyboard prices its fixture on CPP.
- **A heartbeat that had not run in four days, and the question that stayed open** — the dashboard advertised a recheck cadence it was not keeping: no scheduled run against the signals agent in four days while a manual evaluation of the same agent passed 30 of 30 ([#4253](https://github.com/adcontextprotocol/adcp/issues/4253)). [#4265](https://github.com/adcontextprotocol/adcp/pull/4265) shipped three causes the next day — `last_checked_at` was stamped before `comply()` ran, so a crash inside the window silenced the agent for up to 12 hours a cycle; every heartbeat row was written `dry_run: true` and so never reached the dashboard; and manual runs wrote only to a table the dashboard does not read. Two asks did not ship: the last-automated versus last-manual distinction, and an answer to why the tick itself had not fired. The closing comment carved that second one out as a known follow-up — a scheduler concurrency limit of five against an unbounded wait queue, where five hung jobs block the heartbeat indefinitely — deferred until production diagnostics existed. By September 15, 2026 a stall of that shape showed fleet-wide: across all 35 registered agents, heartbeat runs went from 25–36 a day over September 8–13 to six on the 14th and one on the 15th, with no heartbeat anywhere in the registry for fourteen hours and 30 of the 31 agents with a heartbeat on record past a day since their last. Filed with the fleet numbers as [#7546](https://github.com/adcontextprotocol/adcp/issues/7546), pointing at the follow-up rather than asserting it. The filed sweep missed one of the 35 feeds, so the issue shows five and 29 of 30. Bot-triaged seven minutes later as a bug, `priority:P0`, P0 Bugs milestone, ready-to-implement. Its code-reviewer read `scheduler.ts` as confirming the mechanism, with `releaseSlot()` in a `finally` that does not run until the job’s promise settles: “Five hung jobs = five permanently occupied slots = everything else waits forever.” The fix it named is a `Promise.race` timeout in `runJob`, with a queue-depth cap as secondary hardening; the triage’s other expert recommended pulling `/internal/jobs` first to identify the stuck slots. The fix merged at 17:09 UTC on September 16, 2026 as [#7556](https://github.com/adcontextprotocol/adcp/pull/7556), opened under the maintainer account, and #7546 closed as completed one second later. It is the `Promise.race` timeout the triage named, made opt-in: a scheduled job can set `executionTimeoutMs`, and when that expires the scheduler signals the run to stop through an `AbortSignal` and stops waiting on it, so the `finally` holding `releaseSlot()` runs even if the job never settles. Only the compliance heartbeat opts in, at two hours against a documented worst case of about 115 minutes; it passes the signal into the SDK run, checks it before each agent, and, when an aborted run throws, stops before recording a failure against the agent it was testing. The job status behind `/internal/jobs` now reports `activeJobs`, `queuedJobs` and `maxConcurrency`; neither this PR nor its 3.1.x backport adds the queue-depth cap. The repository’s Deploy workflow reports a successful Fly.io deploy of the merge commit, completed at 17:38 UTC, and two more of `main` that include it, completed at 17:55 and 21:05 UTC. The 3.1.x backport, [#7557](https://github.com/adcontextprotocol/adcp/pull/7557), merged at 19:05 UTC the same day and carries over the guard `main` already had against a job overlapping its own previous run. The 35 public compliance feeds list only complete, authoritative runs, and since [#7453](https://github.com/adcontextprotocol/adcp/pull/7453) a timed-out run is kept as audit evidence without changing the public grade; the heartbeat also tests crawler-discovered agents outside the public listing. So the feeds bound the heartbeats that finished on these 35 agents, not the ones attempted or the ones run on other agents. In them, after one heartbeat on September 15, two appear on the 16th, at 18:19 and 18:23 UTC, on two agents, neither of them mine, and none after those through 12:46 UTC on September 17; the feeds do not show whether those two runs owe anything to the fix. Of the 31 agents with a heartbeat on record, 29 are more than two days past their last one. In those feeds, as of 12:46 UTC on September 17, my two agents had no heartbeat since the merge: their last were at 20:03 UTC on September 14 (signals) and 02:43 UTC on September 13 (sales), and their newest runs were owner-triggered, at 09:52 UTC on September 16 and 11:41 UTC on September 17. A follow-up on #7546 at 11:01 UTC on September 17, 2026 set out these public numbers with the same caveat and asked what the jobs status endpoint shows.
- **A heartbeat schedule our own owner tests re-armed, and a premise we got wrong** — every authoritative compliance run re-armed the heartbeat schedule, owner tests included: the `schedule_next` CTE in `recordComplianceRun` set `next_compliance_check_at` to the time of the run plus `check_interval_hours`, 12 by default, and cleared `requeued_at` without looking at `triggered_by`. A full-suite owner test therefore cancelled a pending requeue and put the next heartbeat a full interval after the test ([#7680](https://github.com/adcontextprotocol/adcp/issues/7680), filed September 24, 2026, bot-triaged P1). The filing said that both agents at the centre of [#7355](https://github.com/adcontextprotocol/adcp/issues/7355) are this site’s, among the most owner-tested in the registry, and that we generated that traffic, which skewed the sample there; it kept the mechanism separate from #7355’s throughput question. The first triage took the second of our two suggested fixes, scoped as a gate on `requeued_at IS NULL`. [Eight minutes later we showed](https://github.com/adcontextprotocol/adcp/issues/7680#issuecomment-5818532540) that our suggestion broke either way it was read. As scoped, it would make a requeue permanent: the CTE was the only place `requeued_at` was cleared, so the agent would stay due and sort first in every batch. Copied literally, the guard we had pointed to would stop every heartbeat from advancing the cadence. The triage was rewritten at 17:06 UTC with the shape we had argued for, a `triggered_by` gate, but a different predicate: we proposed `= 'heartbeat'`, it chose `!= 'owner_test'` so that `manual` and `webhook` runs still advance the cadence. On the fix, [PR #7691](https://github.com/adcontextprotocol/adcp/pull/7691) from another contributor, we argued for `= 'heartbeat'` again as the fail-closed choice, on the premise that `triggered_by` was an unvalidated string. The premise was wrong. We had cited three places. Two, [`compliance-db.ts:1294`](https://github.com/adcontextprotocol/adcp/blob/1319a78a1c867143d3734cf557daabb16d7a5409/server/src/db/compliance-db.ts#L1294) and [`registry.ts:1511`](https://github.com/adcontextprotocol/adcp/blob/1319a78a1c867143d3734cf557daabb16d7a5409/server/src/schemas/registry.ts#L1511), are read shapes; the third, [`registry-api.ts:8730`](https://github.com/adcontextprotocol/adcp/blob/1319a78a1c867143d3734cf557daabb16d7a5409/server/src/routes/registry-api.ts#L8730), passes through a request field typed `'owner_test' | 'manual'` at [`compliance-refresh-requests-db.ts:16`](https://github.com/adcontextprotocol/adcp/blob/1319a78a1c867143d3734cf557daabb16d7a5409/server/src/db/compliance-refresh-requests-db.ts#L16). The write input, [`compliance-db.ts:301`](https://github.com/adcontextprotocol/adcp/blob/1319a78a1c867143d3734cf557daabb16d7a5409/server/src/db/compliance-db.ts#L301), is typed by the `TriggeredBy` union at [`:22`](https://github.com/adcontextprotocol/adcp/blob/1319a78a1c867143d3734cf557daabb16d7a5409/server/src/db/compliance-db.ts#L22), which also declares `webhook`, a value we had said appeared nowhere. The maintainer account pointed to the union, and [we retracted](https://github.com/adcontextprotocol/adcp/pull/7691#issuecomment-5838586706) six minutes later, naming only the first two citations. The PR author also handled the first-run `INSERT`, which our filing had left out and the triage had deferred as a follow-up, with a `CASE` on the same literal as the `WHERE`. What held from our side was that the two have to change together; the same reply called that catch important, and [the shipped code comment](https://github.com/adcontextprotocol/adcp/blob/a4003bd7ac6b1889047ab828156af09dddf41f92/server/src/db/compliance-db.ts#L966-L977) now says so. #7691 never merged. The same SQL and test matrix landed inside the maintainer’s [PR #7969](https://github.com/adcontextprotocol/adcp/pull/7969) (“fix(runtime): persist replay claims and preserve heartbeat cadence”), whose description says it includes the scheduling fix from #7691. It merged at 10:40 UTC on October 9, 2026, and #7691 was closed as superseded the same minute. #7680 stayed open until 09:45 UTC on October 13, 2026, when the maintainer [closed it](https://github.com/adcontextprotocol/adcp/issues/7680#issuecomment-6142815658) with before-and-after evidence from this site’s sales agent: a heartbeat at 09:44 UTC on October 10, an owner test at 17:42 and the next heartbeat at 22:10, on its 12-hour cadence, where before the fix the owner test would have moved it to about 05:42 the next morning. The public history shows the same three runs. The same comment credits the fleet’s recovery to [PR #7844](https://github.com/adcontextprotocol/adcp/pull/7844) on October 1, not to this fix. The companion filing, [#7693](https://github.com/adcontextprotocol/adcp/issues/7693) (September 25, 2026), argues that no floor on heartbeat staleness can be keyed safely while `next_compliance_check_at` holds three states at once: the cadence, an in-flight batch lock and a skip deferral. It was bot-triaged P1 and ready to implement, with every skip site writing a new `last_heartbeat_attempt_at` and the floor keyed on that same column, so the floor could never fire for the skip-starved agents it exists for. [We said so](https://github.com/adcontextprotocol/adcp/issues/7693#issuecomment-5838593088), and two minutes later the triage was amended to key the floor on a new `last_heartbeat_success_at`. In that comment we also withdrew our own sequencing, which had the floor waiting on a platform-side request to expose queue state. As of 22:15 UTC on October 13, 2026 none of #7693 is built: there is no PR, and `main` still writes the batch lock into [`next_compliance_check_at`](https://github.com/adcontextprotocol/adcp/blob/110adf30ffb1f2807d1683d2608da00fd512a2f1/server/src/addie/jobs/compliance-heartbeat.ts#L174-L178). At 09:45 UTC the same day #7355 was [re-scoped](https://github.com/adcontextprotocol/adcp/issues/7355#issuecomment-6142816730) to heartbeat throughput falling since October 3, and its list of multi-day gaps includes this site’s signals agent: 102 hours without a completed heartbeat in the public history, from 16:52 UTC on October 8 to 23:08 UTC on October 12. The only completed run the public history shows inside that gap is an owner test at 17:53 UTC on October 9, 25 hours after the last heartbeat and already 13 hours past the 12-hour cadence. #7969 was in production by then: the Deploy workflow’s Fly deploy of a later `main` that contains it finished at 15:43 UTC that day ([run 37947767784](https://github.com/adcontextprotocol/adcp/actions/runs/37947767784), marked failed by an artifact-upload step that ran after the deploy), so that owner test left the schedule alone, and #7680 does not account for the gap. As of 22:15 UTC on October 13 the maintainer has not attributed it; the next step he names is #7844’s queue diagnostic against production.
- **Request-signature verification shipped (test keys only), output schemas of ours that degraded the card for 14 hours, and a suite that contradicts itself for a signing seller** — the signals agent has verified RFC 9421 request signatures since October 10, 2026 ([adcp-signals-adaptor#342](https://github.com/EvgenyAndroid/adcp-signals-adaptor/pull/342)): it advertises `request_signing.supported: true` with `covers_content_digest: "either"` and empty `required_for`, `warn_for` and `supported_for` lists, trusts only the public conformance test keys, and treats a verified signature as a sandbox caller, never a live one. A run of the 15.2.0 runner from here against production at 21:27 UTC on October 10, right after the merge, passed `signed_requests` 28 of 28. The first hosted grade after it was the heartbeat at 23:08 UTC on October 12 (runner 15.8.1, bundle 3.1.24): the public history shows 3 of 3 scenarios passed on its `security_transport` track, which the October 9 owner test had skipped, and per the owner diagnostics `signed_requests` passed 28 of 28. The same heartbeat took the card from passing to degraded, and the fault was ours. The runner’s MCP client (`@modelcontextprotocol/sdk` 1.32.1) checks a result’s `structuredContent` against the tool’s declared `outputSchema`, error results included, once it has cached the tool list, and the 15.8.1 runner caches it. Our schemas had not kept up with our payloads: `get_signals` still required the v2 `count` field that our own payload dropped when it moved to the 3.1 shape, so every call failed with MCP error -32602 and the `signal_owned` badge storyboard went partial; four more tools declared schemas no error result could match, and `activate_signal` ’s rejected its own success result as well. The run read core 37 of 38 scenarios, signals 5 of 9 and error handling 4 of 8. None of our tool schemas had changed since September 8 (#341 to #343, merged between the passing October 9 owner test and this heartbeat, did not touch them), and our own runs on 15.2.0, the post-merge production run included, passed without exercising that check. The heartbeat at 11:18 UTC on October 13 still ran the old code and read partial again. The fix ([adcp-signals-adaptor#344](https://github.com/EvgenyAndroid/adcp-signals-adaptor/pull/344), merged 11:28 UTC) makes every output schema either the tool’s real success shapes or the error envelope, and an owner test through Addie’s `evaluate_agent_quality` at 13:13 UTC on October 13, under 15.8.1, read passing about 14 hours after the card degraded: 11 of 38 storyboards, up from 10 before signing, all 58 scenarios on the four tracks it ran (the media-buy and creative tracks were skipped), `signed_requests` and `signal_owned` among the passes, the Legacy signals badges intact and the streak reset to zero. As of 22:15 UTC on October 13, of the 36 registered agents only this one’s card records a `signed_requests` pass (Triton Digital’s reads partial, 3 of 29 steps). Signing also produced four filings on October 13. Three are against the SDK, and as of 22:15 UTC on October 13 none is triaged: the 13.x runner grades `signed_requests` vectors 001, 007, 018 and 028 against a signing posture the agent never declared and fails in-library vector 025 for every agent, because three fixes from `main` were not backported ([adcp-client#3241](https://github.com/adcontextprotocol/adcp-client/issues/3241)); `verifyRequestSignature` accepts any nonce and runs the step-14 duplicate-key check before the step-13 replay insert ([adcp-client#3242](https://github.com/adcontextprotocol/adcp-client/issues/3242)), and our own verifier, built on 13.1.3, has the first of those gaps, which we shipped knowingly on October 10, while its card reads 28 of 28, because no vector bundled with SDK 15.9.0 (3.0.25, 3.1.24 and 3.2.4) tests the nonce rule; and every valid ES256 signature fails verification in workerd, the Cloudflare Workers runtime the adaptor runs on, which is why it carries a crypto shim ([adcp-client#3243](https://github.com/adcontextprotocol/adcp-client/issues/3243)). The fourth is [evidence on adcp#7563](https://github.com/adcontextprotocol/adcp/issues/7563#issuecomment-6148690383): the 3.1.24 suite contradicts itself for a seller that supports request signing, because vector 027 requires a 401 for an unsigned request carrying `push_notification_config.authentication` and `media_buy_seller` ’s create step sends exactly that request, unsigned; by our reading, not a run, draft [#8064](https://github.com/adcontextprotocol/adcp/pull/8064) as written would move the conflict onto sellers that set `legacy_hmac_fallback: false` rather than remove it. That is why the sales agent’s signing build, which passes `signed_requests` 28 of 28 locally and then fails that create, is on hold. None of this is graded on 3.2: both cards grade on 3.1.24, and the v3.2.4 signing vectors (026’s new expected code, negatives 029 to 031, the profile-3.2 mirrors) apply only once an agent claims 3.2.
- **A field the 3.1 schema requires and two governance storyboards never send** — on the 3.1 line, `governance_approved` and `governance_conditions` register a governance agent on the account, then call `create_media_buy` without `plan_id`, which the request schema from 3.1.20 through v3.1.23 says is “Required when the account has `governance_agents` ”. The seller has no other key for the approval call: the 3.1 `check_governance` requires `plan_id` and tells governance agents to reject a sibling `account` field ([#7547](https://github.com/adcontextprotocol/adcp/issues/7547), filed September 15, 2026). The sales agent shipped delegated governance that day — `sync_governance`, a `check_governance` call before commit, `governance_aware: true` — and a registration on the shared sandbox test account is permanent, so every `create_media_buy` on that account started to require `plan_id`. Six storyboards went red: the two named here; the base `media_buy_seller` storyboard, which registers an agent in its own setup phase and then buys without `plan_id`; and three that never ask for governance and only reuse the account. The full local suite (`@adcp/sdk` 13.0.4, bundle 3.1.20) read 246 steps passed and 8 failed, with Reporting & Delivery down to 7 of 17 scenarios. The filing argues that an agent declaring `governance_aware` cannot accept such a buy and skip the call. About an hour and a half after shipping, this one stopped declaring it. One constant, `GOVERNANCE_DELEGATION_ENABLED = false`, turns off the call and the tool: `sync_governance` is off `tools/list` and refused with `UNSUPPORTED_FEATURE`. A test fails if `governance_aware`, now `false`, disagrees with the constant. A buy on the registered account now goes through without `plan_id` and without calling the agent, then waits for human approval like every buy on this agent. The suite went to 259 passed and 2 failed (`post_sivt` and `sync_creatives_contradicted`, both intentional). Bot-triaged P0 on September 15, at first with two options put to the maintainer: A, add `plan_id: "$context.plan_id"` to both storyboards; B, move `main` ’s deprecation of `plan_id`, in favour of `governance_context`, into the next 3.1.x patch. Our follow-up, under an hour after the switch-off, checked A against the shipped 3.1.20 bundle. Each file there has one `context_outputs` block, owned by `get_products_brief`, so `$context.plan_id` is undefined. Each also has a `sync_plans` step, a governance-agent task, without the `requires: [multi_agent]`, `default_agent: sales` and per-step `agent:` routing that `governance_denied` and `governance_denied_recovery` carry. So `sync_plans` is routed to the seller, and a seller-only agent skips the plan-setup phase as a missing tool. Both findings are about the 3.1 line. That follow-up, at 01:07 UTC on September 16, did not say so, and a second one at 10:21 UTC the same day did. On `main`, both storyboards have routed `sync_plans` to a governance agent and exported its `plan_id` since August 8, 2026 ([PR #6277](https://github.com/adcontextprotocol/adcp/pull/6277), [PR #6280](https://github.com/adcontextprotocol/adcp/pull/6280)), and they send `governance_context` where the released 3.1 files send neither field — there `$context.plan_id` is defined, as the triage said. When that second follow-up went up, none of that had reached the 3.1.x branch or v3.1.23, the hosted card graded on bundle 3.1.20, and a 3.1 seller needed the fixes from #6277 and #6280 on 3.1.x under either option. At 10:26 UTC on September 16, 2026 the bot rewrote that triage. It now says the A-or-B framing rested on the 3.1.20 bundle alone, names a backport of #6277 and #6280 as the fix, and leaves the deprecation as a separate policy call. As of 11:25 UTC on September 17, 2026, nobody else has commented on #7547. At 17:09 UTC on September 16, 2026 [PR #7555](https://github.com/adcontextprotocol/adcp/pull/7555) merged into the 3.1.x branch. It marks the two 3.1 governance storyboards `requires: [multi_agent]` with `default_agent: sales`, routes `sync_plans` to the governance agent and every other step to the seller, gives `sync_plans` a `context_outputs` block that captures `plans[0].plan_id`, sends that as `plan_id: "$context.plan_id"` on `create_media_buy`, and adds a test for the routing and the hand-off. It does not take #6277 and #6280 whole: its description says doing so would also import 3.2-only response fields such as `check_type` and `consultation_context`, which the 3.1 schema-path lints reject, so it carries only the routing and `plan_id` fixes. The 3.1.x `create_media_buy` request schema defines no `governance_context` field, and neither patched request sends one. The description says “Closes #7547”, but GitHub acts on that keyword only when a PR merges into the default branch, `main`, and as of 10:48 UTC on September 17, 2026, #7547 is still open. Nor was the fix released then: there was no v3.1.24 tag, the 3.1.x branch was three commits past v3.1.23, and the open release PR ([PR #7559](https://github.com/adcontextprotocol/adcp/pull/7559)) listed the change under `adcontextprotocol@3.1.24`. The newest public run on the hosted card at that point, an owner refresh at 09:55 UTC on September 16, 2026, before the merge, graded bundle 3.1.20. Of the storyboards, #7555 touches only `governance_approved` and `governance_conditions`. The other four that failed are unchanged on 3.1.x since v3.1.20, and each still calls `create_media_buy` for the brand and operator the governance storyboards register, without `plan_id`. Three of them, `delivery_reporting`, `measurement_accountability` and `vendor_metric_accountability`, register no agent and only reuse the account. The fourth, the base `media_buy_seller` storyboard, registers one in its own `governance_setup` phase, with no multi-agent requirement, and then buys without `plan_id`: the shape this filing reported, in a storyboard it did not name. On `main` its copy has the same shape and sends no `governance_context`, which `main` requires once governance applies to the account. #7555 changes none of the four: turning the constant back on would again have the agent refuse those buys for lack of `plan_id`, as it did in the local suite before the switch-off — the three while the registration on the shared account stands, and `media_buy_seller` on every run, since its own setup phase registers the agent again. The local suite could not run the patched storyboards at the time: it ran bundle 3.1.20 from `@adcp/sdk` 13.0.4, which carries no later 3.1 bundle; the first stable build to bundle 3.1.24 is 13.1.2 (September 28, 13:54 UTC; npm tag `adcp-3.1` that day, `latest` by 10:27 UTC on September 29). The constant stays off; the local suite, re-run on 13.1.2 against the live agent on September 29, read 250 steps passed, 2 failed and 81 skipped, the same two intentional failures, and the hosted grader’s run that night reported the same totals. A follow-up on #7547 at 12:18 UTC on September 17, 2026 raised the base storyboard there, marked as outside that issue’s scope, with the evidence for both branches, and offered to file it separately. The maintainer account answered on September 18, 2026 to file it separately — the base storyboard is a different file, carries none of the `plan_id` infrastructure the backport relies on, and has three plausible fix shapes of differing blast radius, so it should not absorb into a P0 thread otherwise ready to close. It is [#7585](https://github.com/adcontextprotocol/adcp/issues/7585), filed the same day with the per-branch line references: on 3.1.x the file has zero occurrences of `plan_id`, `sync_plans`, `multi_agent` or `default_agent`, and on `main` zero of `governance_context`. The filing concedes what the defect is not: on both branches the obligation is prose in the field description rather than a machine-enforced conditional — top-level `required` is the same five fields on each line, and neither schema carries an `if/then` or `dependentRequired` touching either field — so a schema-validation pass over the storyboard is clean, and it fails only against a seller that enforces the documented requirement. That timing held. The maintainer chose the subtractive option — drop `governance_setup` outright rather than gate it — and the backport landed as [PR #7627](https://github.com/adcontextprotocol/adcp/pull/7627) on September 23, 2026, inside the window. Checked in the published v3.1.24 bytes rather than on the branch: `governance_setup` and `sync_governance` now appear zero times in the base storyboard, and the isolated account key `media-buy-lifecycle.pinnacle-agency.example` appears six times. [#7547](https://github.com/adcontextprotocol/adcp/issues/7547) closed completed the same day on its own scope, which was the point of asking to separate them: both named scenarios now send `plan_id`, and a separate gate ([PR #7625](https://github.com/adcontextprotocol/adcp/pull/7625)) makes them skip entirely for a seller that declares `media_buy.governance_aware: false`, as this one does. The v3.1.24 fixes reached the sales card only on September 29, 2026. Until then it read bundle 3.1.20, four releases behind, from owner tests on September 16 and 17 that ran through *Recheck & retest* (`owner-refresh-` test sessions) shortly before that control was fenced platform-wide ([adcp#7457](https://github.com/adcontextprotocol/adcp/issues/7457)). A requeue only sets queue position, heartbeat throughput stayed collapsed through that window ([adcp#7355](https://github.com/adcontextprotocol/adcp/issues/7355)), and the interactive path below had not been used on either card before September 29. The grader itself moved on: from September 22 it graded 3.1-line agents on bundle 3.1.23 under @adcp/sdk 14.0.0-rc.40 (heartbeats on other agents on September 22 and 25, owner tests on September 23 and 24), and its runner moved to 14.0.0-rc.49 on September 28, then rc.50 on September 29, rc.51 at 09:07 UTC on September 30, rc.53 from 13:43 UTC that day, the stable 14.0.0 from 17:00 UTC on October 1, 14.2.0 from 16:20 UTC on October 6, 15.0.0 from 10:39 UTC on October 9 (#7968), 15.2.0 from 16:32 UTC that day (#8012) and 15.8.1 from 10:36 UTC on October 12 (#8148), still grading 3.1-line agents on 3.1.24 (since #7841, merged 14:58 UTC on October 1, an agent that advertises 3.2 is graded on the 3.2 bundle instead: 3.2.1 from the first such run at 21:48 UTC on October 1, 3.2.2 from October 5, 3.2.3 from October 8, 3.2.4 from October 13). Heartbeats came back too — six on the evening of September 29, nine on September 30 and twenty-one on October 1 (sixteen of them by 20:31 UTC), both of this site’s cards among them (13:49 and 14:54 UTC, both on 3.1.24 under rc.53), against none to two a day over September 22 to 28 — and the registry has run 459 public checks between October 2 and 22:15 UTC on October 13, 435 of them on 3.1.24 and 14 on the 3.2 bundles, under 14.0.0, then 14.2.0, then 15.0.0 and 15.2.0 from October 9 and 15.8.1 from October 12, with the daily count falling from 56 on October 3 to 23 on October 11, then rising to 31 on October 12 and 36 on October 13 by 22:15 UTC, this site’s signals card re-graded twice a day through October 8, by an owner test at 17:53 UTC on October 9 under 15.2.0 (passing on a nine-day streak), by heartbeats at 23:08 UTC on October 12 and 11:18 UTC on October 13 under 15.8.1 (both partial, on an output-schema fault of ours) and last by an owner test at 13:13 UTC on October 13 (passing again), and the sales card unchanged at 32 of 82. The sales card went about 53 hours without a completed grade: after its grade at 15:14 UTC on October 6 (under 14.0.0), its heartbeat at 03:47 UTC on October 7 ran out of the grader’s extended 30-minute budget after 58 of 75 storyboards, and the public history shows no completed run until a heartbeat at 20:42 UTC on October 8, under 14.2.0, that took eight and a half minutes; the next, at 09:10 UTC on October 9, took four. The same suite run from here against the live agent finishes in 70 seconds. The first 3.1-line runs under rc.49 followed on the afternoon of September 28: four owner tests on one other agent between 14:10 and 15:29 UTC, every one graded on bundle 3.1.23; the runner moved and the 3.1 bundle did not, and as of 10:30 UTC on September 29 no public run on any of the 34 registered agents had been graded on 3.1.24. Those four runs also show the one owner path the fence leaves open: in the registry source it guards the queued *Recheck & retest* refresh alone, while Addie’s `evaluate_agent_quality` tool, the one #6206 was filed against and also exposed on the AAO MCP endpoint, runs the suite interactively under a 20-minute budget and, for a full run on the default hosted target while the calling organization owns the agent, records it as an `owner_test` that the live public card shows once the run completes, with no provenance fence in that path. The first public 3.1.24 grade in the registry, and its first public rc.50 run, came at 20:56 UTC on September 29, from a heartbeat on this site’s signals card. The sales card followed at 23:15 UTC through Addie’s `evaluate_agent_quality` (a `quality-eval-` test session on its 20-minute budget): an owner test on bundle 3.1.24 under @adcp/sdk 14.0.0-rc.50, complete and authoritative, with 32 of 82 storyboards passing, 48 untested and two partial, where the card graded on September 17 read 29 passing and seven partial. In that run `governance_approved` and `governance_conditions` read `untested`: on 3.1.24 both require a multi-agent run and `media_buy.governance_aware: true`, and this seller declares `false`. The two partials are the intentional failures from the local suite above, `billing_finality_delivery` (a `post_sivt` measurement window this seller does not guarantee) and `provenance_truth_of_claim` (its `sync_creatives_contradicted` step). The run also reported the live-account phase of `comply_controller_mode_gate` failing, `NOT_FOUND` where the storyboard expects `FORBIDDEN`, which the card does not count.
- **A conformance failure you cannot act on** — `capability_discovery` failures reported the scenario name and nothing else: no request, no response, no pointer, no expected against actual ([#2352](https://github.com/adcontextprotocol/adcp/issues/2352), with the Signals track reported separately as [#2356](https://github.com/adcontextprotocol/adcp/issues/2356) when a declared `signals` protocol was told the track was not applicable). The maintainer wrote the protocol-side runner-output contract in response — [#2364](https://github.com/adcontextprotocol/adcp/pull/2364) mandates the exact request and response, an RFC 6901 `json_pointer`, machine-readable expected and actual, a fetchable `schema_url` and six canonical skip reasons — and [#2365](https://github.com/adcontextprotocol/adcp/pull/2365) populated the signals baseline, which had shipped as a placeholder with no phases, so there had been nothing to run. Both merged the same day. Worth recording what the same thread established about us: the filing argued our agent was correctly implemented, and two of the failures were real non-conformances on our side, a missing `adcp.idempotency` block and no `context.correlation_id` echo. We fixed those. The contribution is the report and the reproduction; the implementation was the maintainer’s.
- **A second filing withdrawn** — an argument that npm-published compliance caches omit the sibling `schemas/` directory the resolver needs, leaving an earlier fix inert for anyone on a plain `npm install` ([#6650](https://github.com/adcontextprotocol/adcp/issues/6650), re-filed correctly as [adcp-client#2587](https://github.com/adcontextprotocol/adcp-client/issues/2587)). The maintainer unpacked the exact tarball and showed the resolver falling through to the package’s own bundled schemas, no sibling required. Retracted the same afternoon. The advisory that prompted it had a different cause entirely — a second, 3.0-shaped validation from the new mixed-version compatibility check — filed separately and fixed within the hour. Two things this one is worth remembering for: the issue still reads *completed* in the API, because an author self-close with no reason renders that way, and the automated triage posted a confirmed-and-ready-to-implement verdict at P1 four minutes *after* the issue was closed and under an hour before the human maintainer disproved it. Triage labels on this repository are a bot’s opinion, not a maintainer’s endorsement.
- **A storyboard that asks for a value the schema rejects, still shipping on 3.1** — the version-negotiation steps in `universal/error-compliance.yaml` and `error-compliance-signals.yaml` tell a seller to answer `VERSION_UNSUPPORTED` with `recovery: fatal`, and list the vocabulary as “correctable, transient, or fatal”. `core/error.json` types `recovery` as `["transient", "correctable", "terminal"]`, so `fatal` is not a legal value, and `enums/error-code.json` classes this code `correctable`: re-pin to a supported release and retry. Someone else had already found it and filed it ([#7375](https://github.com/adcontextprotocol/adcp/issues/7375), September 8, 2026); [PR #7376](https://github.com/adcontextprotocol/adcp/pull/7376) corrected both lines on `main` the same day and the issue closed. What had not happened was the backport. On September 17, 2026 the 3.1.x source still carried the old prose at lines 302 and 359, and v3.1.23 — published on September 14, six days after the fix landed on `main` — shipped it in `dist/compliance/3.1.23/`. That is the line the hosted grader ran, on bundle 3.1.20, until September 22, 2026, when it moved 3.1-line agents to 3.1.23. A comment on the closed issue that day set out the two branch states, the release timeline and the enum, and noted the grade is unaffected either way, because nothing in the SDK parses the `expected:` prose — only the `validations:` entries decide pass or fail. Both of this site’s agents had the defect the prose would have caused, in opposite directions: the sales agent answered an unsupported pin with `recovery: "terminal"`, which on 3.1 means the buyer needs a human, and the signals adaptor sent no `recovery` at all, where 3.1 says senders SHOULD populate it on every error. Both now answer `correctable`, verified live. Seven minutes after that comment, [PR #7572](https://github.com/adcontextprotocol/adcp/pull/7572) was opened against `3.1.x` carrying the same two-line change plus a changeset, described as ready for the 3.1.24 window. Like the other triages on this page it was bot-drafted under the maintainer account, and it sat as a draft — unmergeable by definition, with no reviewer requested — for over a day while the release PR queued two other changesets and not this one. A comment on September 18, 2026 naming the draft flag as the mechanical blocker drew a reply three minutes later undrafting it, a merge at 23:38 UTC, and the release PR regenerating fifteen minutes after that to consume the changeset. On the 3.1.x branch `recovery: fatal` now appears zero times in either file; the general error-shape line reads “transient, correctable, or terminal”, which is the enum the schema actually defines. v3.1.24 was tagged on September 23, 2026, so the fix is released rather than queued. The audit that followed on this side found the defect was a class rather than an instance: the sales agent’s `ToolError` constructor defaults `recovery` to `terminal`, and its own doc comment named only two of the three legal values, so 16 sites across seven codes inherited the most severe classification for errors a buyer could have fixed — a wrong media buy id, a malformed request, a governance denial explained as “over budget”. Each was re-judged against what its call site actually does, and three were kept `terminal` on the evidence: one internal invariant on an id the buyer never supplies, and two admin-console paths where the field never reaches the wire. Those three are now pinned explicitly rather than inherited. The denial case also now forwards the governance agent’s `findings`, which `check-governance-response` requires when the verdict is denied: calling an error correctable while dropping the reason leaves the buyer guessing what to change.
- **A filing that was right about the symptom and wrong about the cause** — the signals agent’s hosted card showed `error_handling` at 10 of 11 scenarios. The failure was not an error-handling defect at all: `billing_gate_dispatch` asserts `field_present: account.supported_billing` in an ungated first phase, and that field is `required` with `minItems: 1`, so there is no honest value for an agent with no account management. Its own description says buyers pass one of those values in `sync_accounts` — a tool this agent does not expose. Declaring it to pass would have been the `governance_aware` mistake again. Filed as [#7573](https://github.com/adcontextprotocol/adcp/issues/7573) on September 18, 2026, bot-triaged P1 within eight minutes with a primary fix in the SDK and a defensive one in the storyboard. Two corrections followed, both ours. One line of the filing said the divergence only appeared when a track was forced; that was true of SDK 13.0.2 and false of the pinned 13.0.4, carried forward without re-checking. The larger one: the triage’s primary fix was a no-op. The runner already enforced `required_tools` in every mode — at `comply.js:600` for capability-driven selection and again at `runner.js:1420` at load time — as an *any-of* gate, which the bundled storyboard schema documents as deliberate and pairs with a strict `required_any_of_tools` form that almost nothing uses. Both storyboards were admitted on one matching tool: `get_adcp_capabilities`, which every agent has, and `comply_test_controller`. Searching only this protocol’s repository before filing had also missed two earlier filings of ours in the client repository, making this the third occurrence — and the any-of convergence that admits these storyboards shipped in 13.0.4 because we asked for it. The fix that landed, [PR #7581](https://github.com/adcontextprotocol/adcp/pull/7581), took the defensive route on September 18, 2026: `optional: true` plus `requires_capability: { path: account, present: true }`, with a runner test. It is on `main` only. The finding that mattered came afterwards. The `required_tools` corrections had already shipped upstream — across storyboards on August 23 and for the other file on September 14 — and are in the released v3.1.23 bundle. Running the SDK’s own `resolveStoryboardsForCapabilities` and `partitionStoryboardsByRequiredTools` against each bundle in turn: on 3.1.20 both storyboards are runnable, on 3.1.23 both are excluded for missing `sync_accounts` and `validate_input` respectively — 19 runnable storyboards and 171 steps down to 17 and 149, with nothing newly selected. So the storyboard defect had largely been fixed weeks earlier, and what remained — until September 22, 2026 — was that the hosted grader was pinned to bundle 3.1.20 (this site’s two cards read it until September 29, when a heartbeat re-graded the signals card at 20:56 UTC and an owner test re-graded the sales card at 23:15 UTC, both on 3.1.24; the grader graded 3.1-line agents on 3.1.23 from September 22 and on 3.1.24 by September 29). That is a registry-side pin, not a protocol matter, and it was raised there rather than on the issue. Excluded is not passed: those storyboards leave the denominator as not-applicable rather than becoming passing steps.
- **An idempotency key that dies with the row it protects** — the recovery audit left one item out of scope: `buyResponse` answers a missed read-back with `MEDIA_BUY_NOT_FOUND`, on an id every caller derives server-side, so there is nothing in the request for the buyer to verify. The trigger is a console delete landing between the caller’s own read and that one. D1 has no interactive transactions and the purge’s `batch()` is atomic only with itself, so nothing serialises the two. Three interleavings reproduce. The narrowest is the create path, since a fresh buy is written `pending_approval`, which sits in neither delete guard and so needs a decide-then-purge pair inside the window; the widest is `get_media_buys`, where one purged row fails the entire list and the sandbox sweep in the promotion cron carries no status guard at all. The first fix answered `CONFLICT` with `recovery: transient` and was wrong. `core/error.json` defines `transient` as “retry after delay”, the purge takes the row’s `UNIQUE` `idempotency_key` with it, and a buyer following that instruction writes a second buy instead of replaying the first. Checked against the running implementation rather than argued: the same key after a purge returns a new `media_buy_id`. Create now answers `terminal` on both of its call sites, and the read paths stay `transient`, where a retry does converge. The half the spec owns went upstream ([#7575](https://github.com/adcontextprotocol/adcp/issues/7575), filed September 17, 2026): `replay_ttl_seconds` scopes the replay window purely in time, minimum 3600, and enumerates three outcomes, being the cached response, `IDEMPOTENCY_CONFLICT` and `IDEMPOTENCY_EXPIRED`. None of them is the fourth that any seller keying idempotency to the resource row will produce, where the key dies with the resource and a replay inside the advertised window creates a second one and returns success. `CONFLICT` is no better a fit: the schema scopes it to revision mismatch, and `error-details/conflict.json` carries `expected_version` and `current_version`, neither of which a deleted row has.
- **A test-scenario report that was out of date when filed** — reported on April 27, 2026 that the SDK’s signals test scenario (`scenarios/signals.js`) called `activate_signal` with `signal_id`, carrying a `SignalID` object, where the schema requires a `signal_agent_segment_id` string ([#3349](https://github.com/adcontextprotocol/adcp/issues/3349), filed in the protocol repository under a header that already named `adcp-client` as its subproject, and re-filed there three minutes later as [adcp-client#1033](https://github.com/adcontextprotocol/adcp-client/issues/1033)). The field name had been corrected on March 21, 2026 and released that day in `@adcp/client` 4.13.0, five weeks before the filing. The object half was never true: even before that fix, the value passed was a string. The two bot triages disagreed: the one on #3349 accepted the premise, and the one on adcp-client#1033, fifteen minutes later, found the report false against the then-current 5.21.1. The client-repo copy was closed on April 30, 2026 as already fixed. This one was closed as not planned on May 19, 2026, with a comment that the spec storyboards already use the correct fields and the report belongs to `adcp-client`. Two merged PRs came out of the bot triages, and neither is the fix the filing asked for: the #3349 triage, taking the report at its word, drafted the removal of training-agent aliases that still accepted the old field names, with sharper schema descriptions ([PR #3356](https://github.com/adcontextprotocol/adcp/pull/3356), merged May 14, 2026), and the adcp-client#1033 triage drafted a fix for a separate bug it found in the same scenario, a governance advisory check that never fired ([adcp-client#1036](https://github.com/adcontextprotocol/adcp-client/pull/1036), merged April 28, 2026).

### Open proposals

- **Geo cell interoperability** — conversion ([#6013](https://github.com/adcontextprotocol/adcp/issues/6013)) and cell-grain delivery reporting ([#6014](https://github.com/adcontextprotocol/adcp/issues/6014)) companions to the geo_cells RFC ([#5969](https://github.com/adcontextprotocol/adcp/issues/5969)), with Nathan Woodman.
- **Static OOH: the channel with no play event** — static out-of-home has nothing to emit an impression against, so proof-of-posting has no shape in the delivery contract; filed with a measurement shape and posting-record proposal ([#6140](https://github.com/adcontextprotocol/adcp/issues/6140)). The channel contract it asked for merged — `ooh_metrics`, posting records and a channel guide ([PR #6241](https://github.com/adcontextprotocol/adcp/pull/6241)) — and the measurement-shape half is still open.
- **A seller shape the taxonomy has no slot for** — the specialisms treat guaranteed-vs-non-guaranteed as a proxy for human-approval-vs-auction, so a publisher-direct seller running fixed-price, non-guaranteed inventory behind a human approval gate matches neither: `sales-non-guaranteed` assumes bidding and states that buys need no human approval, while `sales-guaranteed` describes the human gate but assumes IO-signed reserved inventory and proposal flows ([#6303](https://github.com/adcontextprotocol/adcp/issues/6303), filed with our own live agent as the reproduction after withdrawing a claim we couldn't honestly certify). On October 6, 2026 the maintainer took it to the working group with a decision brief and a draft, [#7963](https://github.com/adcontextprotocol/adcp/pull/7963): a new specialism proposed for 3.3, `sales-fixed-rate`, for fixed-price, non-guaranteed sellers, with optional review-hold phases graded only when a seller advertises a new `force_media_buy_confirmation` controller scenario. We accepted it, name included, over the `sales-publisher-direct` we had asked for: a specialism should name a mechanic a runner can test, not who the seller is. Run against our live agent on October 7, the draft’s product discovery and create phases pass, the bid-free create comes back held with `confirmed_at: null`, the three hold phases skip because we do not advertise the scenario yet, and the only failure is the capabilities check, which expects `sales-fixed-rate` among our declared specialisms: a specialism proposed for 3.3 that we cannot declare while we serve 3.1. [Our reply](https://github.com/adcontextprotocol/adcp/issues/6303#issuecomment-6036482860) also records the gap on our side: our `pending_creatives` still means awaiting our review, so status has to follow creative readiness before we advertise the hold scenario. On October 9 the draft marked the specialism preview, like `sales-exchange`, until the working group ratifies the name and the hold gating, and recorded one narrowing of existing text: a held buy whose flight start passes stays `pending_start` until it is confirmed or rejected, so the rule that a seller moves `pending_start` to `active` at flight start would apply only to committed buys. The certification contradiction found alongside it is already fixed: the docs stated that grading neither requires nor uses `comply_test_controller`, while specialism certification requires `seed_*` scenarios only that controller can execute — confirmed and scoped to the storyboards it actually covers, since the exemption holds for universal and protocol runs but not for specialisms that seed state ([#6301](https://github.com/adcontextprotocol/adcp/issues/6301), fixed).
- **revoke_activation** revocation primitive ([#4203](https://github.com/adcontextprotocol/adcp/issues/4203)) · **Measurement Feedback Signal** ([#4296](https://github.com/adcontextprotocol/adcp/issues/4296)).
- **JWKS adoption baseline** — the chain-of-custody gate on signal-payment work ([#4206](https://github.com/adcontextprotocol/adcp/issues/4206)).

### Not protocol work — bug reports and a feature request against the AAO platform

- **Shipped as filed, one of them only in part** — the member profile edit page threw `parsed is not defined` on load, a one-line scoping error ([#4257](https://github.com/adcontextprotocol/adcp/issues/4257)), and photo uploads on the same page reverted silently on save, from two compounding causes: the upload handler wrote a base64 data URL the brand-identity endpoint rejects, and the save never sent the photo field ([#4260](https://github.com/adcontextprotocol/adcp/issues/4260)). Both were fixed in [PR #4352](https://github.com/adcontextprotocol/adcp/pull/4352), merged May 10, 2026, which references neither issue; its description credits my in-app escalations of the same two defects, and both issues were closed on May 12 with a comment pointing to it. Badge links of the form `/registry/agents/{encoded-url}` returned `Cannot GET` ([#5485](https://github.com/adcontextprotocol/adcp/issues/5485)) until [PR #5492](https://github.com/adcontextprotocol/adcp/pull/5492), a five-issue batch merged June 12, 2026, served that path as a public agent profile page. A “0 / 0 Community seats” row on a Professional plan, which the filing itself called display-only ([#5494](https://github.com/adcontextprotocol/adcp/issues/5494)), was hidden on plans without Community seats by a small conditional ([PR #5586](https://github.com/adcontextprotocol/adcp/pull/5586), merged June 18, 2026). A copy button for replies in AAO’s Addie assistant shipped ([#4266](https://github.com/adcontextprotocol/adcp/issues/4266) → [PR #4269](https://github.com/adcontextprotocol/adcp/pull/4269)) without the plain-text/markdown toggle the request also asked for, which the bot triage declined and the PR left out of scope.
- **Wrong or partial diagnoses, and one wrong report** — the dashboard’s Test view listed media-buy storyboards for a signals-only agent; filed as missing capability filtering, but the filter already existed, and a fallback to the full catalog, taken when the platform’s capability probe of my agent failed for a reason the record does not give, bypassed it. The fix drops the fallback and shows the probe error, with a pointer to what `get_adcp_capabilities` must return, rather than the filtered list the filing expected ([#4254](https://github.com/adcontextprotocol/adcp/issues/4254) → [PR #4369](https://github.com/adcontextprotocol/adcp/pull/4369)). The member directory showed “Tools: 0” for an agent with eight tools; filed as a stale comply cache, a theory the fixing PR calls incorrect: the public discovery endpoint probed the agent live and left the tool list out of its response ([#4256](https://github.com/adcontextprotocol/adcp/issues/4256) → [PR #4261](https://github.com/adcontextprotocol/adcp/pull/4261)). The organization page offered “Register an agent” to an org that had one; the filing guessed the page was not querying the registry or was filtering on a stale comply cache, and the health service in fact returned a hard-coded agent count of zero ([#4255](https://github.com/adcontextprotocol/adcp/issues/4255) → [PR #4258](https://github.com/adcontextprotocol/adcp/pull/4258)). Listing the org’s agents on that page, the filing’s first expected behaviour and its whole suggested fix, was left out of scope by the bot triage and the PR. Addie kept reporting GitHub as unconnected for a turn after OAuth completed; the bot triage and the fixing PR found the token lookup already ran live on every tool call, which rules out the filing’s caching guesses, and put the lag down to propagation delay in the upstream WorkOS API, which none of the filing’s three guesses named. The fix is a single 1.5-second retry that absorbs that window, a note in the not-connected reply that the connection may still be propagating, and a prompt rule that stops Addie offering the Connect link again right after the user says it is connected; none of it is a change to connection state ([#4348](https://github.com/adcontextprotocol/adcp/issues/4348) → [PR #4349](https://github.com/adcontextprotocol/adcp/pull/4349)). And one report was wrong. A community profile photo picker, on a different page from #4260, reported as broken, was the reference-photo input for AI portrait generation: the filing’s own steps name it (“Upload a reference photo”), and the bot triage found its hint reads “Used as reference only, not stored” and that the avatar changes only after Generate and Approve. That triage put a choice between a direct upload path and clearer labels to the maintainer, and the merged fix built the upload path ([#4658](https://github.com/adcontextprotocol/adcp/issues/4658) → [PR #5157](https://github.com/adcontextprotocol/adcp/pull/5157), merged May 29, 2026).
- **Registry & docs reliability** — registry UI rendering empty product/format sections for anonymous viewers despite working public endpoints ([#6229](https://github.com/adcontextprotocol/adcp/issues/6229), fixed and closed; my own duplicate of it, [#6230](https://github.com/adcontextprotocol/adcp/issues/6230), filed 57 seconds later, drew a bot triage the same day that surfaced a third break in publisher discovery; I carried that finding across when I closed #6230 as a duplicate on August 6, 2026, which GitHub records as not planned, and it was fixed in the same change) and the dashboard's aao-verified doc links returning 404 ([#6231](https://github.com/adcontextprotocol/adcp/issues/6231), fixed and closed). The registry card's "Publishers & properties" panel surfacing a raw JSON-parse exception instead of the actual authorization-list cause ([#7333](https://github.com/adcontextprotocol/adcp/issues/7333)) is fixed too — [PR #7362](https://github.com/adcontextprotocol/adcp/pull/7362) now indexes publisher authorization data, guards invalid JSON responses, and renders clean 404/error states.

Contribution statuses validated September 16, 2026 against the public AdCP repository; open proposals are point-in-time and may merge, change, or close. Maintainer-authored work is credited as review influence, not authorship.

*Domains*

## Protocol domains.

AdCP organizes work into domain-specific tasks and schemas. Task names below are drawn from current official documentation.

- **Media Buy** — Inventory discovery, campaign creation, delivery reporting. `get_products · create_media_buy · get_media_buy_delivery`
- **Creative** — Creative format discovery, building, preview, distribution. `build_creative · preview_creative · list_creative_formats`
- **Signals** — Audience and contextual data discovery and activation. `get_signals · activate_signal`
- **Accounts** — Commercial identity, billing, and usage reporting. `list_accounts · sync_accounts · report_usage`
- **Governance** — Brand suitability, approval, policy, audit, content standards. `create_content_standards · calibrate_content`
- **Brand** — Machine-readable brand identity and authorized agents via brand.json. `brand.json discovery`
- **Sponsored Intelligence** — Conversational brand experiences on AI platforms. `Experimental surface in AdCP 3.0`
- **Curation** — Media inventory curation. `Listed "coming soon" — not a current domain`

*Figure: AdCP at the center; each domain connects to a workflow surface.*

*Workflow*

## From brief to governed execution.

1. **Discover authorized agents** — adagents.json, brand.json, registry
2. **Set up account context** — commercial identity, billing, advertiser / operator relationship
3. **Discover inventory and products** — natural-language brief into structured product responses
4. **Build or sync creative** — formats, assets, brand identity, approvals
5. **Add signals** — audiences, suppression, contextual signals, signal activation
6. **Check governance** — budget, brand safety, targeting rules, approvals
7. **Execute, report, and audit** — media buy, delivery, events, audit logs

*Figure: Brief → discovery → accounts → products → creative → signals → governance → buy / report / audit.*

Discovery starts from two machine-readable files — a publisher's `adagents.json` (who may sell its inventory) and a brand's `brand.json` (who may act for the brand, and how):

**adagents.json** (illustrative)

```json
{
  "publisher": "example-publisher.com",
  "authorized_agents": [
    {
      "url": "https://sales-agent.example-ssp.com",
      "role": "seller",
      "properties": ["news", "sports"]
    }
  ],
  "signing_keys": [
    { "kid": "2026-key-1", "alg": "Ed25519" }
  ]
}
``` **brand.json** (illustrative)

```json
{
  "brand": "example-brand.com",
  "display_name": "Example Brand",
  "authorized_agents": [
    { "url": "https://agent.example-buyer.com", "role": "buyer" }
  ],
  "identity": {
    "logos": ["/brand/logo.svg"],
    "colors": ["#1a1a1a", "var(--accent)"],
    "tone": "confident, plain-spoken"
  },
  "policy": { "restricted_categories": ["gambling", "politics"] }
}
```

*Signals*

## Signals: where AdCP meets signal containerization.

The signals layer is where AdCP becomes especially important for agentic advertising. Agents need to discover signals, understand what they mean, check provenance and policy, activate them, and monitor status. That is the same operating problem behind [signal containerization](https://nofluffadvisory.com/writing/signal-containerization-agentic-advertising/) — turning audience logic into a governed, executable object.

- **Discover** — What signals exist and what do they mean?
- **Inspect** — Where did the signal come from, how fresh is it, and what policy applies?
- **Activate** — Where can the signal run: seller, platform, identity path, contextual path, or measurement layer?
- **Monitor** — What is the activation status and what outcome did it improve?

*Figure: Discover, inspect, activate, monitor — signals as executable objects.*

An agent discovers signals with a natural-language brief, then activates the chosen signal to a destination — a single `get_signals` call rather than a taxonomy lookup:

**get_signals (MCP tool call)** (illustrative)

```json
{
  "tool": "get_signals",
  "arguments": {
    "brief": "in-market for premium CTV, US households, privacy-safe",
    "deliver_to": { "platform": "dsp", "account": "acct_123" },
    "max_results": 10
  }
}
```

One open question now sits under this layer. The vectors agents exchange today are text-family embeddings — they encode the words that describe an audience or a brief, and text models famously lose numbers, geography, and time. A second family, [spatiotemporal embeddings](https://nofluffadvisory.com/writing/the-context-economy/#the-moment-has-four-dimensions), encodes the place and hour themselves. A text space and a place-time space do not share a geometry: similarity across the two is undefined until someone defines it — a signals-standards question, exactly the kind of definition a signals working group exists to produce, not an integration ticket.

*Trust*

## Governance is the trust layer.

Agentic advertising only works if actions are accountable. A protocol needs to know who called a tool, what authority they had, what was approved, what conditions applied, and what actually ran.

- Human-in-the-loop approvals (a three-party separation of duties)
- Idempotency keys on every mutating request
- Request signing (RFC 9421 HTTP Message Signatures)
- Correlated audit logs
- Governance checks and signed governance tokens
- Brand-safety and content-standard enforcement
- Budget thresholds and authority / role boundaries

**The principle**

Human judgment is embedded in the system design, not bolted on afterward — the human stays the locus of accountability.

*Complementarity*

## Where AdCP fits with IAB Tech Lab standards.

AdCP is best understood as an agentic management and workflow layer. IAB Tech Lab's AAMP work extends existing standards with agentic foundations, protocols, and trust infrastructure — and its buyer and seller reference agents do workflow-layer work of their own (briefs, planning, negotiation, OpenDirect booking); ARTF focuses on containerized real-time execution; Agentic Audiences on embedding-based signal exchange. These layers can be complementary with clear boundaries — the full repository-level comparison, verified against both codebases, is in [AdCP vs AAMP: The Retrofit and the Greenfield](https://nofluffadvisory.com/writing/adcp-vs-aamp/). See also the [IAB Agentic Standards guide](https://nofluffadvisory.com/standards/iab-agentic-standards/). The protocol's sell side already has a shipping open-source implementation — Prebid.org took stewardship of AdCP's sell-side reference code in January 2026, dissected in [The Prebid Sales Agent](https://nofluffadvisory.com/writing/the-prebid-sales-agent/) — and landing inside the publisher execution layer documented in [Prebid & Header Bidding Infrastructure](https://nofluffadvisory.com/standards/prebid-header-bidding/).

| Initiative | Role | Best question |
| --- | --- | --- |
| AdCP | Agent task / workflow language | What should the agent ask or do? |
| AAMP | IAB Tech Lab umbrella — buyer/seller reference agents plus foundations and trust | How do agents run briefs, negotiation and booking on the standards already in production? |
| ARTF | Containerized real-time execution framework | How can service agents run inside host infrastructure with low latency and controlled mutation? |
| Agentic Audiences | Embedding-based signal exchange | How do agents exchange identity, contextual, and reinforcement signals? |
| OpenRTB / AdCOM / Deals API / OpenDirect | Existing transaction and object standards | What underlying objects and transaction models should agentic systems reference? |

*Figure: Two ancestries — new rails and existing rails — overlapping in function, meeting head-to-head at the deal plane.*

*Implementation*

## Implementation lens by company type.

Pick your company type to see what to expose or consume — and the AdCP domains it touches first.

**Publisher / seller — What to expose.** Authorized agents, inventory products, packages, account setup, governance, reporting.

*Key protocols: adagents.json, Media Buy, Accounts, Governance.*

**Agency / buyer — What to consume.** Partner discovery, product discovery, creative formats, media buy, governance, reporting.

*Key protocols: brand.json, Media Buy, Creative, Signals.*

**Data / signals vendor — What to expose.** Signal catalog, provenance, activation paths, pricing, policy, status.

*Key protocols: Signals, Accounts, Governance.*

**SSP / exchange — What to support.** Seller agents, deals, signals, governance, a real-time execution bridge, reporting.

*Key protocols: Media Buy, Signals, Governance, registry.*

**DSP / buying platform — What to support.** Buyer agents, media buys, creative, signal activation, governance, measurement.

*Key protocols: Media Buy, Creative, Signals, Governance.*

**Creative / AI platform — What to expose.** Formats, asset generation, preview, brand identity, approval workflow.

*Key protocols: Creative, Brand, Governance.*

**Measurement / clean room — What to expose.** Delivery, event logging, attribution, audit, lift, governed outputs.

*Key protocols: Media Buy, Accounts, Governance.*

*No Fluff POV*

## A protocol defines the task. It does not replace judgment.

The industry should avoid treating AdCP as a magic layer that makes agents safe by default. The protocol can define the task. It cannot replace commercial judgment, governance design, data rights, measurement discipline, or operating ownership.

- Start with one workflow, not every workflow.
- Expose the safest useful task first.
- Design governance before spend movement.
- Treat signals as governed objects, not just segment IDs.
- Build audit and status from day one.
- Connect protocol work to business outcomes, not demos.

*Stack fit*

## Where this fits in the full standards stack.

**The layer map**

AdCP defines the agent workflow layer. It still needs transaction rails, privacy constraints, measurement trust, and evidence discipline around it.

- [Core AdTech Standards](https://nofluffadvisory.com/standards/core-adtech-standards/)
- [Privacy & Consent Standards](https://nofluffadvisory.com/standards/privacy-consent-platform-apis/)
- [Measurement & Media Quality](https://nofluffadvisory.com/standards/measurement-verification-media-quality/)
- [IAB Agentic Standards](https://nofluffadvisory.com/standards/iab-agentic-standards/)
- [Research & Measurement Science](https://nofluffadvisory.com/standards/research-measurement-science/)

*Related*

## Related materials.

- [Agentic Transformation](https://nofluffadvisory.com/services/playbooks/agentic-transformation/)
- [AdCP vs AAMP (essay)](https://nofluffadvisory.com/writing/adcp-vs-aamp/)
- [Signal Containerization (essay)](https://nofluffadvisory.com/writing/signal-containerization-agentic-advertising/)
- [The Context Economy (essay)](https://nofluffadvisory.com/writing/the-context-economy/)
- [The Prebid Sales Agent (essay)](https://nofluffadvisory.com/writing/the-prebid-sales-agent/)
- [Prebid & Header Bidding](https://nofluffadvisory.com/standards/prebid-header-bidding/)
- [AdCP Ecosystem prototype](https://nofluffadvisory.com/building/adcp-ecosystem/)
- [AdCP Signals Adaptor](https://nofluffadvisory.com/building/adcp-signals-adaptor/)
- [Enterprise Data Collaboration](https://nofluffadvisory.com/services/playbooks/multicloud-data-orchestration/)
- [Semantic Infrastructure](https://nofluffadvisory.com/services/playbooks/multicloud-data-orchestration/ecosystem-surfaces/semantic-infrastructure/)
- [DSP / Agentic Buying](https://nofluffadvisory.com/services/playbooks/multicloud-data-orchestration/ecosystem-surfaces/dsp-agentic-buying/)
- [BI / MMM / Decision Intelligence](https://nofluffadvisory.com/services/playbooks/multicloud-data-orchestration/ecosystem-surfaces/bi-mmm-decision-intelligence/)
- [IAB Agentic Standards](https://nofluffadvisory.com/standards/iab-agentic-standards/)
- [Core AdTech Standards](https://nofluffadvisory.com/standards/core-adtech-standards/)
- [Privacy & Consent Standards](https://nofluffadvisory.com/standards/privacy-consent-platform-apis/)
- [Measurement & Media Quality](https://nofluffadvisory.com/standards/measurement-verification-media-quality/)
- [Writing: Agentic Advertising](https://nofluffadvisory.com/topics/agentic-advertising/)
- [Glossary: AdCP](https://nofluffadvisory.com/glossary/#adcp)
- [Embeddings in Advertising](https://nofluffadvisory.com/topics/embeddings/)

### Primary sources to validate (16 sources)

- [AdCP — Advertising Context Protocol (repository README)](https://github.com/adcontextprotocol/adcp) — AgenticAdvertising.org / adcontextprotocol. Official GitHub; confidence: primary; checked 2026-06-07. Authoritative expansion "AdCP - Advertising Context Protocol"; an open standard for advertising automation over MCP and A2A; reference implementation + docs. Supports: Official name, Scope, Transport (MCP/A2A), Stewardship.
- [AdCP Documentation — Introduction](https://docs.adcontextprotocol.org/docs/intro) — AgenticAdvertising.org. Official docs; confidence: primary; checked 2026-06-07. Defines AdCP as "an open agentic advertising standard" using MCP (tool calls) and A2A (agent-to-agent) — "same tasks, same schemas, different transport." Supports: What AdCP is, Transport model, Positioning.
- [AdCP docs index (llms.txt)](https://docs.adcontextprotocol.org/llms.txt) — AgenticAdvertising.org. Official docs; confidence: primary; checked 2026-06-07. Machine-readable docs index; enumerates the layered architecture (L0 wire/transport → L4 business logic) and the protocol domains + task references. Supports: Architecture layers, Domain/task index.
- [AdCP Media Buy Protocol](https://docs.adcontextprotocol.org/docs/media-buy/) — AgenticAdvertising.org. Official docs; confidence: primary; checked 2026-06-07. Inventory discovery, campaign creation, and delivery reporting. Verified tasks include get_products, create_media_buy, get_media_buy_delivery. Supports: Media Buy domain, Verified task names.
- [AdCP Creative Protocol](https://docs.adcontextprotocol.org/docs/creative/) — AgenticAdvertising.org. Official docs; confidence: primary; checked 2026-06-07. Creative from brief to delivery across CTV, display, social. Verified tasks include build_creative, preview_creative, list_creative_formats. Supports: Creative domain, Verified task names.
- [AdCP Signals Protocol (overview)](https://docs.adcontextprotocol.org/docs/signals/overview) — AgenticAdvertising.org. Official docs; confidence: primary; checked 2026-06-07. Discover and activate audience/contextual signals across data providers via natural language. Verified tasks: get_signals, activate_signal. Supports: Signals domain, Signal containerization link.
- [AdCP Accounts Protocol (overview)](https://docs.adcontextprotocol.org/docs/accounts/overview) — AgenticAdvertising.org. Official docs; confidence: primary; checked 2026-06-07. Commercial layer — billing, operator authorization, usage reporting. Verified tasks: list_accounts, sync_accounts, report_usage. Supports: Accounts domain, Verified task names.
- [AdCP Governance Protocol (overview)](https://docs.adcontextprotocol.org/docs/governance/overview) — AgenticAdvertising.org. Official docs; confidence: primary; checked 2026-06-07. Human oversight of autonomous buying via three-party separation of duties and signed governance tokens; embedded human judgment as the locus of accountability. Verified tasks: create_content_standards, calibrate_content. Supports: Governance domain, Human-in-the-loop, Verified task names.
- [AdCP Brand Protocol](https://docs.adcontextprotocol.org/docs/brand-protocol/) — AgenticAdvertising.org. Official docs; confidence: primary; checked 2026-06-07. Machine-readable brand guidelines via brand.json — the buy-side identity file paralleling publisher adagents.json. Supports: Brand domain, brand.json.
- [AdCP Registry](https://docs.adcontextprotocol.org/docs/registry/) — AgenticAdvertising.org. Official docs; confidence: primary; checked 2026-06-07. Public REST API for agent discovery, brand resolution, property lookup, and authorization; validates adagents.json (publisher) against brand.json (operator). Supports: adagents.json, Discovery/identity, Authorization.
- [AdCP Security Model](https://docs.adcontextprotocol.org/docs/building/concepts/security-model) — AgenticAdvertising.org. Official docs; confidence: primary; checked 2026-06-07. Required idempotency_key on every mutating request; RFC 9421 HTTP Message Signatures (Ed25519/ECDSA P-256); correlated audit records; replay protection. Supports: Idempotency, Signatures, Audit, Trust layer.
- [AdCP Release Notes](https://docs.adcontextprotocol.org/docs/reference/release-notes) — AgenticAdvertising.org. Official docs; confidence: primary; checked 2026-10-13. AdCP 3.2 is GA as v3.2.1 (the docs date it September 30, 2026; GitHub release published October 1, 05:54Z; wire pin "3.2"). 3.2.0 was never released: an accidental cut on June 30 committed 3.2.0 from 3.1-era main, #5769 reverted it within hours, and its signed artifacts stay on the CDN under immutable caching, so the number is withdrawn. Additive over 3.1 apart from a recorded exception list — the ratified removal of body-level status from create_media_buy / update_media_buy success (DR-0011; read media_buy_status), the request-signing profile correction (content-digest coverage and RFC 8941 padded Base64, selected by the endpoint rather than the request pin), eight tightened request rules and three producer-side tightenings, plus clarified reporting-timezone delivery dates. The versions reference, migration guide and What's New page (all flipped to GA at 16:24Z on September 30, #7775) say @adcp/sdk 14.0.0 and adcp 8.0.0 ship alongside 3.2.1, and both shipped on October 1: 14.0.0 to npm at 12:39Z and 8.0.0 to PyPI at 18:12Z; npm latest then moved through 14.1.0 to 14.4.0 (October 4 to 6), then 15.0.0 (a new SDK major for an OAuth issuer-binding change) and 15.2.0 (the SDK-side fix for the A2A signing advisory) on October 7, all declaring 3.2.1 and bundling the 3.0.25 / 3.1.24 / 3.2.1 lines; every build from 15.2.1 (October 8) through 15.8.1 (October 11) declares and bundles 3.2.3, latest reaching 15.7.0 late on October 9, and 15.9.0 (October 13), latest as of 22:15Z on October 13, is the first to declare and bundle 3.2.4; adcp-3.2 points at 14.4.0, rc at 14.0.0 and adcp-3.1 at 13.1.3, and the PyPI default moved to 8.1.0 on October 6 and to 8.1.1 (which adopts the signed 3.2.3 bundle) on October 8, beside 9.0.0b1, 9.0.0b2 and 9.0.0b3 prereleases; Go's newest tagged module, adcp/v3.2.1, still embeds rc.1 (adcp-go main took the 3.2.2 bundle at 10:24Z on October 7, untagged, and has not moved on to 3.2.3 or 3.2.4) and Java has no released SDK as of 22:15Z on October 13. v3.2.2 was tagged on October 4 (17:19Z; two documentation patches), v3.2.3 on October 7 (20:38Z; security errata for GHSA-2pm6-6mc8-8xcm: request_signing.required_for now applies over A2A and fails closed when a request does not resolve to one operation, plus storyboard fixes), v3.2.4 on October 12 (09:29Z; conformance fixes: new request-signing vectors, five storyboard fixes and smaller bundled schemas), v3.1.25 / v3.0.27 on October 1 (14:15Z; compliance-storyboard fixes), v3.0.28 and v3.1.26 on October 7 and v3.1.27 on October 8 (storyboard fixes and a 3.2 URL-validation backport), none of them in the versions reference on main or on the published site as of 22:15Z on October 13; since October 6 the reference on main also lists 3.3 as a pending beta (no v3.3.0-beta.0 tag as of 22:15Z on October 13); the published versions table lacks that row, though the published site’s navigation has carried a 3.3 preview section, including the 3.3 beta program page, since October 8 (#7999). Hosted grading moved to 3.2.1 with #7841 (merged 14:58Z on October 1: agents advertising 3.2 graded on the 3.2 bundle, 3.1-only agents kept on 3.1.24) and its runner to the stable 14.0.0 from 17:00Z, 14.2.0 from 16:20Z on October 6, 15.0.0 from 10:39Z and 15.2.0 from 16:32Z on October 9 (#7968, #8012) and 15.8.1 from 10:36Z on October 12 (#8148); the first public 3.2 run came at 21:48Z on October 1 (one agent, on 3.2.1; on 3.2.2 from October 5, 3.2.3 from October 8 and 3.2.4 from October 13), and the 459 public runs between October 2 and 22:15Z on October 13 carry 3.1.24 (435), the 3.2 bundles (14) and 3.0.25 (10). 3.1 is a maintained line, 3.0 the other (per the versions reference, security and critical fixes for a maintainer-decided window): GA at v3.1.0 (June 18, 2026), v3.1.3 (July 13) withdrawn four days later, patched through v3.1.24 (September 23), v3.1.25 (October 1, compliance-storyboard fixture fixes backported from #7770 and #7756), v3.1.26 (October 7, storyboard fixes) and v3.1.27 (October 8, macro-bearing URL validation backported from 3.2), none of these three in the versions reference as of 22:15Z on October 13 — 3.1.24 is eight conformance-suite changes including the governance scenarios gated on media_buy.governance_aware (#7625) and routed with the synchronized plan_id (#7555, resolving #7547), the universal lifecycle and non-governance specialisms kept ungoverned on isolated account keys (#7627 resolving #7585) and the sales baselines likewise (#7665 resolving #7628), provenance tool prerequisites (#7586), agent_url canonicalization (#7367, partial), creative format_kind, and VERSION_UNSUPPORTED recovery fatal → correctable (#7376 backport); #7547 and #7585 were filed by this site's author. v3.1.23 (September 14) carried the #7404 required_tools gate fix (#7406, the 3.1.x backport of #7405) and the v3.1.22 record correction (#7451); v3.1.21 (September 9, #7384) scoped guaranteed idempotency replay to state-mutating requests. 3.0 stays maintained, patched to v3.0.27 on October 1 and v3.0.28 on October 7 (the versions reference lists 3.0.26 as of 22:15Z on October 13). Feature detail lives in the official What's New in 3.2 and the 3.1→3.2 migration guide. Supports: Version status, AdCP 3.2 GA / v3.2.4, 3.1 maintained / v3.1.27, What's new in 3.2, 3.1→3.2 migration, 3.0→3.1 migration.
- [AdCP — What's new in AdCP 3.2](https://docs.adcontextprotocol.org/docs/reference/whats-new-in-3-2) — AgenticAdvertising.org. Official docs; confidence: primary; checked 2026-10-13. The official 3.2 feature page (GA revision of September 30, 2026; lead and numbers table revised at 18:55Z by #7815 after the #7775 flip): platform power (seller-optimized shared budgets with per-control capabilities, hard daily caps, outcome targets with optional cost-per and availability-horizon planning), a MediaBuy-level frequency cap, Reliable Reporting (experimental, media_buy.reporting_delivery), data collaboration, products declaring how audience data reaches them, clean rooms included (experimental), the compact seven-tool lifecycle behind media_buy.lifecycle_tools with the 3.x facades retained, and runtime trust (error.recovery, integer retry_after, 28 new error codes, RFC 8941 signing on 3.2 endpoints, Mcp-Session-Id never authoritative). It lists the experimental surfaces and the adopter actions per role, says sync_reporting_status becomes required Core in the next eligible minor, no earlier than October 24, 2026, and ties 3.2 badges to hosted grading on the 3.2.1 bundle. It also names @adcp/sdk 14.0.0 and adcp 8.0.0 as shipping alongside 3.2.1, which the registries did not show until October 1 (npm 12:39Z, PyPI 18:12Z). Supports: 3.2 feature set, Experimental surfaces, Adopter actions.
- [AdCP — What's new in v3](https://docs.adcontextprotocol.org/docs/reference/whats-new-in-v3) — AgenticAdvertising.org. Official docs; confidence: primary; checked 2026-06-07. 3.0 expands AdCP into brand identity, governance, media planning, and conversational brand experiences; v2 fully deprecated August 1, 2026 (UTC). Supports: 3.0 scope, Deprecation timeline.
- [AgenticAdvertising.org](https://agenticadvertising.org/) — AgenticAdvertising.org (AAO). Official standards page; confidence: supporting; checked 2026-06-07. The organization that publishes and governs AdCP — an industry body of publishers, platforms, agencies, and technology providers (in formation). Supports: Stewardship, Governance body.
- [IAB Tech Lab — Introducing the Agent Registry](https://iabtechlab.com/introducing-the-iab-tech-lab-agent-registry/) — IAB Tech Lab. Official standards page; confidence: primary; checked 2026-06-07. Trust/transparency layer for agent identity, verification, and disclosure; registrants associate a GPP ID (incl. TCF GVL IDs); the registry is itself an MCP server; "test and learn" phase. Supports: Agent Registry, Identity/verification, Status.

> Platform capabilities and naming change quickly. Last validated: 2026-10-13. Check current documentation before implementation.
