Repository navigation
Conversation
test kit resolution
- load each storyboard's declared kit and replace only its auth block
with test_kit_auth
- keep the own auth of live-mode kits (sandbox: false)
- give storyboards that declare no kit { auth: test_kit_auth }; leave a
declared kit that cannot be loaded without the overlay
- validate the merged kit and refuse test_kit with test_kit_auth
- export the TestKitAuth type and validateTestKitAuthOverlay
runner
- drop test_kit_auth from auth: none and invalid-key probe clients
- count test_kit_auth among the run's credentials
comply
- validate test_kit_auth before contacting the agent
- authenticate discovery with test_kit_auth when no run-level auth is set
docs
- document test_kit_auth for graders that use their own credential
There was a problem hiding this comment.
Ladon verdict: Approve
Approve — additive test_kit_auth credential overlay with correct minor changeset.
What I checked:
- Changeset correctness:
minoris correct for the additive overlay feature. - Witness-not-translator: overlay is consumed from returned options; no fabrication of upstream fields.
- Credential safety:
runCredentialValuesredaction andcreateAuthOverrideClient(auth: none) both strip/covertest_kit_auth. - Validation:
validateTestKitAuthOverlayrefusestest_kit+test_kit_authtogether before the agent is contacted (tests assertagent.requests.length === 0). - Refactor of
resolveDeclaredTestKit→loadDeclaredTestKitpreserves no-overlay behavior and throw ordering; unloadable-kit path fails closed. - No new external I/O, timeouts, or async surface.
Medium findings (1):
- src/lib/testing/storyboard/test-kit.ts:318 — live-mode guard keys on
kit.sandbox === false, so a declared live kit omittingsandboxis overlaid and could grade a conformant seller FAIL (opposite polarity to the!kit.sandboxconvention at sandbox-entities.ts:115). Worth a follow-up fix.
A single medium finding with no blocking issues, no escalation trigger, no gated paths, and no team gate falls through to row 9 → approve. gated_paths is false (row 2 does not apply despite review_decision: REVIEW_REQUIRED). high_risk is false.
Medium findings
- src/lib/testing/storyboard/test-kit.ts:318 — test_kit_auth live-mode protection fails open for kits that omit
sandbox
…itted test kit resolution - replace a declared kit's auth with test_kit_auth only when the kit declares sandbox: true or carries no credential of its own - keep the own auth of a credential-bearing kit that omits sandbox, the same polarity as getSandboxEntities tests - cover a credential-bearing kit without sandbox and a probe-only kit - check every kit in the bundled compliance caches: live kits declare sandbox: false and keep their principal docs - describe the overlay rule in the guide, the option JSDoc and the changeset
There was a problem hiding this comment.
Ladon verdict: Approve
Approve — prior medium finding resolved, no new findings in the delta.
This is a subsequent review (prior outcome: approve). The earlier medium finding — test_kit_auth live-mode protection failing open for kits that omit sandbox (src/lib/testing/storyboard/test-kit.ts:318) — has been addressed. The reworked withAuthOverlay (test-kit.ts:308) now keeps a declared kit's own api_key/basic credential instead of taking the caller's overlay when sandbox is absent. Polarity matches getSandboxEntities, carriesCredential covers the two inline credential kinds (OAuth resolves via options.auth, never inline), and a new bundled-cache test exercises the credential-bearing-without-sandbox path. Changeset present and docs updated.
Decision table: no critical/high findings (row 1 n/a); gated_paths false (row 2 n/a); high_risk false (rows 3/5 n/a); no medium findings at all (rows 4/8 n/a); prior decision was approve, not escalate (row 6 n/a); no no-auto-approve team match (row 7 n/a). Falls through to row 9 → approve.
Unblocks adcontextprotocol/adcp#8929.
Problem
A grader that tests with its own credential passes it in a run-level
test_kit.resolveDeclaredTestKitloads a storyboard's declared kit (prerequisites.test_kit) only whenoptions.test_kitis unset. So that run-level kit replaces every declared kit, and no storyboard gets its own fixtures:$build_assets_from_format;commercial_relationshipfor phaseskip_if;creative_build_probes;creative_formats.AAO's hosted
comply()does exactly this (adcp#8929). adcp#8930 works around it by copying one kit'sassetsinto the run kit.routeStoryboardcannot fix this from the host side:comply()does not call it for the discovery-diagnostic branch, for capability-gated storyboards, or inrunWithDegradedProfile.route.storyboardcannot change the kit fields the runner reads directly.Changes
src/lib/testing/storyboard/test-kit.tsresolveDeclaredTestKittakestest_kit_auth, a credential laid over the declared kit:sandbox: truekeeps every field exceptauth, which the overlay replaces whole. None of the kit's ownapi_key,basicorprobe_tasksits next to the caller's credential.auth.api_keyorauth.basic, as in runner-contract kits) gets the overlay as itsauth.sandbox: false, or carries a credential without declaringsandbox: true, keeps its ownauth(or none). It may be the live-mode principal the storyboard tests (comply_controller_mode_gate grades false FAIL against conformant sellers: from_test_kit never resolves the storyboard-declared kit (silent no-auth locally; seller-bearer substitution in the hosted engine) adcp#6735). An absentsandboxis never read as sandbox, the same polarity asgetSandboxEntities().{ auth: test_kit_auth }, which is what a run-level kit gives it today.from_test_kitsteps fail as a configuration error, as they do withouttest_kit_auth.test_kit_auth.validateTestKitAuthOverlay, also exported from the storyboard barrel next tovalidateTestKit:test_kittogether withtest_kit_auth, withTestKitValidationErroron fieldtest_kit_auth.test_kit.authrules:probe_taskis required and must be allowlisted, andapi_keymust be printable ASCII.test_kit.authmessages are unchanged.loadDeclaredTestKit, which keeps the same containment, symlink and error behaviour.src/lib/testing/types.ts,agent-tester.ts,index.tsTestKitAuthtype, the shape oftest_kit.auth.TestOptions.test_kit_auth?: TestKitAuth, documented.src/lib/testing/storyboard/runner.tscreateAuthOverrideClient(used forauth: nonesteps and invalid-key probes) dropstest_kit_authas it already dropstest_kit, so neither can be promoted back into the probe's credential.runCredentialValuestreatstest_kit_authas a credential the run holds, for header exclusion and evidence scrubbing.src/lib/testing/compliance/comply.tscomply()validatestest_kit_authup front, before contacting the agent.comply()runs, on any branch, goes throughrunStoryboard, which resolves the kit per storyboard.src/lib/testing/client.tsauth, the transport falls back totest_kit_authwhen there is notest_kit.comply()'s own discovery then authenticates the way it does withtest_kit: { auth }.test_kit: null.src/lib/testing/local-agent-runner.tsresolvePerStoryboardJSDoc says a per-storyboardtest_kitoverride on a run withtest_kit_authmust also settest_kit_auth: undefined.Docs
docs/guides/VALIDATE-YOUR-AGENT.md: how to grade with your own credential and keep declared kits.docs/guides/CREATIVE-BUILD-PROBE.md:test_kit_authkeeps the declared kit's recipes.Tests
New file:
test/lib/storyboard-test-kit-auth-overlay.test.js, 15 tests. All of them fail onmain. The two added for thesandboxpolarity fix also fail on the first commit of this PR.Unit tests on
resolveDeclaredTestKit:basicincluded, becomes the overlay;probe_taskonly) gets the overlay;sandboxkeeps it;sandbox: falseand keep their principal,sandbox: truekits and runner kits take the overlay, and a credential-bearing kit withoutsandboxkeeps its credential;{ auth };probe_taskis replaced before validation;comply()tests against a loopback MCP agent that records each probe'sAuthorizationandx-adcp-authheaders and its arguments. Each probe sits in a phase gated on its own kit'sfixture_marker, and the kit-less storyboards have a phase that runs only if a marker leaked. They check that:auth: nonesteps send noAuthorizationand nox-adcp-auth, with and without run-levelauth;auth, discovery authenticates with the overlay;test_kit+test_kit_auth, and an overlay withoutprobe_task, are refused with no request to the agent.Existing suites:
test/lib/storyboard-declared-test-kit.test.js: 20/20.comply()/testing-client suites pass. The only local failures come from incomplete schema caches in my checkout and fail identically onmain.tsc --noEmit, eslint (no new warnings) and prettier are clean.npm run review:codex -- --all --base mainwas not run: the codex CLI is not available in this environment.Changeset
@adcp/sdkminor (.changeset/test-kit-auth-overlay.md): a new option and type, no breaking change.Notes for graders: kit principals under the overlay
Inventory of the kits in the 4 bundled SDK caches, adcp source, and the 68 published adcp bundles:
the only live-mode kit (
acme-outdoor-live.yaml) declaressandbox: false;every brand kit declares
sandbox: true;runner-contract kits omit
sandbox, andbilling-gate-runner.yamlis the only one with a credential.billing-gate-runner.yaml.sandboxand carriesdemo-billing-passthrough-v1, the spoofable test principal mapped tocommercial_relationship: passthrough_only. So it keeps that credential.per_agent_gate_rejectphase then runs for sellers that advertiseagentbilling, under that demo principal, exactly as a local run does.canonical_formats. It describes the kit key as "a different buyer principal from the one controller seeding ran under". Withtest_kit_authset to the transport credential, the two principals are the same, as on hosted runs today.Out of scope / follow-ups
comply()passes the owner credential astest_kit_authinstead of a run-leveltest_kit;assetscopy and its drift guard;liveModeTestKitRoute(adcp#7772) if it is no longer needed;billing-gate-runnernote and decide thecanonical_formatsnote above.docs/guides/CREATIVE-BUILD-PROBE.mdsentence "Hosted auth defaults … do not merge missing recipes from a separately declared brand kit" goes stale and needs updating.--test-kit.🤖 Generated with Claude Code