Unknown fixture エラー
sample_request はハードコードされた ID(test-product、test-pricing、campaign_hero_video、gov_acme_q2_2027 など)を参照します。ランナーは、変更ステップが実行される前にエージェントがその ID をカタログに持つことを期待します。
修正: comply_test_controller を実装し、ストーリーボードの fixtures: ブロックで宣言されたシードシナリオを尊重します。prerequisites.controller_seeding: true が設定されると、ランナーは、メインフェーズが実行される前に外部キー順で seed_product、seed_pricing_option、seed_creative、seed_plan、seed_media_buy を呼ぶフィクスチャフェーズを自動注入します。
完全なシードコントラクトについては コンプライアンステストコントローラー — シナリオ を参照。シード呼び出しで UNKNOWN_SCENARIO を返すエージェントは、ストーリーボードを not_applicable とグレードします — 欠けているサンドボックスサーフェスでペナルティを受けませんが、事前シードされた状態に依存するストーリーボードを通過できません。
401 で署名チャレンジが欠けている
get_adcp_capabilities.request_signing.required_for で宣言された操作に未署名リクエストを送りました。エージェントは 401 で拒否しましたが WWW-Authenticate: Signature ... チャレンジヘッダーを含めなかったため、ランナーはトランスポートバインディングからエラーコードを解決できませんでした。
修正: 欠けているまたは無効な署名によって引き起こされるすべての 401 で RFC 9421 チャレンジヘッダーを発します。ランナーはトランスポートバインディング順序経由でエラーコードを解決します — WWW-Authenticate ヘッダーが欠けている場合、JSON ボディが有用なメッセージを運んでもエラー分類は「(none)」にフォールバックします。
リファレンス SDK は、これらのエラーを @adcp/sdk/signing の RequestSignatureError 経由で .code: RequestSignatureErrorCode で構築します。完全なタクソノミー(request_signature_required、request_signature_header_malformed、request_signature_tag_invalid、request_signature_window_invalid、request_signature_key_unknown など)はそのモジュールで列挙されます。エージェントは、SDK を話す呼び出し元が自動的に回復できるよう、チャレンジで同じコードをサーフェスすべきです(SHOULD)。
チャレンジヘッダー形式については 署名付きリクエスト(トランスポート層) と transport-error バインディング順序 を参照。
レスポンスエンベロープドリフト
check: error_code を使いましたが、あなたのレスポンスはランナーのクライアント検出順序が期待しなかった形状でエラーをサーフェスします。実際には、これはトランスポート層が既に adcp_error を運んでいたときエージェントが errors[] を返した(またはその逆)ことを意味します — ストーリーボードは単一のエラーコードをアサートし、ランナーはあなたが発したのと異なる層からそれを解決しました。
修正: エンベロープ対ペイロードの 2 層モデル に従い、レスポンスごとに 1 つのエラーサーフェスを選び、それに固執します。MCP: 構造化コンテンツには adcp_error、タスクペイロードエラーには errors[]。A2A: 同じ層が適用 — エンベロープのトランスポートエラー、タスクアーティファクトの DataPart のアプリケーションエラー。
ランナーの check: error_code は形状非依存 — どちらの層からも解決する — が、エージェントが両方を同時に発すると不一致になりえ、ランナーは解決されたコードをベクターの期待に対してグレードします。1 つのサーフェスを選び一貫していれば分岐を避けます。
コンテキストエコー失敗
context: オブジェクトを含まないレスポンスを返しました。context: { correlation_id: ... } を送るすべてのストーリーボードステップは、context.correlation_id がレスポンスで変更なくエコーされることをアサートします。
修正: エラーを含むすべてのレスポンスで完全な context: オブジェクトを逐語的に保持します。エコーコントラクトは規範的 — バイヤーは correlation_id を使ってマルチエージェントフローをつなぎ、ランナーはすべてのコンテキストを運ぶステップをそれでグレードします。Context and sessions — 規範的エコーコントラクト を参照。
キャプチャは同じコントラクトを逆に使います: context_outputs: を通じて "$context.<name>" を渡すストーリーボードは、プロデューサーステップの検証が通過した後にキャプチャが投入されることに依存します。プロデューサーが失敗または context: を省略したとき $context.foo を読む下流ステップは unresolved_substitution とグレードされます。
ケイパビリティベクター不一致(ランナーが宣言、エージェントがサポートしない)
get_adcp_capabilities レスポンスでアドバタイズしないケイパビリティを要求するステップをディスパッチしました。ランナーはこれらのステップを自動スキップすべきです。代わりに失敗としてグレードされているのを見ている場合、ケイパビリティが誤ったキーで宣言されているか、ランナーが自動スキップパスを欠いています。
修正: get_adcp_capabilities.tools リストと任意の required-for フィールド(request_signing.required_for、idempotency.supported_tools など)を再確認します。専門化エージェントにのみ適用されるベクターについては、ストーリーボード作者が skipVectors を使ってオプトアウトを明示的にフラグできます。実装者として、修正はほぼ常にベクターではなくケイパビリティ宣言にあります。
required-for 合成
auth.api_key または auth.basic を宣言せず かつ エージェントがリクエスト署名サポートをアドバタイズしないことを意味します — ランナーに呼び出しを認証する方法を残しません。
修正: (a) ランナーが静的な Authorization ヘッダー認証情報を使うようテストキットに auth.api_key または auth.basic を宣言するか、(b) ランナーが代わりにリクエストに署名するよう get_adcp_capabilities.request_signing 経由でリクエスト署名をアドバタイズします。ランナーの requireAuthenticatedOrSigned ゲートはどちらのパスも受け入れます — 両方が欠けているときのみ失敗します。
Static-credential agent: no auth mechanism contributed (assert_mechanism)
mechanism_required フェーズが、任意の optional auth フェーズから auth_mechanism_verified への寄与を見つけませんでした。これは静的認証情報のみのエージェント(Bearer API キーまたは HTTP Basic)の最も一般的な失敗で、実際の auth 問題ではありません — テストキット設定のギャップです。
何が起こったか: api_key_path フェーズは skip_if: "!test_kit.auth.api_key" を持ち、basic_path フェーズは skip_if: "!test_kit.auth.basic" を持ちます — それぞれ、テストキットが一致する認証情報を宣言しない限りスキップされます。oauth_discovery フェーズは /.well-known/oauth-protected-resource/... で 404 になります(静的認証情報のみのエージェントに期待される。それらの失敗はランナーによって黙って無視される)。すべての optional auth フェーズが何も寄与しないと、assert_mechanism は actual: [] を見ます。
--auth TOKEN の区別: ランナーに渡す --auth TOKEN フラグはランナー自身のセッション認証情報です — あなたのエージェントへのランナー自身のリクエストを認可します。それは、静的認証情報フェーズが肯定的および無効認証情報プローブ中に送る特定の認証情報である test_kit.auth.api_key や test_kit.auth.basic とは完全に別です。これらは同じトークンではなく交換可能でありません。
Bearer API キーエージェントの修正: すべてのデフォルト AdCP ブランドテストキットは、demo-<kit>-v1 命名規則を使って auth.api_key の下にそのプローブ API キーを宣言します。デフォルトテストキット(acme-outdoor)は demo-acme-outdoor-v1 を使います。キットのプローブキーを本番鍵と並んで有効なコンプライアンステスト認証情報として受け入れるようエージェントを設定します。demo-<kit>- プレフィックスが AdCP 適合性ハンドルです — 対して実行するキットのプレフィックスに一致する任意の Bearer トークンを受け入れます(サフィックスは仕様バージョンをまたいでローテートでき、プレフィックスは安定のまま):
username/password またはエンコードされていない username:password ペアを含む単一の credentials 値のいずれかで auth.basic を宣言するテストキットを使います。その Basic 認証情報を本番 Basic 認証情報と並んで有効なコンプライアンステスト認証情報として受け入れるようエージェントを設定します。basic_path フェーズは次に有効な Basic 認証情報とランダム無効な Basic 認証情報を送り、エージェントが有効な認証情報を受け入れ無効なものを拒否するときのみ auth_mechanism_verified を寄与します。
自身の本番認証情報のみを受け入れるエージェントは、一致する静的パスをスキップし(テストキット認証情報が一致しない)、oauth_discovery に失敗し(PRM なし)、assert_mechanism で actual: [] に着地します。テストキット認証情報を許可された認証情報セットに追加すれば十分です — PRM エンドポイントや OAuth 発行者は不要です。
OAuth フェーズを「通過」するために存在しない発行者を指す偽の /.well-known/oauth-protected-resource/... を提供しないでください。それは、ストーリーボードが捕まえるよう設計された advertised-but-unserved 失敗モードをトリガーします。
carve-out がなぜ存在するか、静的認証情報 / oauth_discovery フェーズセマンティクスがどう設計されたかの背景については、既知の仕様の曖昧さ — 非 OAuth エージェントに必要な PRM を参照。
INVALID_STATE 対 INVALID_TRANSITION
混同しやすい 2 つのコード:
INVALID_STATE— 「リソースがこのアクションを許さない状態にある」の正準 AdCP メディアバイエラーコード。要求されたように遷移できないメディアバイに対するcreate_media_buy/update_media_buy/pause/resume/cancelで使う。権威ある使用についてはmedia-buy/specification.mdxとmedia-buy/media-buys/index.mdxを参照。INVALID_TRANSITION—comply_test_controllerサンドボックスプリミティブに固有。ランナーがセラーが拒否するステートマシン遷移を要求するとき(例:activeを通らずにapproved→archivedを強制)に発せられる。コンプライアンステストコントローラー — シナリオ を参照。
INVALID_STATE をアサートするストーリーボードベクターに対してエージェントが INVALID_TRANSITION を返すのはエラーコード語彙の不一致です — INVALID_TRANSITION は static/schemas/source/enums/error-code.json の正準 enum になく、コンプライアンステストコントローラーの外に現れるべきではありません。