Repository navigation
fix(accounts): advertise account.requests and serve account_requests on the platform path - #3586
Conversation
…on the platform path A seller registering request_account now advertises the AdCP 3.3 account.requests capability block (supported, request_task, read_task: list_accounts) and the account.requests experimental feature id, so a buyer's client.accounts.ensure routes to request_account instead of falling back to sync_accounts. capabilities.accountRequests supplies changeable_attributes, pending_action_kinds and event_type. Releases without request_account see neither the block nor the feature id. On the platform path, accounts.listRequests(request, ctx) serves the caller's requests as account_requests[] and account_requests_pagination on list_accounts when the buyer sends include_requests, request_ids or requests_pagination. It needs accounts.list; a requestAccount seller without it gets a startup warning, since buyers poll pending requests through list_accounts. Fixes #3575. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Buyers read the revision a request_account change is based on from list_accounts. The platform Account had no revision field, so a platform seller could not serve it. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
| // AdCP 3.3 account.requests: the caller's requests ride on list_accounts when asked for. | ||
| const requests = | ||
| accounts.listRequests && | ||
| (filter.include_requests === true || |
There was a problem hiding this comment.
Medium: The account_requests emission is gated by the buyer's request fields but not by the served release. filterCapabilitiesForToolAvailability deliberately hides account.requests from capabilities on pre-3.3 releases, yet this handler emits account_requests whenever the buyer sends include_requests/request_ids/requests_pagination at any release. Production defaults to validation: 'off' (create-adcp-server.ts:5732-5733), so a buyer pinned to 3.2 that sends those fields gets a 3.3-only feature on a 3.2 wire response — the exact asymmetry the capability gate exists to prevent. ctx.servedAdcpVersion is available and the file already gates other 3.3 behavior with isAdcpVersionAtLeast(servedAdcpVersion, '3.3.0-beta.0') (L1993); gate this call the same way, and add a test that a 3.2 list_accounts with include_requests returns no account_requests. (Same unconditional-emission pattern applies to Account.revision in toWireAccount, lower impact.)
There was a problem hiding this comment.
Fixed in 8f7ac80.
listRequestsnow runs only whenisAdcpVersionAtLeast(ctx.servedAdcpVersion, '3.3.0-beta.0')holds. Below 3.3,account_requestsandaccount_requests_paginationare never emitted, whatever request fields the buyer sends.Account.revisionis now removed fromlist_accountsrows served to a release before 3.2. When no served version is known, rows keep it, which is the existing behavior.- New test: a 3.1 and a 3.2
list_accountscall each sendinclude_requests,request_idsandrequests_paginationwith validation off. Neither getsaccount_requests, andlistRequestsis never called.revisionappears at 3.2 but not at 3.1. A 3.3 call still gets its requests.
There was a problem hiding this comment.
Ladon verdict: Approve
Approve — additive seller-side AdCP 3.3 account.requests support.
What I checked
- Changeset is
minor, correct for a purely additive wire change (account.requestsregistration,accounts.listRequestsonlist_accounts,Account.revisionpass-through). - Witness-not-translator: revision and requests pass through untouched; no fabrication or re-shaping at the seam.
- Capability gating is release-scoped with synthetic-block cleanup and startup throw/warn guards for missing
list/listRequests. - Tests are thorough (403 lines): capabilities gating, caller isolation, pagination, buyer ensure/refresh round-trip.
Medium findings (non-blocking)
- src/lib/server/decisioning/runtime/from-platform.ts:9299 —
account_requestsresponse emission is gated by buyer request fields but not by served release, so under productionvalidation:'off'a 3.2-pinned buyer could pull a 3.3-only feature onto a 3.2 response. Recommend gating onctx.servedAdcpVersionand adding a pre-3.3 test.
Decision rationale
No critical/high findings. gated_paths is false. high_risk is false. No author team gate. Exactly one medium finding (category not data-loss/schema/infra), which falls through to row 9 → approve. The single medium is worth addressing but does not block.
Medium findings
- src/lib/server/decisioning/runtime/from-platform.ts:9299 — account_requests response emission not gated by served release
There was a problem hiding this comment.
Ladon verdict: Approve
Approve — additive read-side field, clean diff.
This PR adds Account.revision (revision?: number) to the Account interface and emits wire.revision unconditionally in toWireAccount, consistent with every sibling optional field (sandbox, ext, credit_limit, advertiser). Release gating correctly lives downstream, not in the projection, so the witness-not-translator contract is honored and no new gap is introduced.
Checks performed:
- Changeset present and correctly typed
minorfor an additive read-side field (satisfies changeset-vs-wire-impact). - DR-0033 minor-release pathway: additive read-side field is droppable in the prior minor with no code change; no identity/mutation impact.
- Test asserts revision=3 is served and the response is schema-valid under strict validation.
The prior-run Medium (account_requests emission gating in from-platform.ts) is outside this delta and not re-flagged. No high-risk paths, no gated paths, no author-team gate.
Decision table: no critical/high findings (row 1 n/a), gated_paths false (row 2 n/a), no deletions (row 3 n/a), no medium findings (rows 4/5/8 n/a), prior decision was approve (row 6 n/a), no team gate (row 7 n/a) → row 9 approve.
…hat define them list_accounts emitted account_requests whenever the buyer sent include_requests, request_ids or requests_pagination, at any served release, while capabilities hide account.requests below 3.3. listRequests now runs only for releases from 3.3.0-beta.0, and Account.revision, an AdCP 3.2 field, is not served to an earlier release. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
…lling account.requests lives in the account capability block, whose schema requires supported_billing. The server used to fill in ['agent'] when the seller declared none, a billing claim the seller never made. It now refuses at construction and names the one-line fix (capabilities.account.supportedBilling, or capabilities.supportedBillings on the platform path). The 3.3 beta adoption tests declare it. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
There was a problem hiding this comment.
Ladon verdict: Approve
Approve — subsequent pass on PR #3586, clean.
This pass covers a two-file delta: src/lib/server/decisioning/runtime/from-platform.ts adds version gates to the list_accounts handler (account_requests fails closed behind isAdcpVersionAtLeast(served, '3.3.0-beta.0'), Account.revision stripped below 3.2), plus one new test.
Checks performed:
- Both version gates are correct — the listRequests gate short-circuits before the hook runs (verified by
listRequestCalls.length === 0), and the revision guard follows the file's served-version convention (DR-0033 minor-release backward-compat pathway handled as droppable projection). - New test covers 3.1 / 3.2 / current versions.
- Changeset present (
.changeset/account-requests-seller.md) for thesrc/lib/**changes. - No witness-not-translator violations; no official-transport-client concerns.
No critical, high, or medium findings in this run. Prior decision was approve with no findings. high_risk false, gated_paths false, no author team gate. Falls through to row 9.
There was a problem hiding this comment.
Ladon verdict: Approve
Approve — clean subsequent pass, no blocking or medium findings.
This delta (5 files, 158 lines) replaces the prior fabrication of account.supported_billing: ['agent'] with a construction-time refusal when a seller registers request_account without declaring supported_billing — correctly aligning with the witness-not-translator rule. Verified:
create-adcp-server.ts:154-165— guard scoped torequest_account, no null deref (||short-circuit).- Removal of the
syntheticAccountBlockdeletion step; declaredsupported_billinglegitimately persists to pre-3.3 releases, andfilterCapabilitiesForToolAvailabilitystill strips only.requests. - Tests and docs updated consistently; changeset stays
minor(breaking-for-experimental downgrades to normative — appropriate).
One out-of-delta note (not a finding): from-platform.ts:3065 still defaults supported_billing to ['agent'] for platform-path sellers with an account projection, so the changeset's "SDK never fills in this claim" is slightly overstated for that path — pre-existing, documented default, not introduced by this PR.
No critical/high/medium findings. high_risk false, gated_paths false, no author-team gate. Prior decision was approve with no findings. Falls through to row 9.
Fixes #3575.
A seller that registers
request_accountthroughcreateAdcpServerFromPlatform(platform, { accounts: { requestAccount } })served the tool but did not advertise it, so a TS buyer'sclient.accounts.ensurefell back tosync_accounts. The seller also had no way to returnaccount_requests[]onlist_accounts, which is the read task buyers use to poll a pending request.Capability
Registering
requestAccountnow advertises theaccount.requestsblock onget_adcp_capabilities, on bothcreateAdcpServerand the platform path:capabilities.accountRequests(changeableAttributes,pendingActionKinds,eventType). This isplatform.capabilities.accountRequestson the platform path andcapabilities.accountRequestsoncreateAdcpServer. Setting it withoutrequestAccountis a configuration error.list_collections,list_proposals): it is added for releases that definerequest_accountand removed for earlier ones. Those releases don't get theaccount.requestsblock either. A seller that listsaccount.requestsinoverrides.experimental_featureswithout registering the tool loses the claim.account.requests, its optional fields are kept, butsupported,request_taskandread_taskare always the framework's values.{ supported_billing: ['agent'] }, the same default the platform path already uses. Releases without requests don't see this block.accounts.listRequestsAccountStoregains an optionallistRequests(request, ctx) => CursorPage<AccountRequest>hook. It runs only when the buyer sendsinclude_requests,request_idsorrequests_pagination. The framework returns its items asaccount_requests[]and buildsaccount_requests_paginationfromnextCursor/totalCount. The accounts page is unchanged, and the result still passes throughreporting.projectListAccounts.listRequestswithoutaccounts.listthrowsPlatformConfigError.requestAccountwith neitherlistRequestsnor anopts.accounts.listAccountsoverride logs a startup warning, because buyers would have no way to poll a pending request.Account.revisionThe platform
Accountgainsrevision, which is now projected ontolist_accounts. Buyers read it there and send it with arequest_accountchange. Without this field, a platform seller had no way to serve it.This replaces both workarounds in the interop seller (adcontextprotocol/adcp#8679): the hand-written
capabilities.overridesblock and theprojectListAccountswrapper.Tests
test/lib/account-requests-seller.test.js:requestAccountadvertises the block and the feature id, and the response is schema-valid. A 3.2 caller sees neither.requestAccountadvertises nothing, even when overrides claim the feature.list_accountswithinclude_requests,request_idsorrequests_paginationreturns only the caller's requests, schema-valid and paged. Without those flags the hook is never called. Listed accounts carryrevision.createAdcpServer: the synthesized account block, an adopter override, andaccountRequestswithout the tool.AgentClientover in-memory MCP) runsclient.accounts.ensureagainst the server:ready, thenpending. After the seller approves,refresh()reportsreadythroughlist_accountsrequest_ids, and no duplicate request is opened.The existing capability, account and
list_accountssuites pass: 3,066 tests across 75 files, including thetoWireAccountprojection suites.Docs:
docs/guides/account-resolution.mdhas a new section, Account requests.🤖 Generated with Claude Code