feat(adapters): add list? option to createDerivedAccountStore for spec-compliant list_accounts#1630
feat(adapters): add list? option to createDerivedAccountStore for spec-compliant list_accounts#1630bokelley wants to merge 2 commits into
Conversation
Extends `DerivedAccountStoreOptions` with an optional `list?` callback so `'derived'`-mode sellers can wire `list_accounts` for spec compliance (every seller must expose `list_accounts` OR `sync_accounts`) without changing their resolution mode. The framework's existing `if (accounts.list)` gate at `from-platform.ts:4576` auto-wires the handler when the option is set. The `account_id` refusal for `'derived'` platforms is unchanged — `list?` is for discovery only. Docs and `llms.txt` updated to distinguish the resolution mode from the factory default, and to clarify the listing-is-discovery constraint with an explicit `createTenantStore` redirect for adopters who need `account_id` addressing after listing. Closes #1628 https://claude.ai/code/session_01JhJirRzBzWgSD98zJRpsRb
Pausing the merge — Python-side reviewer flagged inverted rejection logicHeads-up from the Python team that the rejection direction in this PR (and in current main) may be backwards: that derived mode should only accept `account_id` and reject the natural-key arm. Worth investigating before this lands because if true, the new `list?` option doubles down on a wrong contract. I checked three sources before commenting: 1. AdCP 3.0.9 spec (`schemas/cache/3.0.9/core/account-ref.json`) The spec describes only two arms and ties them to `require_operator_auth`:
There is no `derived` mode in the spec. It's an SDK abstraction. 2. JS SDK (current main, `src/lib/server/decisioning/runtime/from-platform.ts:193`) `refuseInlineAccountIdWhenForbidden` rejects inline `{ account_id }` for both `'implicit'` and `'derived'`; permits the brand+operator arm in both. Documented at `AccountStore.resolution` JSDoc (`account.ts:412`). 3. Python SDK (`adcontextprotocol/adcp-client-python`, `src/adcp/decisioning/accounts.py`) `SingletonAccounts(resolution='derived')` is described as: "single-platform deployment with per-principal idempotency scoping. Synthesizes `account.id` from the verified principal." The semantics are identical to the JS `createDerivedAccountStore`: auth principal IS the tenant, no buyer-supplied `account_id`. So the JS SDK and Python SDK are aligned today. The Python team member's assertion that derived should only accept `account_id` doesn't match the Python SDK either. Possible interpretations of the flag:
Recommendation. Don't admin-merge #1630 yet. Two unblocks possible:
|
…regeneration The prior PR commit manually edited docs/llms.txt to document the new list? option on createDerivedAccountStore, but didn't update the source template in scripts/generate-agent-docs.ts:574. Running npm run generate-agent-docs would have reverted the manual change. Update the template string to match the already-correct llms.txt content so future doc regeneration preserves the list? documentation. https://claude.ai/code/session_01S6SKqBPErPdhrJ2R5scwiG
|
CI failure fixed. Pushed a fixup commit (0ef45fe) that updates On the rejection-direction question. I read the full chain before responding. @bokelley's analysis is correct:
The Python reviewer's assertion ("derived should only accept The contract this PR ships is sound. Holding on merge for the Python reviewer's clarification makes sense, but the logic itself doesn't need to change. Replied by Claude Code. Session: https://claude.ai/code/session_01S6SKqBPErPdhrJ2R5scwiG Generated by Claude Code |
|
Closing — the underlying Corrected three-mode taxonomy (after offline discussion):
Adding Tracking the rework at #1647. Spec clarification (so JS and Python don't diverge again) at adcontextprotocol/adcp#4341. Closes #1628 conceptually — the original ask (multi-tenant derived needs a path to |
|
Acknowledged. The closure rationale is clear — landing the Generated by Claude Code |
|
Noted — #1647 and adcontextprotocol/adcp#4341 are the right threads to watch. Closing the loop here. Generated by Claude Code |
|
Acknowledged — noted the forward references to #1647 and adcontextprotocol/adcp#4341. _Generated by Claude Code Generated by Claude Code |
Closes #1628
Extends
DerivedAccountStoreOptionswith an optionallist?callback so'derived'-mode sellers can wirelist_accountswithout changing their resolution mode. The framework's existingif (accounts.list)gate atfrom-platform.ts:4576already auto-wires the handler — the factory just needed to surface the option. Docs andllms.txtare updated to distinguish the'derived'resolution mode from the factory default, clarify thatlist?is for discovery/spec-compliance only (theaccount_idrefusal still fires unconditionally), and redirect adopters who needaccount_idaddressing after listing tocreateTenantStore.What tested
npm run format:check— cleantsc --noEmit— no new errors; pre-existingTS2688/TS5107environment-level errors unchanged from baseline (same as PRs fix(a2a/comply): three-layer A2A timeout fix — pollTaskCompletion + comply signal + discovery (#1612) #1613, fix(conformance): thread AbortSignal through complyImpl storyboard loop #1615)tsx) unavailable in this environment;tsc --noEmitis the type-correctness gateDerivedAccountStoreOptions.list?signature verified to matchAccountStore.list?ataccount.ts:534character-for-characterAccountFilter & CursorRequestintersection verified: allAccountFilterfields are optional, so{ limit: 10 }in the new tests satisfies the filter typeNits (not fixed, surfaced here)
assert.equal(store.list, undefined)in the newdescribe('list callback')block is redundant with the existing assertion in the outer describe — harmless but not needed### Multi-tenant derivedheading is semantically broad; a future pass could rename to### Upstream roster enumerationto be more precise for agents scanning headingsINVALID_REQUEST,account.account_id) could be promoted into the pre-example "Key constraint" bold block rather than remaining only in the post-example prosePre-PR review
AccountFilterintersection); one nit (redundantassert.equalin new test describe); changeset present and correctly typed asminorllms.txttrimmed to Shape A/B/C density with guide link; three remaining nits surfaced aboveSession: https://claude.ai/code/session_01JhJirRzBzWgSD98zJRpsRb
Generated by Claude Code