Skip to content

fix: support seed_account comply controller#2288

Merged
bokelley merged 2 commits into
mainfrom
seed-account-unknown-scenario
Jun 26, 2026
Merged

fix: support seed_account comply controller#2288
bokelley merged 2 commits into
mainfrom
seed-account-unknown-scenario

Conversation

@bokelley

Copy link
Copy Markdown
Contributor

Summary

  • Adds seed_account support to the lower-level comply_test_controller store/dispatcher and createComplyController typed facade.
  • Teaches storyboard fixture seeding to emit seed_account calls from fixtures.accounts[], including the current { account_id, fixture } storyboard shape.
  • Includes seed.account in platform capability projection so get_adcp_capabilities.compliance_testing.scenarios matches list_scenarios.
  • Adds a patch changeset.

Root Cause

seed_account was present in the protocol schema, but the SDK helper surfaces did not enumerate or dispatch it. Storyboard seeding also ignored fixtures.accounts[], so pagination-integrity account fixtures were never seeded.

Validation

  • npm run build:lib
  • NODE_ENV=test node --test-timeout=60000 --test-force-exit --test test/comply-controller.test.js
  • NODE_ENV=test node --test-timeout=60000 --test-force-exit --test test/server-test-controller.test.js
  • NODE_ENV=test node --test-timeout=60000 --test-force-exit --test test/lib/storyboard-controller-seeding.test.js
  • NODE_ENV=test node --test-timeout=60000 --test-force-exit --test test/server-decisioning-comply-test.test.js
  • git diff --check
  • Pre-push validation: typecheck + build passed

Review

Ran parallel expert review (protocol, code review, Node.js testing). Initial findings on account fixture unwrapping and capability projection were fixed; re-checks reported no remaining actionable issues.

Local Repro

Against origin/main, createComplyController({ seed: { account } }) returns UNKNOWN_SCENARIO for seed_account and advertises no seed scenario. This branch advertises seed_account, dispatches to the adapter, and emits the three seed_account calls from the cached pagination-integrity-list-accounts storyboard.

@bokelley bokelley marked this pull request as ready for review June 26, 2026 15:55
aao-ipr-bot[bot]
aao-ipr-bot Bot previously approved these changes Jun 26, 2026

@aao-ipr-bot aao-ipr-bot Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Clean additive wiring of seed_account across all five touch points. Right shape: the dispatcher fails closed — UNKNOWN_SCENARIO when the store omits seedAccount, INVALID_PARAMS when params.account_id is absent — and the storyboard seeder lifts account_id into params with the rest unwrapped into fixture, byte-for-byte the established seed_* contract.

Things I checked

  • Spec-faithful, not fabricated. seed_account is named in the spec request schema (src/lib/types/tools.generated.ts:25479 — "Account to ... seed. Used by ... seed_account"). The SDK is wiring a defined scenario, not inventing one. ad-tech-protocol-expert: sound.
  • The as unknown as ControllerScenario cast (comply-controller.ts:655) is correct and necessary — seed_account is absent from the v3-1-beta ListScenariosSuccess.scenarios enum (src/lib/types/v3-1-beta/tools.generated.ts:23492-23512, which lists seed_product but not seed_account). The enum docstring normatively mandates open-extension ("Runners and sellers MUST accept unknown scenario strings"), so this is the house convention for seed_buyer_agent / force_audience_status, not a new smell.
  • Fail-closed dispatch at test-controller.ts:904-916account_id checked before store.seedAccount, cache key seed_account:${accountId} matches the per-(kind,id) convention, shared fixture derivation inherits the prototype-pollution guard.
  • No mock-data injection. fixture ?? {} passes straight through to the registered adapter (comply-controller.ts:519-521). Witness, not translator — preserved.
  • Changeset present (.changeset/seed-account-controller.md), patch. Both experts confirm patch is right for an additive opt-in testing scenario.
  • Tests cover routing, INVALID_PARAMS, UNKNOWN_SCENARIO, fixture unwrapping (nested {account_id, fixture} and flat-field shapes), ordering, and capability projection through from-platform.ts.

