Skip to content

feat(runner): structured RunnerNotice advisory surface on StoryboardResult / ComplianceResult#1705

Merged
bokelley merged 6 commits into
mainfrom
claude/issue-1704-runner-notices
May 12, 2026
Merged

feat(runner): structured RunnerNotice advisory surface on StoryboardResult / ComplianceResult#1705
bokelley merged 6 commits into
mainfrom
claude/issue-1704-runner-notices

Conversation

@bokelley
Copy link
Copy Markdown
Contributor

Closes #1704

Summary

  • Adds notices: RunnerNotice[] to StoryboardResult (always-present, default []) and notices?: RunnerNotice[] to ComplianceResult (optional, deduped by code across all storyboard runs)
  • New exported types: RunnerNotice, NoticeCode (stable union), NoticeSeverity ('info' | 'deprecation' | 'future_required')
  • Two spec-grounded day-one notices from collectCapabilityNotices():
    • request_signing_required_in_4_0 (future_required) — on signed_requests storyboards (or storyboards with a request_signing_probe step) when request_signing.supported is absent/false
    • legacy_hmac_fallback_removed_in_4_0 (deprecation) — on webhook-related storyboards (id matches /webhook/i or has webhook assertion steps) when webhook_signing.legacy_hmac_fallback: true
  • All early-return paths (buildCapabilityUnsupportedResult, buildRequirementUnmetResult, buildRequiredToolsMissingResult, buildDiscoveryFailedResult, buildNotApplicableStoryboardResult, checkAccountDiscoveryGate) carry notices: []
  • CI gates and JUnit consumers can key on stable code values instead of parsing prose skip.detail strings

Deferred: signed_requests_specialism_deprecated — pending upstream deprecation of the 'signed-requests' specialism value in adcontextprotocol/adcp#4418; the value is still active in the spec.

Test plan

  • 13 new tests in test/lib/storyboard-notices.test.js (5 describe blocks, node:test runner, _profile injection — no live agent or schema cache needed)
  • notices always-present on StoryboardResult including early-return paths
  • request_signing_required_in_4_0 fires on signed_requests storyboard and request_signing_probe storyboards; does not fire when signing declared or on unrelated storyboards
  • legacy_hmac_fallback_removed_in_4_0 fires on webhook-scoped storyboards only; does not fire on non-webhook storyboards even when flag is set
  • Notice codes are unique per storyboard result
  • No notices when raw_capabilities absent (standalone runner without pre-fetched profile)
  • TypeScript: tsc --project tsconfig.lib.json clean (no errors)
  • Prettier: format check passes

Pre-PR review

Two expert panels reviewed the diff before this PR was opened:

Code-reviewer — no blockers; two issues addressed:

  • Fixed: buildRequiredToolsMissingResult now spreads preflightNotices (was the only early-return path missing it)
  • Fixed: legacy_hmac_fallback_removed_in_4_0 scoped to webhook storyboards via isWebhookRelatedStoryboard guard (analogous to isSignedRequestsStoryboard)
  • Fixed: capability-unsupported test now asserts notices.length === 0
  • Fixed: message length assertion aligned to JSDoc guidance (≤ 200 chars)

Protocol expert — one blocker addressed:

  • Fixed: legacy_hmac_fallback_removed_in_4_0 was firing unconditionally on every storyboard; now gated to webhook-related storyboards only (by id pattern /webhook/i or presence of webhook assertion task steps)

Triage-managed PR — opened by the triage agent for issue #1704. Do not merge without human review. The agent does not push to main and has not modified .github/workflows/, .agents/, or package.json.

https://claude.ai/code/session_01EfP3yr9YftU4Qkj9dwfZbN


Generated by Claude Code

…esult / ComplianceResult (#1704)

Adds `notices: RunnerNotice[]` to StoryboardResult (always-present) and
`notices?: RunnerNotice[]` to ComplianceResult (optional, deduped by code).
Exposes two spec-grounded day-one notices: request_signing_required_in_4_0
(future_required, scoped to signed_requests storyboards) and
legacy_hmac_fallback_removed_in_4_0 (deprecation, scoped to webhook
storyboards). CI gates can now key on stable notice codes instead of
parsing prose skip.detail strings.

https://claude.ai/code/session_01EfP3yr9YftU4Qkj9dwfZbN
Comment thread test/lib/storyboard-notices.test.js Fixed
bokelley and others added 3 commits May 11, 2026 21:52
…ner-notices

# Conflicts:
#	src/lib/version.ts
…eview

Addresses three independent expert reviews on #1705 (code-reviewer,
adtech-product-expert, dx-expert). Two blockers + four nits applied.

Blockers fixed:

