Skip to content

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

@bokelley

Description

@bokelley

Summary

When a comply() scenario step fails, ComplianceResult.tracks[].scenarios[].steps[].error ships as {} even though the underlying SDK transport has the full structured error (adcp_error: { code, message, recovery, field, details.validation_errors }).

Repro

Run any create_media_buy-touching storyboard against a 3.0-strict seller that rejects the runner's request. Compare:

SingleAgentClient.executeTask (returns the full error):

{
  "status": "failed",
  "error": "INVALID_REQUEST: create_media_buy failed: Invalid value for field 'packages.0.product_id': Field required",
  "data": {
    "adcp_error": {
      "code": "INVALID_REQUEST",
      "message": "create_media_buy failed: ...",
      "field": "packages.0.product_id",
      "details": { "validation_errors": [...] }
    }
  }
}

comply() ComplianceResult for the same call:

{
  "step_id": "...",
  "task": "create_media_buy",
  "passed": false,
  "error": {}                              ← detail dropped
}

The comply harness is collapsing/normalizing the result and stripping the meaningful payload.

Why it matters

The comply harness output is the canonical input for AAO heartbeat grading. With error: {}, an owner staring at a failing storyboard from the dashboard cannot see what their agent actually returned wrong on the wire. Diagnosing the failure requires re-running with a different tool. This is the main reason it took several probes to discover #1676 and #1677 even though both errors were sitting on the wire all along.

Fix

Preserve the underlying transport error on every step entry. Minimum:

step.error = transportResult.error ?? {};
// or, more usefully, an object with at minimum:
step.error = {
  message: transportResult.error?.message,
  code: transportResult.error?.code,
  adcp_error: transportResult.data?.adcp_error,
};

Add a serialization test that pins this contract — step.error must be JSON-serializable and must carry the underlying error message when the step failed for a non-skip reason.

Cross-link

Same Wonderstruck probe as #1676#1678. Findings doc in adcontextprotocol/adcp .context/wonderstruck-findings.md.

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