You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
The 'derived' resolution mode is currently shipped with inverted wire semantics. It's documented and implemented as "single-tenant; refuse account_id; permit brand+operator," but the pattern adopters actually need — and that the dominant programmatic/social case requires — is the opposite: upstream platform owns the roster, buyer must list_accounts, buyer passes account_id on every subsequent call, sync_accounts is forbidden.
The "single-tenant agent" framing was a mistake. AudioStack and flashtalking sit in this mode at N=1 (one account per credential); Meta/Snap/Figma MCP sit in this mode at N=many. The wire contract is identical — roster size is an operational property of the upstream, not a different SDK pattern.
Corrected three-mode taxonomy
Mode
Roster owner
Onboarding
Wire reference
'explicit'
Seller (no list)
None
account_id inline
'implicit'
Buyer-declared
sync_accounts
brand + operator
'derived'
Upstream platform
list_accounts
account_id inline
Concrete changes
Invert refuseInlineAccountIdWhenForbidden for derived.src/lib/server/decisioning/runtime/from-platform.ts:193, 1201 currently refuses { account_id } for both 'implicit' and 'derived'. For derived it should refuse the brand+operator union arm and acceptaccount_id. Implicit's behavior is unchanged.
Refuse sync_accounts dispatch when resolution: 'derived'. Either fail at platform-config time when the adopter wires accounts.upsert alongside 'derived', or return UNSUPPORTED_FEATURE at dispatch. Upstream owns the roster.
Update AccountStore.resolution JSDoc at src/lib/server/decisioning/account.ts:389-412 and docs/guides/account-resolution.md to reflect the corrected taxonomy. The "Multi-tenant derived" framing disappears — derived is uniformly upstream-managed regardless of N.
Update scripts/generate-agent-docs.ts source string (the "Four reference AccountStore shapes" paragraph) so the regenerated docs/llms.txt matches the corrected semantics.
Audit reference adapters (audiostack, flashtalking, scope3data/agentic-adapters#100) — createDerivedAccountStore's toAccount(ctx) callback now needs to verify a buyer-supplied account_id matches what the credential maps to, instead of being a pure "ignore the ref, return the singleton" shortcut.
Migration / breaking-change scope
Technically breaking for any adopter relying on current (inverted) rejection behavior. In practice the inverted behavior is unusable for upstream-managed adapters (they can't get account_id through), so adopters that successfully shipped with 'derived' today are either:
N=1 single-tenant (audiostack-shape) where toAccount(ctx) ignores the ref — minor adjustment to verify the ref instead
Bypassing the SDK's resolve and routing on credential themselves — unaffected
Major version bump warranted. Feature flag (accounts.resolutionVersion: 2) considered but probably not worth the dual-codepath maintenance.
Reference adapter scope3data/agentic-adapters#100 (AudioStack) — confirm no breakage during the rework.
Python SDK (adcp-client-python) had a partial inverse intuition (their reading: derived only accepts account_id); neither SDK had the full picture. Spec clarification keeps both aligned going forward.
What
The
'derived'resolution mode is currently shipped with inverted wire semantics. It's documented and implemented as "single-tenant; refuseaccount_id; permit brand+operator," but the pattern adopters actually need — and that the dominant programmatic/social case requires — is the opposite: upstream platform owns the roster, buyer mustlist_accounts, buyer passesaccount_idon every subsequent call,sync_accountsis forbidden.The "single-tenant agent" framing was a mistake. AudioStack and flashtalking sit in this mode at N=1 (one account per credential); Meta/Snap/Figma MCP sit in this mode at N=many. The wire contract is identical — roster size is an operational property of the upstream, not a different SDK pattern.
Corrected three-mode taxonomy
'explicit'account_idinline'implicit'sync_accounts'derived'list_accountsaccount_idinlineConcrete changes
refuseInlineAccountIdWhenForbiddenfor derived.src/lib/server/decisioning/runtime/from-platform.ts:193, 1201currently refuses{ account_id }for both'implicit'and'derived'. For derived it should refuse the brand+operator union arm and acceptaccount_id. Implicit's behavior is unchanged.sync_accountsdispatch whenresolution: 'derived'. Either fail at platform-config time when the adopter wiresaccounts.upsertalongside'derived', or returnUNSUPPORTED_FEATUREat dispatch. Upstream owns the roster.list_accounts(not OR) for derived in the storyboard: missing required-account tool should fail, not skip #1624 compliance gate. Currentlylist_accountsORsync_accounts. For derived it must belist_accountsonly.AccountStore.resolutionJSDoc atsrc/lib/server/decisioning/account.ts:389-412anddocs/guides/account-resolution.mdto reflect the corrected taxonomy. The "Multi-tenant derived" framing disappears — derived is uniformly upstream-managed regardless of N.scripts/generate-agent-docs.tssource string (the "Four reference AccountStore shapes" paragraph) so the regenerateddocs/llms.txtmatches the corrected semantics.createDerivedAccountStore'stoAccount(ctx)callback now needs to verify a buyer-suppliedaccount_idmatches what the credential maps to, instead of being a pure "ignore the ref, return the singleton" shortcut.Migration / breaking-change scope
Technically breaking for any adopter relying on current (inverted) rejection behavior. In practice the inverted behavior is unusable for upstream-managed adapters (they can't get
account_idthrough), so adopters that successfully shipped with'derived'today are either:toAccount(ctx)ignores the ref — minor adjustment to verify the ref insteadMajor version bump warranted. Feature flag (
accounts.resolutionVersion: 2) considered but probably not worth the dual-codepath maintenance.Cross-references
list?to derived but kept the inverted rejection logic and the single-tenant framing.account-ref.jsondescription currently doesn't disambiguate upstream-managed roster from'explicit'; needs explicit wording so JS and Python SDKs implement the same contract.scope3data/agentic-adapters#100(AudioStack) — confirm no breakage during the rework.adcp-client-python) had a partial inverse intuition (their reading: derived only acceptsaccount_id); neither SDK had the full picture. Spec clarification keeps both aligned going forward.