1. NoticeCode is now `string` (with KNOWN_NOTICE_CODES const + KnownNoticeCode
   union for autocomplete). Every new advisory code would have been a
   TypeScript breaking change otherwise — adopters narrowing on `code` would
   see a major bump for each new notice. Matches the issue spec's
   "code: string" intent (#1704).

2. ComplianceResult.notices is now always-present (default `[]`), mirroring
   StoryboardResult.notices. Drops the conditional spread at the result
   return and the `?` on the type. Adopters can iterate
   `for (const n of result.notices)` at either level without a defensive
   `?.`. Backfills the field on three early-return paths.

Nits fixed:

3. Renamed `effective_adcp_version` -> `effective_version` to align with
   upstream spec proposal adcp#4418 and #1704.

4. `isWebhookRelatedStoryboard` no longer matches `/webhook/i` storyboard id;
   relies solely on `WEBHOOK_STEP_TASKS` step-task presence. Eliminates
   false positives like a hypothetical `webhook_authoring_guide`.

5. `request_signing_required_in_4_0` now populates the previously-dead
   `requirement: 'request_signer'` field, wiring it to the structured
   requirement name. Unblocks badge routing.

6. Both notices carry `docs_url` for adopter click-through.

7. Dedup policy commented as "last-occurrence wins" at comply.ts.

Deferred to follow-ups: dot-namespaced code naming, CLI default-output
surfacing, doc additions (TYPE-SUMMARY/llms.txt/VALIDATE-YOUR-AGENT),
AAO Verified dashboard rendering, strict-mode example in changelog.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@bokelley
Copy link
Copy Markdown
Contributor Author

Review pass

Spawned three independent expert reviewers (code-reviewer, adtech-product-expert, dx-expert) on the auto-drafted diff. Pushed two commits to address their findings.

Blockers fixed (commit 8b7e682a)

  1. NoticeCode opened to string + KNOWN_NOTICE_CODES const + KnownNoticeCode literal union for autocomplete. The original closed 2-value union meant every future notice was a TypeScript breaking change for adopters narrowing on code. The issue spec (Structured notices on ComplianceResult / StoryboardResult (warn-on-skip surface) #1704) and upstream adcp#4418 both treat code as a string.

  2. ComplianceResult.notices is now always-present (matches StoryboardResult.notices invariant). Drops the conditional spread + ? on the type. Adopters can iterate at either level without ?.. Backfilled on buildNotApplicableStoryboardResult, the second-pass return at comply.ts:1281, and buildUnreachableResult.

Nits fixed in the same commit

  • Renamed effective_adcp_versioneffective_version. Aligns with upstream spec proposal adcp#4418 and the original Structured notices on ComplianceResult / StoryboardResult (warn-on-skip surface) #1704 field name.
  • isWebhookRelatedStoryboard no longer matches /webhook/i on storyboard id — relies on WEBHOOK_STEP_TASKS set only. Eliminates false positives like a hypothetical webhook_authoring_guide storyboard. Authoring contract is "the storyboard asserts webhook delivery", which is the step-task signal.
  • request_signing_required_in_4_0 now populates requirement: 'request_signer' (previously dead field). Wires the notice to the structured requirement name for consumer badge routing.
  • Both notices carry docs_url for adopter click-through (adtech-product-expert recommendation — every dashboard / CI surface eventually wants the deep-link).
  • Dedup policy at comply.ts:1071 now has a comment naming the chosen "last-occurrence wins" policy per Map semantics.

Coordinated dependency

Merged main into the branch (commit 926ea59e) to pull in PR #1703 / commit 7de0872c — that's where 'request_signer' was added to RequirementName, which the requirement field reference depends on.

Test results

  • node --test test/lib/storyboard-notices.test.js — 5/5 describe blocks pass
  • node --test test/lib/storyboard-requires-gate.test.js — 4/4 describe blocks pass (no regressions from the merge)
  • npm run format:check clean
  • tsc --project tsconfig.lib.json clean

Deferred to follow-ups (separate issues to file)

  • Dot-namespaced code naming. adtech-product-expert recommended request_signing.required + effective_version: "4.0" as separate fields rather than _in_4_0 suffix, so codes scale into AdCP 5.0+. Worth a taxonomy doc PR after this lands.
  • CLI default-output surfacing. dx-expert: today adcp storyboard run text output doesn't show notices; only --json carries them. Follow-up to render n.notices count + one-line "DEPRECATION: …" under each storyboard summary.
  • Docs entriesTYPE-SUMMARY.md, llms.txt, VALIDATE-YOUR-AGENT.md should mention the new surface.
  • AAO Verified dashboard rendering — file a paired issue on the AAO repo; the dashboard won't auto-surface notices until it knows about the field.
  • Strict-mode example in the changelog. Document result.notices.some(n => n.severity === 'future_required') && process.exit(1) as the one-liner adopters can drop in CI to fail-on-future-required.

These are intentional follow-ups, not blockers — the surface is right and the day-one notices are useful as-is.

Convergence with #1707

The schema_version_fetch_failed notice deliverable #1707 calls out lands directly on this surface once #1707 implements dynamic schema fetch. No coordination needed beyond the existing cross-reference in #1707's body.

Ready for human review.

},
};

