v5.8.1
Patch Changes
-
f61f284: Re-export the storyboard assertion registry (
registerAssertion,
getAssertion,listAssertions,clearAssertionRegistry,
resolveAssertions, and typesAssertionSpec,AssertionContext,
AssertionResult) from@adcp/client/testingso authors of invariant
modules can import them from the documented package entry point. The
underlying module (./storyboard/assertions) already exported these;
only the parent./testingindex was missing the re-exports. Closes
the gap introduced by #692. -
bdebac9:
refs_resolvescope: canonicalize$agent_urlby stripping transport
suffixes instead of comparing raw target URL to bare agent origins.Before this fix, storyboards using
scope: { key: 'agent_url', equals: '$agent_url' }silently graded every source refout_of_scopeon MCP
and A2A runners, because$agent_urlexpanded to the runner's target
URL (with/mcp,/a2a, or/.well-known/agent.jsonsuffixes) while
refs carried the bare agent URL per AdCP convention. Net effect: the
check degraded from integrity enforcement to a no-op on every MCP agent.The scope comparator now mirrors
SingleAgentClient.computeBaseUrl:
strip/mcp,/a2a,/sse, and/.well-known/agent[-card].json
suffixes; lowercase scheme and host; drop default ports; strip
userinfo, query, and fragment. Path below the transport suffix is
preserved, so sibling agents at different subpaths on a shared host
(e.g.https://publisher.com/.well-known/adcp/salesvs
/.well-known/adcp/creative) remain distinguishable. Closes #710. -
bdebac9:
refs_resolve: harden grader-visible observation andactual.missing
payloads against hostile agent responses.Compliance reports may be published or forwarded to third parties, so
every ref field emitted by the runner is now:- Userinfo-scrubbed on URL-keyed fields via WHATWG URL parsing plus
a regex fallback that scrubsscheme://user:pass@shapes embedded
in non-URL fields. Credentials planted inagent_urlvalues can no
longer leak through compliance output. - Scheme-restricted on URL-keyed fields: non-
http(s)schemes
(e.g.javascript:,data:,file:) are replaced with a
<non-http scheme: …>placeholder so downstream UIs rendering
agent_urlas a link cannot inherit a stored-XSS vector. - Length-capped at 512 code points per string field, with a
code-point-boundary truncation that preserves surrogate pairs. - Count-capped at 50 observations per check, with an
observations_truncatedmarker when the cap fires. Meta
observations (scope_excluded_all_refs,target_paginated)
precede per-ref entries so the cap never drops primary signal.
Match and dedup behavior is unchanged: the internal projection used
for ref comparison is kept separate from the sanitized projection used
for user-facing output, so truncation never false-collapses dedup
keys.refsMatchandprojectRefalso now usehasOwnPropertyto
prevent storyboard authors from accidentally drawing match keys from
Object.prototype. Closes #714. - Userinfo-scrubbed on URL-keyed fields via WHATWG URL parsing plus
-
bdebac9:
refs_resolve: emit ascope_excluded_all_refsmeta-observation when
a scope filter partitions every source ref out. The integrity check
enforces nothing when no ref falls in-scope; graders previously got a
silent pass. The meta-observation surfaces the structural smell without
changing pass/fail semantics. Suppressed underon_out_of_scope: 'ignore'
(which explicitly opts out of scope warnings). Closes #711. -
bdebac9:
refs_resolve: detect paginated current-step targets and demote
unresolved refs to observations instead of failing the check.Previously, when the target response carried
pagination.has_more: true, any ref legitimately defined on a later page graded as
missing— a false-positive failure against a conformant paginating
seller. The runner now emits atarget_paginatedmeta-observation and
reports each would-be-missing ref as anunresolved_with_pagination
observation, letting the check pass until the spec-level resolution
lands (compliance mode requiring sellers to return everything
referenced by products in a single response). Closes #712. -
c4ff3e6: Skill example refresh to match recent upstream schema changes and fix a brand-rights coverage gap surfaced by the
compliance:skill-matrixdogfood harness:list_creative_formats.renders[]: upstream restructured renders to requireroleplus exactly one ofdimensions(object) orparameters_from_format_id: trueunderoneOf. Updated seller, creative, generative-seller, and retail-media skill examples; flaggedrenders: [{ width, height }]as the canonical wrong shape.get_media_buys.media_buys[]:currencyandtotal_budgetare now required per row. Seller skill example now shows both; added a persistence note (save these fields oncreate_media_buyso subsequent queries can echo them).contextresponse field: schema-typed asobject. Across all 8 skills, rewrote the "Context and Ext Passthrough" section to stop recommendingcontext: args.contextecho (which fabricates string values whenargs.contextis undefined or confused with domain fields likecampaign_context). Explicit guidance: leave the field out of your return —createAdcpServerauto-injects the request's context object; hand-setting a non-object string fails validation and the framework does not overwrite.- Brand-rights governance flow: the
brand_rights/governance_deniedscenario expects the brand agent to callcheck_governancebefore issuing a license. Addedaccounts: { syncAccounts, syncGovernance }handlers and acheckGovernance()call in theacquireRightsexample, returningGOVERNANCE_DENIEDwith findings propagated from the governance agent. - Seller idempotency section: referenced adcontextprotocol/adcp-client#678 as a known grader-side limitation on the missing-key probe (MCP Accept header negotiation), so builders don't chase a skill fix for what's actually a grader issue.