Skip to content

fix(comply): forward structured adcp_error from failed storyboard steps#1684

Merged
bokelley merged 3 commits into
mainfrom
claude/issue-1679-comply-adcp-error-forwarding
May 11, 2026
Merged

fix(comply): forward structured adcp_error from failed storyboard steps#1684
bokelley merged 3 commits into
mainfrom
claude/issue-1679-comply-adcp-error-forwarding

Conversation

@bokelley
Copy link
Copy Markdown
Contributor

Closes #1679

Summary

When a storyboard step fails with a structured AdCP error (e.g. INVALID_REQUEST with field + details.validation_errors), ConversationTypes.TaskResultFailure.adcpError was silently dropped at the executeStoryboardTask boundary. The testing/types.ts TaskResult had no adcpError field, so every downstream consumer — the runner, storyboard-tracks.ts, and extractFailures() in comply.ts — only saw the human-readable error: string. This left ComplianceFailure.error as either an opaque string or {}, making AAO heartbeat grading and LLM self-correction loops unable to identify the exact fault address without re-running the step.

This PR adds adcp_error?: AdcpErrorInfo as a parallel field alongside the existing error?: string across the full compliance pipeline:

  • testing/types.ts TaskResult — new field wired at the root
  • task-map.ts executeStoryboardTask — forwards result.adcpError as adcp_error
  • storyboard/types.ts StoryboardStepResult — new field propagated by the runner
  • runner.ts step result assembly — spreads taskResult.adcp_error; suppressed on expect_error steps (mirrors existing error suppression); deleted on peer_branch_taken regrade (consistency fix caught in pre-PR review)
  • compliance/types.ts ComplianceFailure — new field on the primary machine-readable surface
  • comply.ts extractFailures() — forwards step.adcp_error into assembled failures

All changes are additive-only. error?: string is unchanged; callers reading it as a string will continue to work. The new field is optional and present only when the agent returned a structured adcp_error envelope.

What was tested

  • npm run format:check — passed ✓
  • npm run typecheck — pre-existing errors (Cannot find type definition file for 'node', deprecated moduleResolution=node10); no new errors introduced (verified by stash+recheck)
  • npm run build:lib — cannot run (no node_modules in CI sandbox)
  • npm test — 5 new tests added in task-map.test.ts; 406 pre-existing test files fail due to missing packages (zod, ws, @modelcontextprotocol/sdk) in the no-npm-install sandbox; 2 unrelated test files continue to pass. New tests will pass with npm install — the import chain (task-map → response-unwrapper → zod) is present in the pre-existing baseline failure list, not introduced by this change.

Nits noted (not fixed — out of scope for this PR)

  • runner.ts:3307 || short-circuit: if stepResult.error (client-side throw) is non-empty, taskResult?.error (protocol string) is never read. Pre-existing; tracked separately.
  • summary.ts deriveReason could prefer adcp_error.code + adcp_error.field when the struct is present. Pre-existing; tracked separately.
  • The expect_error suppression design: both "suppress" (current) and "always include" are defensible. Current choice mirrors the existing error gate and avoids consumer confusion on passing steps. Documented in StoryboardStepResult.adcp_error TSDoc.

Pre-PR review

  • code-reviewer: approved — drop site correct, expect_error suppression sound, two issues fixed (peer_branch_taken regrade inconsistency, top-level import type in compliance/types.ts); nit on runner-level suppression test noted but cannot be added without npm install environment
  • ad-tech-protocol-expert: approved — non-breaking per spec, AdcpErrorInfo is the canonical error shape, minor changeset bump is correct

Triage-managed PR. This bot does not currently iterate on
review comments or PR conversation threads (only on the source
issue). To unblock:

  • Push fixup commits directly: gh pr checkout <num>
    fix → push.
  • Or re-trigger: comment /triage execute on the source
    issue.

See adcp#3121
for context.

Session: https://claude.ai/code/session_018694zhanVSMB72JRJEQCwq


Generated by Claude Code