Follow-ups (non-blocking — file as issues)

  • The v3-1-beta ListScenariosSuccess.scenarios enum omits seed_account while the request schema names it. A buyer running closed-world schema validation against the beta schema could reject a list_scenarios response that advertises seed_account. This is an upstream schema lag, not an SDK bug — file an issue on adcontextprotocol/adcp to add seed_account to the response enum, then the cast can be dropped when codegen catches up. Triage order (spec → mock → SDK) confirms the spec defines the contract; the enum is the lagging artifact.

Minor nits (non-blocking)

  1. Cast line placement. comply-controller.ts:641 puts the new seed_account push (which needs the cast) directly above the un-cast seed_product group, rather than below the comment at line 648 that explains the extension-cast convention alongside seed_buyer_agent / force_audience_status. Reads slightly anomalous — a cast line in the no-cast block. Cosmetic.

Approving on the strength of the fail-closed dispatch plus both experts returning sound.

@aao-ipr-bot aao-ipr-bot Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Clean additive change. seed_account mirrors the existing seed_product/seed_buyer_agent extension pattern at every layer — store, dispatcher, typed facade, capability projection, and storyboard seeding — so the new scenario inherits every existing guard rather than carving a new path.

Things I checked

  • seed_account is real protocol surface, not fabricated. ad-tech-protocol-expert: sound — seed_account is enumerated in the generated schema (tools.generated.ts:25467), with params.account_id documented (:25479) and scenario an open string field. The PR is filling a genuine SDK enumeration/dispatch gap, exactly as the body claims.
  • Dispatch correctness (test-controller.ts:906-916): missing account_idINVALID_PARAMS; absent store.seedAccountUNKNOWN_SCENARIO. Param-check-then-store-check ordering matches every sibling case. The prototype-pollution guard (:882-892) and fixture-must-be-object guard run before the switch, so the account fixture inherits both.
  • The as unknown as ControllerScenario cast (comply-controller.ts:651) is the established escape hatch for scenarios not yet widened into the narrower ListScenariosSuccess['scenarios'] response union — identical to seed_buyer_agent/force_audience_status on the adjacent lines. Witness, not translator: seedFixtureFromFields passes fixture fields through verbatim, only coercing fixture ?? {} for an absent fixture.
  • No new auth surface. security-reviewer: the sandbox-authority gate (from-platform.ts:1799-1897) keys on the resolved-account mode, not the scenario string — adding a switch arm cannot widen it. seed_account has no auto-seed fallback (auto-seed only fills product/pricing_option), so nothing writes account fixtures unless the adopter explicitly wires seed.account. No fixture logging in test-controller.ts; safeEcho never reflects params/fixture.
  • buildSeedCalls account_id-lifting (seeding.ts:80-98): destructures account_id, routes the rest through the shared seedFixtureFromFields, handles both nested-fixture and direct-field storyboard shapes, and emits an authoring_error without issuing the seed on an empty/non-string id. Tests cover both shapes plus ordering and the authoring-error case.
  • Changeset present, Changeset Check will pass.

Follow-ups (non-blocking — file as issues)

  • The list_scenarios response union (ControllerScenario) lags the open scenario set, so each new extension scenario accrues an as unknown as cast in advertisedScenarios. Worth widening the codegen source so the cast pile stops growing — ad-tech-protocol-expert flagged the same thing.
  • patch is defensible (the repo treats these test-controller extension adapters as patch-level additive surface, and SeedAccountParams + seed.account are purely additive with no behavior change). Strictly, a new exported type leans minor — note it for the next version-bump audit, but it doesn't understate impact in a way that breaks semver consumers.

Minor nits (non-blocking)

  1. SeedAccountParams JSDoc invites secrets into fixtures. The "billing/rate-card metadata, authorization" wording (comply-controller.ts:97-103) could nudge adopters toward live credentials in sandbox fixtures. A one-line pointer to docs/guides/CTX-METADATA-SAFETY.md would close that. Docs-only.

LGTM. Follow-ups noted below.

@bokelley bokelley merged commit 26c7053 into main Jun 26, 2026
31 checks passed
@bokelley bokelley deleted the seed-account-unknown-scenario branch June 26, 2026 16:16
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant