Summary
schemas/protocol/get-adcp-capabilities-response.json makes adcp.idempotency.replay_ttl_seconds REQUIRED when the idempotency block is present, but leaves the block itself optional. This creates a trap: SDK response builders (and every canonical "minimal" example in the docs) emit capabilities without the block at all, which is schema-valid but also silently means "I have said nothing about idempotency."
Sellers that do support idempotency have to know to include both the block and the TTL. Sellers that don't can skip the whole thing — but then there's no positive signal to buyers that this seller has no replay protection. The "required-when-present" shape ends up as the worst of both worlds.
Evidence
schemas/protocol/get-adcp-capabilities-response.json ~lines 21-40 — adcp.idempotency.replay_ttl_seconds required when idempotency object is present.
- AdCP Python SDK v4.0.0-rc:
capabilities_response(["media_buy"]) emits {"adcp": {"major_versions": [3]}, "supported_protocols": [...]} with no idempotency block. Only capabilities_response(["media_buy"], idempotency=store.capability()) emits the block. 4 of 5 reference skills don't call .capability() in their minimal example.
Question
Should AdCP treat idempotency as a positive declaration (required on the top-level response, with replay_ttl_seconds: 0 meaning "not supported"), or keep it optional?
Resolution options
- Require
adcp.idempotency at the top level of the capabilities response; replay_ttl_seconds: 0 explicitly means "replay dedup not supported; callers should not retry with the same idempotency_key".
- Keep optional, but clarify in the docs that absence means "undefined behavior on replays" and require downstream SDKs to warn when a seller omits it.
- Mirror the existing
request_signing.supported: bool pattern — add idempotency.supported: bool, decouple from replay_ttl_seconds.
Option (3) feels most consistent with how request_signing is already modeled.
Surfaced during pre-4.0 DX validation: adcontextprotocol/adcp-client-python#205
Summary
schemas/protocol/get-adcp-capabilities-response.jsonmakesadcp.idempotency.replay_ttl_secondsREQUIRED when theidempotencyblock is present, but leaves the block itself optional. This creates a trap: SDK response builders (and every canonical "minimal" example in the docs) emit capabilities without the block at all, which is schema-valid but also silently means "I have said nothing about idempotency."Sellers that do support idempotency have to know to include both the block and the TTL. Sellers that don't can skip the whole thing — but then there's no positive signal to buyers that this seller has no replay protection. The "required-when-present" shape ends up as the worst of both worlds.
Evidence
schemas/protocol/get-adcp-capabilities-response.json~lines 21-40 —adcp.idempotency.replay_ttl_secondsrequired whenidempotencyobject is present.capabilities_response(["media_buy"])emits{"adcp": {"major_versions": [3]}, "supported_protocols": [...]}with no idempotency block. Onlycapabilities_response(["media_buy"], idempotency=store.capability())emits the block. 4 of 5 reference skills don't call.capability()in their minimal example.Question
Should AdCP treat idempotency as a positive declaration (required on the top-level response, with
replay_ttl_seconds: 0meaning "not supported"), or keep it optional?Resolution options
adcp.idempotencyat the top level of the capabilities response;replay_ttl_seconds: 0explicitly means "replay dedup not supported; callers should not retry with the same idempotency_key".request_signing.supported: boolpattern — addidempotency.supported: bool, decouple fromreplay_ttl_seconds.Option (3) feels most consistent with how
request_signingis already modeled.Surfaced during pre-4.0 DX validation: adcontextprotocol/adcp-client-python#205