claude added 2 commits May 11, 2026 13:53
…ps (#1679)

Structured error detail (code, field, details.validation_errors) was silently
dropped at the executeStoryboardTask boundary. ConversationTypes.TaskResultFailure
carries adcpError but testing/types.ts TaskResult had no matching field, so every
downstream consumer (runner, storyboard-tracks, comply extractFailures) saw only
the human-readable error string.

https://claude.ai/code/session_018694zhanVSMB72JRJEQCwq
…l import

Pre-PR review (code-reviewer) noted that delete step.error in the
peer_branch_taken regrade path was not matched by delete step.adcp_error,
leaving inconsistent intermediate state on skipped StepResults.
Also converts inline import() in compliance/types.ts to a top-level
import type to match the file's header style.

https://claude.ai/code/session_018694zhanVSMB72JRJEQCwq
@bokelley
Copy link
Copy Markdown
Contributor Author

Tracking under #1685 (the SDK is a witness, not a translator). This is the keystone PR — ship this first. While step.error arrives as {}, the other four PRs (#1683, #1681, #1682, #1690) can regress silently because every failure looks identical from the grader. Once adcp_error flows through, the other four become observable in cert runs and any future politeness regression is a tripwire.

@bokelley
Copy link
Copy Markdown
Contributor Author

Acknowledged — keystone ordering noted. Holding #1683, #1681, #1682, and #1690 as observability-dependent on this merge.


Generated by Claude Code

@bokelley
Copy link
Copy Markdown
Contributor Author

Noted — thanks for the sequencing update. Once this merges, #1683, #1681, #1682, and #1690 should be clear to proceed.


Generated by Claude Code

@bokelley
Copy link
Copy Markdown
Contributor Author

Understood — noted the downstream unblock list (#1683, #1681, #1682, #1690). Nothing to act on here; this PR is ready for merge when you're set.


Generated by Claude Code


Generated by Claude Code

@bokelley
Copy link
Copy Markdown
Contributor Author

Acknowledged — standing by for merge.


Generated by Claude Code


Generated by Claude Code

@bokelley bokelley merged commit f92d9d9 into main May 11, 2026
10 checks passed
bokelley added a commit that referenced this pull request May 11, 2026
…ible via ComplianceResult (#1698)

* docs(AdcpErrorInfo): warn sellers that message/details are grader-visible

`adcp_error.message` and `.details` from seller responses are forwarded
into `ComplianceResult.failures[].adcp_error` (landed in PR #1684) — a
grader-visible archive surface that outlives the request. Three touches:

- JSDoc on `AdcpErrorInfo.message` and `.details` in ConversationTypes.ts
  with an explicit seller-side warning (grader-visible, don't embed tokens
  or internal IDs)
- New subsection §4 "Compliance failure envelopes (`adcp_error`)" in
  `docs/guides/CTX-METADATA-SAFETY.md` covering what flows where, what
  to avoid, and cross-linking to pickSafeDetails
- Two-sentence addition in `skills/build-decisioning-platform/advanced/
  REFERENCE.md` pickSafeDetails section noting the compliance-record
  leak class alongside the live-buyer-response leak class

Closes #1697

https://claude.ai/code/session_011YZtF1KAFTD54e85so2KjN

* fix(docs): correct relative path in REFERENCE.md cross-link

Three ../ hops not four from skills/build-decisioning-platform/advanced/
to repo root.

https://claude.ai/code/session_011YZtF1KAFTD54e85so2KjN

* fix: drop duplicate ValidationError import in request-normalizer

The squash-merge of #1681 (`from '../errors/index'`) and #1683
(`from '../errors'`) into main produced two identical-name imports.
TS2300 breaks the build on every PR branched off the post-merge
main. Single import resolves both.

* fix(test): pass account in pre-3.0 package shape tests

After #1683 landed, `normalizeRequestParams('create_media_buy', …)` requires
an explicit account. Add `account: { account_id: 'test-acc' }` to the two
test fixtures so the package-shape validators (#1681) are still the gate
under test.

---------

Co-authored-by: Claude <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

comply() ComplianceResult drops step.error to {} — wire-level INVALID_REQUEST detail lost

2 participants