const profileWithLegacyHmacAndSigning = {
… CLI rendering

Applies six design decisions from review discussion:

1. **Closed `NoticeCode` literal union.** Reverts the open-string + KNOWN
   constant approach. Adopters who narrow on `code` get exhaustiveness
   checks; new codes invite explicit handling instead of silently passing
   through. The breaking-change cost is correct — a deprecation or
   future-required advisory IS the kind of signal CI gates / dashboards
   should explicitly handle.

2. **Dot-namespaced code naming.** Renamed both day-one codes:
   - `request_signing_required_in_4_0` -> `request_signing.required`
   - `legacy_hmac_fallback_removed_in_4_0` -> `webhook_signing.legacy_hmac_fallback.removed`
   The *when* lives in `effective_version`; the code stays stable across
   spec versions (no `_in_4_0` / `_in_5_0` proliferation as the spec moves).

3. **Dropped `requirement` field.** Was populated on 1 of 2 day-one
   notices; future deprecation notices won't have a structured
   `RequirementName` either. Consumers wanting cross-reference can map
   by `code` (which is stable). Can re-add as a generic `linked: {...}`
   later if real cross-reference needs emerge.

4. **CLI default-output rendering.** New `printNotices(notices)` helper
   in bin/adcp.js renders severity-badged one-liners under each
   storyboard summary AND under the multi-storyboard rollup. Aggregates
   across storyboards with `storyboard_ids` merge. Without this,
   adopters who tail the default text output never saw the signal
   (was `--json`-only previously).

5. **Storyboard-level `storyboard_ids: string[]` on every notice.** Each
   notice carries its source storyboard ids. On `StoryboardResult.notices`
   it's a single-element array; on `ComplianceResult.notices` the rollup
   merges arrays across storyboards emitting the same code. Auditors get
   "how widespread is this deprecation" without re-walking per-storyboard
   arrays; dashboards rendering badge counts still see one entry per
   unique code.

6. **Comply-level aggregation rewritten** to merge `storyboard_ids` per
   code instead of last-write-wins on the whole notice object. Order
   preserved across the run's storyboard execution order. Comment names
   the chosen first-occurrence-wins policy for the notice body.

Paired AAO-repo issue tracked separately for the dashboard-rendering
side (AAO Verified renders verdicts, not advisory payloads; needs a
dashboard-side change to surface notices).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@bokelley
Copy link
Copy Markdown
Contributor Author

Design pass shipped (commit `df86a5c3`)

All six decisions from review discussion applied:

  1. Closed NoticeCode literal union. Flipped back from open-string. Adopters narrowing on code get exhaustiveness — new codes are TS breaking changes by design (CI gates / dashboards SHOULD have explicit handling for a new deprecation or future-required signal). One-way ratchet to open later if real adopters complain; today open would be a one-way ratchet AWAY from type safety.

  2. Dot-namespaced code naming:

    • request_signing_required_in_4_0request_signing.required
    • legacy_hmac_fallback_removed_in_4_0webhook_signing.legacy_hmac_fallback.removed
      The when lives in effective_version; codes stay stable across spec versions (no _in_4_0 / _in_5_0 proliferation).
  3. Dropped requirement field. Was populated on 1 of 2 day-one notices; future deprecation notices won't have a RequirementName either. Consumers can map by code. Can re-add as a generic linked: {...} later if real cross-reference needs emerge.

  4. CLI default-output rendering. New printNotices() helper renders severity-badged one-liners under each storyboard summary AND under the multi-storyboard rollup. Aggregates across storyboards with storyboard_ids merge. Without this, adopters who tail the default text output never saw the signal.

  5. storyboard_ids: string[] on every notice. Carries which storyboards triggered the advisory. StoryboardResult.notices ships single-element arrays; ComplianceResult.notices merges across the run. Auditors see "how widespread" without re-walking arrays; dashboards rendering badge counts still see one entry per unique code.

  6. Comply-level aggregation rewritten to merge storyboard_ids per code instead of last-write-wins on the whole notice object. Order preserved across storyboard execution order. First-occurrence-wins for the notice body itself.

Paired AAO-repo issue

Filed adcontextprotocol/adcp#4436 tracking the AAO Verified dashboard side — surfaces notices[] as a distinct visual section so sellers see forward-readiness signals at the same time they see today's verdict. The wire field ships independently with this PR; the user-facing value lands when AAO renders it.

Test results

  • node --test test/lib/storyboard-notices.test.js — 5/5 describe blocks pass
  • npm run format:check clean
  • npm run build clean

Remaining deferred follow-ups (separate issues)

  • TYPE-SUMMARY / llms.txt / VALIDATE-YOUR-AGENT docs entries
  • Strict-mode "fail build on future_required" example in changelog
  • (Resolved in this commit: dot-namespacing, CLI rendering, AAO dashboard)

Ready for human review / admin merge.

@bokelley bokelley marked this pull request as ready for review May 12, 2026 02:13
@bokelley bokelley merged commit e1ec3ef into main May 12, 2026
10 checks passed
@bokelley bokelley deleted the claude/issue-1704-runner-notices branch May 12, 2026 02:18
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.

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

2 participants