Skip to content

Structured notices on ComplianceResult / StoryboardResult (warn-on-skip surface) #1704

@bokelley

Description

@bokelley

Summary

The runner has no structured advisory surface today. Skips carry reason + detail + requirement; there's no severity, no code, no machine-readable way to say "this passed/skipped now but will fail in 4.0" or "you're using a deprecated claim shape." Three open gaps make this load-bearing:

  1. Unimplemented SHOULD already in the spec. compliance/{version}/universal/signed-requests.yaml:34 says:

    the runner SHOULD emit an informational notice (not a failure) advising the agent to drop the now-redundant specialism claim and rely solely on request_signing.supported: true.
    The SDK does not emit any notice today. The SHOULD has been silently unimplemented since the deprecated signed-requests specialism enum landed.

  2. 4.0 forward-readiness signals have nowhere to live. Per schemas/cache/3.0.11/protocol/get-adcp-capabilities-response.json:892, request_signing is "Required for spend-committing operations in 4.0". Same file at line 966: legacy_hmac_fallback is "Deprecated; removed in AdCP 4.0." A 3.0 seller that legitimately skips signed_requests today (per comply(): autodetect request_signer and oauth_metadata requirements (mirror webhook_receiver autodetect from #1678) #1702) will fail compliance on the 4.0 cut with no advance warning unless the runner surfaces the signal.

  3. Skip detail strings are a workaround, not a feature. comply(): autodetect request_signer and oauth_metadata requirements (mirror webhook_receiver autodetect from #1678) #1702 / PR fix(comply): autodetect request_signer + pre-empt oauth_discovery (#1702) #1703 currently rides the 4.0 forward-readiness suffix in skip.detail as a copy-edit. That works for the human report rendering but is unparseable for dashboards, JUnit consumers, or CI gates that want to display "DEPRECATION" / "FUTURE-REQUIRED" badges. The detail string is the wrong shape for downstream automation.

Proposed shape

Add notices: RunnerNotice[] to StoryboardResult (and likely surface it transitively on ComplianceResult):

```ts
export interface RunnerNotice {
/** Severity. `info` = behavior is fine today, here is context. `deprecation` = SHOULD migrate. `future_required` = will be required in a named future version; cite the version. /
severity: 'info' | 'deprecation' | 'future_required';
/
* Stable machine-readable identifier so dashboards can render badges / aggregate. /
code: string;
/
* Human-readable explanation; first 200 chars suitable for tabular rendering. /
message: string;
/
* When `future_required`, the AdCP version that flips the requirement. /
effective_version?: string;
/
* When relevant, the structured requirement name (matches `RunnerSkipResult.requirement`). /
requirement?: RequirementName;
/
* Path into the agent's capability response that motivated the notice (e.g. `request_signing.supported`). */
capability_path?: string;
}
```

Concrete notices to emit on day one:

Code Severity Trigger
`signed_requests_specialism_deprecated` `deprecation` agent advertises legacy `specialisms: ['signed-requests']` enum (covers signed-requests.yaml:34)
`request_signing_required_in_4_0` `future_required` runner skipped `signed_requests` because `request_signing.supported !== true` (PR #1703 case)
`legacy_hmac_fallback_removed_in_4_0` `deprecation` agent advertises `webhook_signing.legacy_hmac_fallback: true`

Why a runner-output shape, not just a CLI report tweak

The runner output is what dashboards, JUnit consumers, and downstream Verified pipelines consume. Anything that wants to surface "passed but plan ahead" needs a stable field on the output contract, not prose in a detail string. Once the field exists, the CLI / HTML / JUnit renderers light it up consistently.

Relationship to upstream

Filing a parallel issue on `adcontextprotocol/adcp` to ask whether `runner-output-contract.yaml` should standardize the notices shape so the AdCP Verified runner and third-party CI gates converge. If upstream picks up the field, the SDK becomes a reference implementation. If upstream stays silent, the SDK keeps it as a runner-output extension. Either path lands real value; I'd rather not bake an opinion the spec can't share.

References

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions