@adcp/sdk 13.0.4 → 13.1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (235) hide show
  1. package/bin/adcp-grade.js +4 -3
  2. package/bin/adcp.js +18 -0
  3. package/dist/lib/conformance/invariants/uniformError.d.ts.map +1 -1
  4. package/dist/lib/conformance/invariants/uniformError.js +21 -0
  5. package/dist/lib/conformance/invariants/uniformError.js.map +1 -1
  6. package/dist/lib/conformance/invariants/uniformError.mjs +22 -1
  7. package/dist/lib/conformance/invariants/uniformError.mjs.map +1 -1
  8. package/dist/lib/core/AgentClient.d.mts +1 -1
  9. package/dist/lib/core/AgentClient.d.ts +1 -1
  10. package/dist/lib/core/AgentClient.d.ts.map +1 -1
  11. package/dist/lib/core/AgentClient.js +1 -1
  12. package/dist/lib/core/AgentClient.js.map +1 -1
  13. package/dist/lib/core/AgentClient.mjs +1 -1
  14. package/dist/lib/core/AgentClient.mjs.map +1 -1
  15. package/dist/lib/core/SingleAgentClient.d.mts +1 -1
  16. package/dist/lib/core/SingleAgentClient.d.ts +1 -1
  17. package/dist/lib/core/SingleAgentClient.d.ts.map +1 -1
  18. package/dist/lib/core/SingleAgentClient.js +88 -48
  19. package/dist/lib/core/SingleAgentClient.js.map +1 -1
  20. package/dist/lib/core/SingleAgentClient.mjs +88 -48
  21. package/dist/lib/core/SingleAgentClient.mjs.map +1 -1
  22. package/dist/lib/core/TaskExecutor.d.ts.map +1 -1
  23. package/dist/lib/core/TaskExecutor.js +8 -4
  24. package/dist/lib/core/TaskExecutor.js.map +1 -1
  25. package/dist/lib/core/TaskExecutor.mjs +8 -4
  26. package/dist/lib/core/TaskExecutor.mjs.map +1 -1
  27. package/dist/lib/index.d.mts +1 -1
  28. package/dist/lib/index.d.ts +1 -1
  29. package/dist/lib/index.d.ts.map +1 -1
  30. package/dist/lib/index.js.map +1 -1
  31. package/dist/lib/index.mjs.map +1 -1
  32. package/dist/lib/net/agent-transport-fetch.d.mts +15 -0
  33. package/dist/lib/net/agent-transport-fetch.d.ts +15 -0
  34. package/dist/lib/net/agent-transport-fetch.d.ts.map +1 -1
  35. package/dist/lib/net/agent-transport-fetch.js +37 -2
  36. package/dist/lib/net/agent-transport-fetch.js.map +1 -1
  37. package/dist/lib/net/agent-transport-fetch.mjs +37 -2
  38. package/dist/lib/net/agent-transport-fetch.mjs.map +1 -1
  39. package/dist/lib/net/credential-headers.d.mts +1 -0
  40. package/dist/lib/net/credential-headers.d.ts +2 -0
  41. package/dist/lib/net/credential-headers.d.ts.map +1 -0
  42. package/dist/lib/net/credential-headers.js +34 -0
  43. package/dist/lib/net/credential-headers.js.map +1 -0
  44. package/dist/lib/net/credential-headers.mjs +10 -0
  45. package/dist/lib/net/credential-headers.mjs.map +1 -0
  46. package/dist/lib/protocols/a2a-native-v1.d.mts +18 -0
  47. package/dist/lib/protocols/a2a-native-v1.d.ts +19 -0
  48. package/dist/lib/protocols/a2a-native-v1.d.ts.map +1 -0
  49. package/dist/lib/protocols/a2a-native-v1.js +183 -0
  50. package/dist/lib/protocols/a2a-native-v1.js.map +1 -0
  51. package/dist/lib/protocols/a2a-native-v1.mjs +167 -0
  52. package/dist/lib/protocols/a2a-native-v1.mjs.map +1 -0
  53. package/dist/lib/protocols/a2a-push-notification.d.mts +13 -0
  54. package/dist/lib/protocols/a2a-push-notification.d.ts +14 -0
  55. package/dist/lib/protocols/a2a-push-notification.d.ts.map +1 -0
  56. package/dist/lib/protocols/a2a-push-notification.js +42 -0
  57. package/dist/lib/protocols/a2a-push-notification.js.map +1 -0
  58. package/dist/lib/protocols/a2a-push-notification.mjs +23 -0
  59. package/dist/lib/protocols/a2a-push-notification.mjs.map +1 -0
  60. package/dist/lib/protocols/a2a.d.mts +15 -5
  61. package/dist/lib/protocols/a2a.d.ts +15 -5
  62. package/dist/lib/protocols/a2a.d.ts.map +1 -1
  63. package/dist/lib/protocols/a2a.js +102 -13
  64. package/dist/lib/protocols/a2a.js.map +1 -1
  65. package/dist/lib/protocols/a2a.mjs +90 -12
  66. package/dist/lib/protocols/a2a.mjs.map +1 -1
  67. package/dist/lib/protocols/index.d.mts +3 -0
  68. package/dist/lib/protocols/index.d.ts +3 -0
  69. package/dist/lib/protocols/index.d.ts.map +1 -1
  70. package/dist/lib/protocols/index.js +18 -6
  71. package/dist/lib/protocols/index.js.map +1 -1
  72. package/dist/lib/protocols/index.mjs +18 -6
  73. package/dist/lib/protocols/index.mjs.map +1 -1
  74. package/dist/lib/protocols/mcp-modern.d.ts.map +1 -1
  75. package/dist/lib/protocols/mcp-modern.js +3 -1
  76. package/dist/lib/protocols/mcp-modern.js.map +1 -1
  77. package/dist/lib/protocols/mcp-modern.mjs +3 -1
  78. package/dist/lib/protocols/mcp-modern.mjs.map +1 -1
  79. package/dist/lib/protocols/mcp-tasks.d.ts.map +1 -1
  80. package/dist/lib/protocols/mcp-tasks.js +2 -1
  81. package/dist/lib/protocols/mcp-tasks.js.map +1 -1
  82. package/dist/lib/protocols/mcp-tasks.mjs +2 -1
  83. package/dist/lib/protocols/mcp-tasks.mjs.map +1 -1
  84. package/dist/lib/protocols/mcp.d.mts +8 -5
  85. package/dist/lib/protocols/mcp.d.ts +8 -5
  86. package/dist/lib/protocols/mcp.d.ts.map +1 -1
  87. package/dist/lib/protocols/mcp.js +12 -4
  88. package/dist/lib/protocols/mcp.js.map +1 -1
  89. package/dist/lib/protocols/mcp.mjs +12 -4
  90. package/dist/lib/protocols/mcp.mjs.map +1 -1
  91. package/dist/lib/protocols/rawResponseCapture.d.mts +9 -1
  92. package/dist/lib/protocols/rawResponseCapture.d.ts +9 -1
  93. package/dist/lib/protocols/rawResponseCapture.d.ts.map +1 -1
  94. package/dist/lib/protocols/rawResponseCapture.js +153 -10
  95. package/dist/lib/protocols/rawResponseCapture.js.map +1 -1
  96. package/dist/lib/protocols/rawResponseCapture.mjs +153 -10
  97. package/dist/lib/protocols/rawResponseCapture.mjs.map +1 -1
  98. package/dist/lib/schemas-data/v2.5/_provenance.json +1 -1
  99. package/dist/lib/signing/agent-fetch.d.mts +3 -1
  100. package/dist/lib/signing/agent-fetch.d.ts +3 -1
  101. package/dist/lib/signing/agent-fetch.d.ts.map +1 -1
  102. package/dist/lib/signing/agent-fetch.js +4 -2
  103. package/dist/lib/signing/agent-fetch.js.map +1 -1
  104. package/dist/lib/signing/agent-fetch.mjs +4 -2
  105. package/dist/lib/signing/agent-fetch.mjs.map +1 -1
  106. package/dist/lib/signing/protocol-methods.d.mts +24 -0
  107. package/dist/lib/signing/protocol-methods.d.ts +25 -0
  108. package/dist/lib/signing/protocol-methods.d.ts.map +1 -0
  109. package/dist/lib/signing/protocol-methods.js +51 -0
  110. package/dist/lib/signing/protocol-methods.js.map +1 -0
  111. package/dist/lib/signing/protocol-methods.mjs +25 -0
  112. package/dist/lib/signing/protocol-methods.mjs.map +1 -0
  113. package/dist/lib/signing/types.d.mts +2 -0
  114. package/dist/lib/signing/types.d.ts +2 -0
  115. package/dist/lib/signing/types.d.ts.map +1 -1
  116. package/dist/lib/signing/types.js.map +1 -1
  117. package/dist/lib/signing/types.mjs.map +1 -1
  118. package/dist/lib/signing/verifier.d.ts.map +1 -1
  119. package/dist/lib/signing/verifier.js +6 -2
  120. package/dist/lib/signing/verifier.js.map +1 -1
  121. package/dist/lib/signing/verifier.mjs +6 -2
  122. package/dist/lib/signing/verifier.mjs.map +1 -1
  123. package/dist/lib/testing/client.d.ts.map +1 -1
  124. package/dist/lib/testing/client.js +4 -1
  125. package/dist/lib/testing/client.js.map +1 -1
  126. package/dist/lib/testing/client.mjs +4 -1
  127. package/dist/lib/testing/client.mjs.map +1 -1
  128. package/dist/lib/testing/compliance/comply.d.ts.map +1 -1
  129. package/dist/lib/testing/compliance/comply.js +3 -0
  130. package/dist/lib/testing/compliance/comply.js.map +1 -1
  131. package/dist/lib/testing/compliance/comply.mjs +3 -0
  132. package/dist/lib/testing/compliance/comply.mjs.map +1 -1
  133. package/dist/lib/testing/storyboard/agent-routing.d.mts +3 -1
  134. package/dist/lib/testing/storyboard/agent-routing.d.ts +3 -1
  135. package/dist/lib/testing/storyboard/agent-routing.d.ts.map +1 -1
  136. package/dist/lib/testing/storyboard/agent-routing.js +5 -2
  137. package/dist/lib/testing/storyboard/agent-routing.js.map +1 -1
  138. package/dist/lib/testing/storyboard/agent-routing.mjs +4 -2
  139. package/dist/lib/testing/storyboard/agent-routing.mjs.map +1 -1
  140. package/dist/lib/testing/storyboard/compliance.d.mts +1 -1
  141. package/dist/lib/testing/storyboard/compliance.d.ts +1 -1
  142. package/dist/lib/testing/storyboard/compliance.d.ts.map +1 -1
  143. package/dist/lib/testing/storyboard/compliance.js +4 -1
  144. package/dist/lib/testing/storyboard/compliance.js.map +1 -1
  145. package/dist/lib/testing/storyboard/compliance.mjs +4 -1
  146. package/dist/lib/testing/storyboard/compliance.mjs.map +1 -1
  147. package/dist/lib/testing/storyboard/native-a2a-compliance.d.mts +7 -0
  148. package/dist/lib/testing/storyboard/native-a2a-compliance.d.ts +8 -0
  149. package/dist/lib/testing/storyboard/native-a2a-compliance.d.ts.map +1 -0
  150. package/dist/lib/testing/storyboard/native-a2a-compliance.js +45 -0
  151. package/dist/lib/testing/storyboard/native-a2a-compliance.js.map +1 -0
  152. package/dist/lib/testing/storyboard/native-a2a-compliance.mjs +21 -0
  153. package/dist/lib/testing/storyboard/native-a2a-compliance.mjs.map +1 -0
  154. package/dist/lib/testing/storyboard/probes.d.mts +2 -0
  155. package/dist/lib/testing/storyboard/probes.d.ts +2 -0
  156. package/dist/lib/testing/storyboard/probes.d.ts.map +1 -1
  157. package/dist/lib/testing/storyboard/probes.js +3 -2
  158. package/dist/lib/testing/storyboard/probes.js.map +1 -1
  159. package/dist/lib/testing/storyboard/probes.mjs +3 -2
  160. package/dist/lib/testing/storyboard/probes.mjs.map +1 -1
  161. package/dist/lib/testing/storyboard/request-signing/a2a-dispatch.d.mts +31 -0
  162. package/dist/lib/testing/storyboard/request-signing/a2a-dispatch.d.ts +32 -0
  163. package/dist/lib/testing/storyboard/request-signing/a2a-dispatch.d.ts.map +1 -0
  164. package/dist/lib/testing/storyboard/request-signing/a2a-dispatch.js +279 -0
  165. package/dist/lib/testing/storyboard/request-signing/a2a-dispatch.js.map +1 -0
  166. package/dist/lib/testing/storyboard/request-signing/a2a-dispatch.mjs +244 -0
  167. package/dist/lib/testing/storyboard/request-signing/a2a-dispatch.mjs.map +1 -0
  168. package/dist/lib/testing/storyboard/request-signing/builder.d.mts +4 -1
  169. package/dist/lib/testing/storyboard/request-signing/builder.d.ts +4 -1
  170. package/dist/lib/testing/storyboard/request-signing/builder.d.ts.map +1 -1
  171. package/dist/lib/testing/storyboard/request-signing/builder.js +19 -0
  172. package/dist/lib/testing/storyboard/request-signing/builder.js.map +1 -1
  173. package/dist/lib/testing/storyboard/request-signing/builder.mjs +19 -0
  174. package/dist/lib/testing/storyboard/request-signing/builder.mjs.map +1 -1
  175. package/dist/lib/testing/storyboard/request-signing/grader.d.mts +5 -6
  176. package/dist/lib/testing/storyboard/request-signing/grader.d.ts +5 -6
  177. package/dist/lib/testing/storyboard/request-signing/grader.d.ts.map +1 -1
  178. package/dist/lib/testing/storyboard/request-signing/grader.js +82 -13
  179. package/dist/lib/testing/storyboard/request-signing/grader.js.map +1 -1
  180. package/dist/lib/testing/storyboard/request-signing/grader.mjs +86 -13
  181. package/dist/lib/testing/storyboard/request-signing/grader.mjs.map +1 -1
  182. package/dist/lib/testing/storyboard/request-signing/index.d.mts +1 -0
  183. package/dist/lib/testing/storyboard/request-signing/index.d.ts +1 -0
  184. package/dist/lib/testing/storyboard/request-signing/index.d.ts.map +1 -1
  185. package/dist/lib/testing/storyboard/request-signing/index.js +7 -0
  186. package/dist/lib/testing/storyboard/request-signing/index.js.map +1 -1
  187. package/dist/lib/testing/storyboard/request-signing/index.mjs +8 -0
  188. package/dist/lib/testing/storyboard/request-signing/index.mjs.map +1 -1
  189. package/dist/lib/testing/storyboard/request-signing/probe-dispatch.d.mts +2 -2
  190. package/dist/lib/testing/storyboard/request-signing/probe-dispatch.d.ts +2 -2
  191. package/dist/lib/testing/storyboard/request-signing/probe-dispatch.d.ts.map +1 -1
  192. package/dist/lib/testing/storyboard/request-signing/probe-dispatch.js +6 -5
  193. package/dist/lib/testing/storyboard/request-signing/probe-dispatch.js.map +1 -1
  194. package/dist/lib/testing/storyboard/request-signing/probe-dispatch.mjs +6 -5
  195. package/dist/lib/testing/storyboard/request-signing/probe-dispatch.mjs.map +1 -1
  196. package/dist/lib/testing/storyboard/request-signing/types.d.mts +1 -0
  197. package/dist/lib/testing/storyboard/request-signing/types.d.ts +1 -0
  198. package/dist/lib/testing/storyboard/request-signing/types.d.ts.map +1 -1
  199. package/dist/lib/testing/storyboard/request-signing/types.js.map +1 -1
  200. package/dist/lib/testing/storyboard/request-signing/types.mjs.map +1 -1
  201. package/dist/lib/testing/storyboard/request-signing/vector-loader.d.ts.map +1 -1
  202. package/dist/lib/testing/storyboard/request-signing/vector-loader.js +1 -0
  203. package/dist/lib/testing/storyboard/request-signing/vector-loader.js.map +1 -1
  204. package/dist/lib/testing/storyboard/request-signing/vector-loader.mjs +1 -0
  205. package/dist/lib/testing/storyboard/request-signing/vector-loader.mjs.map +1 -1
  206. package/dist/lib/testing/storyboard/runner.d.mts +28 -1
  207. package/dist/lib/testing/storyboard/runner.d.ts +28 -1
  208. package/dist/lib/testing/storyboard/runner.d.ts.map +1 -1
  209. package/dist/lib/testing/storyboard/runner.js +251 -55
  210. package/dist/lib/testing/storyboard/runner.js.map +1 -1
  211. package/dist/lib/testing/storyboard/runner.mjs +255 -60
  212. package/dist/lib/testing/storyboard/runner.mjs.map +1 -1
  213. package/dist/lib/testing/storyboard/types.d.mts +4 -2
  214. package/dist/lib/testing/storyboard/types.d.ts +4 -2
  215. package/dist/lib/testing/storyboard/types.d.ts.map +1 -1
  216. package/dist/lib/testing/storyboard/types.js +1 -0
  217. package/dist/lib/testing/storyboard/types.js.map +1 -1
  218. package/dist/lib/testing/storyboard/types.mjs +1 -0
  219. package/dist/lib/testing/storyboard/types.mjs.map +1 -1
  220. package/dist/lib/testing/storyboard/validations.d.mts +1 -1
  221. package/dist/lib/testing/storyboard/validations.d.ts +1 -1
  222. package/dist/lib/testing/storyboard/validations.d.ts.map +1 -1
  223. package/dist/lib/testing/storyboard/validations.js +97 -22
  224. package/dist/lib/testing/storyboard/validations.js.map +1 -1
  225. package/dist/lib/testing/storyboard/validations.mjs +98 -22
  226. package/dist/lib/testing/storyboard/validations.mjs.map +1 -1
  227. package/dist/lib/version.d.mts +3 -3
  228. package/dist/lib/version.d.ts +3 -3
  229. package/dist/lib/version.js +3 -3
  230. package/dist/lib/version.js.map +1 -1
  231. package/dist/lib/version.mjs +3 -3
  232. package/dist/lib/version.mjs.map +1 -1
  233. package/docs/guides/BUILD-AN-AGENT.md +1 -1
  234. package/docs/llms.txt +5 -3
  235. package/package.json +2 -1
@@ -26,9 +26,11 @@ var import_crypto = require("crypto");
26
26
  var import_builder = require('./builder.js');
27
27
  var import_probe = require('./probe.js');
28
28
  var import_vector_loader = require('./vector-loader.js');
29
+ var import_a2a_dispatch = require('./a2a-dispatch.js');
29
30
  var import_test_kit = require('./test-kit.js');
30
31
  var import_signing = require('../../../signing/index.js');
31
32
  var import_parser = require('../../../signing/parser.js');
33
+ var import_protocol_methods = require('../../../signing/protocol-methods.js');
32
34
  async function gradeRequestSigning(agentUrl, options = {}) {
33
35
  const start = Date.now();
34
36
  const loaded = (0, import_vector_loader.loadRequestSigningVectors)(options);
@@ -53,7 +55,8 @@ async function gradeRequestSigning(agentUrl, options = {}) {
53
55
  timeoutMs: options.timeoutMs,
54
56
  mcpSessionId
55
57
  };
56
- const buildOpts = { baseUrl: agentUrl, transport: options.transport ?? "raw" };
58
+ const transport = options.transport ?? "raw";
59
+ const dispatchOptions = transport === "a2a" ? { ...options, cardFetch: (0, import_a2a_dispatch.createCachedA2aCardFetch)(agentUrl, options) } : options;
57
60
  const positive = [];
58
61
  for (const vector of loaded.positive) {
59
62
  const skip = preflightSkip(vector, "positive", contract, options);
@@ -61,9 +64,10 @@ async function gradeRequestSigning(agentUrl, options = {}) {
61
64
  positive.push(skip);
62
65
  continue;
63
66
  }
67
+ const buildOpts = await buildOptionsForVector(vector, agentUrl, transport, dispatchOptions);
64
68
  const signed = (0, import_builder.buildPositiveRequest)(vector, loaded.keys, buildOpts);
65
69
  const probed = await (0, import_probe.probeSignedRequest)(signed, probeOpts);
66
- positive.push(gradePositive(vector, probed));
70
+ positive.push(withA2aProbeUrl(gradePositive(vector, probed), buildOpts));
67
71
  }
68
72
  const negative = [];
69
73
  for (const vector of loaded.negative) {
@@ -72,7 +76,10 @@ async function gradeRequestSigning(agentUrl, options = {}) {
72
76
  negative.push(skip);
73
77
  continue;
74
78
  }
75
- negative.push(await gradeNegative(vector, loaded, contract, probeOpts, buildOpts, options));
79
+ const buildOpts = vector.jwks_override ? { baseUrl: agentUrl, transport } : await buildOptionsForVector(vector, agentUrl, transport, dispatchOptions);
80
+ negative.push(
81
+ withA2aProbeUrl(await gradeNegative(vector, loaded, contract, probeOpts, buildOpts, options), buildOpts)
82
+ );
76
83
  }
77
84
  const all = [...positive, ...negative];
78
85
  const passed_count = all.filter((r) => r.passed && !r.skipped).length;
@@ -96,11 +103,15 @@ async function gradeRequestSigning(agentUrl, options = {}) {
96
103
  total_duration_ms: Date.now() - start
97
104
  };
98
105
  }
99
- const MCP_FLATTENED_VECTORS = /* @__PURE__ */ new Set([
106
+ const TRANSPORT_FLATTENED_VECTORS = /* @__PURE__ */ new Set([
100
107
  "005-default-port-stripped",
101
108
  "006-dot-segment-path",
102
109
  "007-query-byte-preserved",
103
- "008-percent-encoded-path"
110
+ "008-percent-encoded-path",
111
+ "009-percent-encoded-unreserved-decoded",
112
+ "010-percent-encoded-slash-preserved",
113
+ "011-ipv6-authority",
114
+ "012-ipv6-authority-default-port-stripped"
104
115
  ]);
105
116
  const TRANSPORT_UNGRADABLE = {
106
117
  // fetch() and the Node URL parser normalize U-labels to A-labels before
@@ -120,6 +131,7 @@ function preflightSkip(vector, kind, contract, options) {
120
131
  probe_duration_ms: 0,
121
132
  ...expected_error_code ? { expected_error_code } : {}
122
133
  };
134
+ const transport = options.transport ?? "raw";
123
135
  if (options.onlyVectors && !options.onlyVectors.includes(vector.id)) {
124
136
  return { ...base, skipped: true, skip_reason: "not_in_only_vectors" };
125
137
  }
@@ -152,12 +164,14 @@ function preflightSkip(vector, kind, contract, options) {
152
164
  if (transportReason) {
153
165
  return { ...base, skipped: true, skip_reason: "transport_ungradable", diagnostic: transportReason };
154
166
  }
155
- if (kind === "positive" && options.transport === "mcp" && MCP_FLATTENED_VECTORS.has(vector.id)) {
167
+ if (kind === "positive" && transport !== "raw" && TRANSPORT_FLATTENED_VECTORS.has(vector.id)) {
156
168
  return {
157
169
  ...base,
158
170
  skipped: true,
159
- skip_reason: "mcp_mode_flattens_url_edges",
160
- diagnostic: `Vector ${vector.id} tests a URL-canonicalization edge (port/path/query/encoding) that MCP mode neutralizes by routing every vector to the MCP endpoint. Grade this edge with \`--transport raw\` against a per-operation AdCP agent.`
171
+ // Preserve the existing public MCP report value. A2A uses the new
172
+ // transport-neutral reason because it is not running in MCP mode.
173
+ skip_reason: transport === "mcp" ? "mcp_mode_flattens_url_edges" : "transport_flattens_url_edges",
174
+ diagnostic: `Vector ${vector.id} tests a URL-canonicalization edge (port/path/query/encoding) that ${transport} mode neutralizes by routing every vector to one endpoint. Grade this edge with \`--transport raw\` against a per-operation AdCP agent.`
161
175
  };
162
176
  }
163
177
  if (kind === "negative") {
@@ -184,6 +198,47 @@ function preflightSkip(vector, kind, contract, options) {
184
198
  }
185
199
  return void 0;
186
200
  }
201
+ async function captureA2aRequestForVector(vector, agentUrl, options) {
202
+ const body = parseA2aVectorBody(vector.id, vector.request.body);
203
+ if (body.jsonrpc === "2.0" && typeof body.method === "string") {
204
+ if (body.method !== "tasks/cancel" && body.method !== "CancelTask") {
205
+ throw new Error(`vector "${vector.id}" uses unsupported A2A JSON-RPC method "${body.method}"`);
206
+ }
207
+ const params = body.params && typeof body.params === "object" ? body.params : {};
208
+ const taskId = typeof params.taskId === "string" ? params.taskId : String(params.id ?? "");
209
+ return (0, import_a2a_dispatch.captureA2aRequest)(agentUrl, { kind: "cancelTask", taskId }, a2aDispatchOptions(options));
210
+ }
211
+ return (0, import_a2a_dispatch.captureA2aRequest)(
212
+ agentUrl,
213
+ { kind: "sendMessage", operation: (0, import_a2a_dispatch.operationFromVectorUrl)(vector.request.url), args: body },
214
+ a2aDispatchOptions(options)
215
+ );
216
+ }
217
+ async function buildOptionsForVector(vector, agentUrl, transport, options) {
218
+ if (transport !== "a2a") return { baseUrl: agentUrl, transport };
219
+ return {
220
+ baseUrl: agentUrl,
221
+ transport,
222
+ a2aRequest: await captureA2aRequestForVector(vector, agentUrl, options)
223
+ };
224
+ }
225
+ function a2aDispatchOptions(options) {
226
+ return {
227
+ allowPrivateIp: options.allowPrivateIp === true,
228
+ ...options.timeoutMs !== void 0 ? { timeoutMs: options.timeoutMs } : {},
229
+ ...options.cardFetch ? { cardFetch: options.cardFetch } : {}
230
+ };
231
+ }
232
+ function parseA2aVectorBody(vectorId, body) {
233
+ if (!body) return {};
234
+ try {
235
+ const parsed = JSON.parse(body);
236
+ if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) throw new TypeError("not an object");
237
+ return parsed;
238
+ } catch (cause) {
239
+ throw new Error(`vector "${vectorId}" body must be a JSON object for A2A dispatch`, { cause });
240
+ }
241
+ }
187
242
  async function gradeOneVector(vectorId, kind, agentUrl, options = {}) {
188
243
  const loaded = (0, import_vector_loader.loadRequestSigningVectors)(options);
189
244
  const contract = (0, import_test_kit.loadSignedRequestsRunnerContract)(options);
@@ -207,17 +262,23 @@ async function gradeOneVector(vectorId, kind, agentUrl, options = {}) {
207
262
  timeoutMs: options.timeoutMs,
208
263
  mcpSessionId
209
264
  };
210
- const buildOpts = { baseUrl: agentUrl, transport: options.transport ?? "raw" };
211
265
  const vector = kind === "positive" ? loaded.positive.find((v) => v.id === vectorId) : loaded.negative.find((v) => v.id === vectorId);
212
266
  if (!vector) throw new Error(`Unknown ${kind} vector "${vectorId}"`);
213
267
  const skip = preflightSkip(vector, kind, contract, options);
214
268
  if (skip) return skip;
269
+ const buildOpts = kind === "negative" && vector.jwks_override ? { baseUrl: agentUrl, transport: options.transport ?? "raw" } : await buildOptionsForVector(vector, agentUrl, options.transport ?? "raw", options);
215
270
  if (kind === "positive") {
216
271
  const signed = (0, import_builder.buildPositiveRequest)(vector, loaded.keys, buildOpts);
217
272
  const probe = await (0, import_probe.probeSignedRequest)(signed, probeOpts);
218
- return gradePositive(vector, probe);
273
+ return withA2aProbeUrl(gradePositive(vector, probe), buildOpts);
219
274
  }
220
- return gradeNegative(vector, loaded, contract, probeOpts, buildOpts, options);
275
+ return withA2aProbeUrl(
276
+ await gradeNegative(vector, loaded, contract, probeOpts, buildOpts, options),
277
+ buildOpts
278
+ );
279
+ }
280
+ function withA2aProbeUrl(result, buildOpts) {
281
+ return buildOpts.transport === "a2a" && buildOpts.a2aRequest ? { ...result, probe_url: buildOpts.a2aRequest.url } : result;
221
282
  }
222
283
  function gradePositive(vector, probe) {
223
284
  const accepted = probe.status >= 200 && probe.status < 300;
@@ -460,13 +521,21 @@ function capabilityMismatch(vector, agentCap) {
460
521
  return `Vector asserts required_for includes [${missingRequiredFor.join(", ")}] but agent's required_for does not. Either add the operation to the agent's request_signing.required_for, or accept the skip.`;
461
522
  }
462
523
  const vectorProtocolMethodsRequiredFor = vectorCap.protocol_methods_required_for ?? [];
463
- const agentProtocolMethodsRequiredForSet = new Set(agentCap.protocol_methods_required_for ?? []);
464
524
  const missingProtocolMethodsRequiredFor = vectorProtocolMethodsRequiredFor.filter(
465
- (method) => !agentProtocolMethodsRequiredForSet.has(method)
525
+ (method) => !(0, import_protocol_methods.protocolMethodListIncludes)(agentCap.protocol_methods_required_for ?? [], method)
466
526
  );
467
527
  if (missingProtocolMethodsRequiredFor.length > 0) {
468
528
  return `Vector asserts protocol_methods_required_for includes [${missingProtocolMethodsRequiredFor.join(", ")}] but agent's protocol_methods_required_for does not. Either add the method to the agent's request_signing.protocol_methods_required_for, or accept the skip.`;
469
529
  }
530
+ for (const bucket of ["supported", "warn"]) {
531
+ const field = `protocol_methods_${bucket}_for`;
532
+ const expected = vectorCap[field] ?? [];
533
+ const actual = agentCap[field] ?? [];
534
+ const missing = expected.filter((method) => !(0, import_protocol_methods.protocolMethodListIncludes)(actual, method));
535
+ if (missing.length > 0) {
536
+ return `Vector asserts ${field} includes [${missing.join(", ")}] but agent's ${field} does not. Declare the equivalent stable A2A protocol method spelling, or accept the skip.`;
537
+ }
538
+ }
470
539
  return void 0;
471
540
  }
472
541
  function buildNegativeDiagnostic(vector, probe) {
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../../../src/lib/testing/storyboard/request-signing/grader.ts"],"sourcesContent":["import { randomBytes } from 'crypto';\nimport { buildNegativeRequest, buildPositiveRequest, type BuildOptions, type SignedHttpRequest } from './builder';\nimport { initializeMcpSession, probeSignedRequest, type ProbeResult } from './probe';\nimport { loadRequestSigningVectors, type LoadVectorsOptions } from './vector-loader';\nimport { loadSignedRequestsRunnerContract, type SignedRequestsRunnerContract } from './test-kit';\nimport {\n InMemoryReplayStore,\n InMemoryRevocationStore,\n RequestSignatureError,\n StaticJwksResolver,\n verifyRequestSignature,\n type AdcpJsonWebKey,\n} from '../../../signing';\nimport { parseSignatureInput } from '../../../signing/parser';\nimport type { NegativeVector, PositiveVector, VerifierCapabilityFixture } from './types';\n\nexport interface GradeOptions extends LoadVectorsOptions {\n /** Allow http:// and private-IP destinations. Off by default (match fetchProbe). */\n allowPrivateIp?: boolean;\n /** Skip the rate-abuse vector (it sends 100+ requests; slow). Defaults to false. */\n skipRateAbuse?: boolean;\n /**\n * Override the rate-abuse cap the grader targets. Defaults to the contract's\n * `grading_target_per_keyid_cap_requests`. Agents that advertise a smaller\n * per-keyid cap for the test counterparty MAY lower this so grading finishes\n * in a reasonable time — see test-kits/signed-requests-runner.yaml.\n */\n rateAbuseCap?: number;\n /**\n * Vector IDs to skip for operator-driven reasons (SDK-internal vectors,\n * environment-specific quirks, etc.). Capability-profile mismatches\n * don't belong here — pass {@link agentCapability} and the grader auto-\n * skips vectors whose `verifier_capability` can't match the agent.\n */\n skipVectors?: string[];\n /**\n * Agent's declared `request_signing` capability block — exactly the shape\n * in `get_adcp_capabilities.response.request_signing`. When provided, the\n * grader pre-flights every vector's `verifier_capability` against this\n * profile and auto-skips any vector that asserts a policy the agent\n * didn't advertise (e.g., vector 007 requires `covers_content_digest:\n * 'required'`; agent declares `'either'` — auto-skipped with\n * `skip_reason: 'capability_profile_mismatch'`). The grader also parses\n * each vector's `Signature-Input` and auto-skips vectors whose actual\n * signed components are structurally incompatible with the agent's\n * policy (uncovered `content-digest` against a `'required'` verifier,\n * or covered `content-digest` against a `'forbidden'` verifier).\n *\n * Without this option, every vector runs and cap-profile mismatches\n * produce failed vectors that the operator has to manually translate\n * into `skipVectors` entries — fragile and easy to get wrong per\n * profile. Set `agentCapability` and `skipVectors` collapses to just\n * the handful of operator-specific overrides (like vector 025, which\n * exercises the SDK library rather than the agent).\n */\n agentCapability?: VerifierCapabilityFixture;\n /**\n * When set, run only the named vector ids (all others auto-skip). Takes\n * precedence over `skipVectors`. Useful for isolated regression tests\n * against a single vector without hand-maintaining an inverted skip list.\n */\n onlyVectors?: string[];\n /**\n * Opt in to running vectors that produce live agent-side effects — vector\n * 016 (replay_window) sends a valid `create_media_buy`-shaped request the\n * agent will accept, and vector 020 (rate_abuse) floods cap+1 requests.\n * Required unless the test-kit contract declares `endpoint_scope: sandbox`\n * (in which case the agent asserts the operation is side-effect-free).\n * Default: false — side-effectful vectors auto-skip against non-sandbox\n * endpoints.\n */\n allowLiveSideEffects?: boolean;\n /**\n * Agent's declared `covers_content_digest` policy from\n * `get_adcp_capabilities.request_signing.covers_content_digest`. When set\n * without `agentCapability`, the grader auto-skips both positive and\n * negative vectors whose signature shape is structurally incompatible\n * with the agent's policy:\n *\n * - Vectors whose `verifier_capability.covers_content_digest` asserts\n * a strict policy the agent didn't advertise (e.g. `'either'` →\n * skips neg/007 (`'required'`) and neg/018 (`'forbidden'`)).\n * - Vectors whose actual `Signature-Input` covers `content-digest`\n * against a `'forbidden'` agent (rejected with\n * `request_signature_components_unexpected` before the intended\n * error path).\n * - Vectors whose actual `Signature-Input` does not cover\n * `content-digest` against a `'required'` agent (rejected with\n * `request_signature_components_incomplete` before the intended\n * error path).\n *\n * Skipped vectors use `skip_reason: 'capability_profile_mismatch'`.\n *\n * Has no effect when `agentCapability` is provided — the full\n * capability fixture's `covers_content_digest` field governs via\n * `capabilityMismatch()`, which performs the same shape check. Use\n * `agentCapability` when you also need `required_for` skip behavior.\n */\n agentContentDigestPolicy?: 'required' | 'forbidden' | 'either';\n /**\n * Transport shape the agent speaks. `'raw'` (default) POSTs per-operation\n * AdCP endpoints matching the vectors' URL shape. `'mcp'` wraps each\n * vector body in a JSON-RPC `tools/call` envelope and POSTs to the MCP\n * mount path (`agentUrl`) — use when grading an MCP agent whose verifier\n * sits as transport-layer middleware ahead of MCP dispatch.\n *\n * See adcontextprotocol/adcp-client#612 for the MCP-mode rationale.\n */\n transport?: 'raw' | 'mcp';\n /**\n * MCP session ID to attach as `Mcp-Session-Id` on every probe after\n * signing. When `transport` is `'mcp'` and this field is `undefined`,\n * `gradeRequestSigning` / `gradeOneVector` automatically performs an\n * `initialize` handshake to acquire a session ID before grading starts.\n *\n * Pass a pre-acquired ID (from `initializeMcpSession`) to reuse one\n * session across multiple calls and avoid repeated handshakes — useful\n * when the storyboard runner initializes the session once at storyboard\n * start and threads it through each per-vector call.\n *\n * Pass `''` (empty string) to opt out of auto-initialization and send\n * requests session-less — for stateless streamable-HTTP agents that do\n * not issue a session ID.\n */\n mcpSessionId?: string;\n /**\n * Headers for the auto-`initialize` handshake only (typically the agent's\n * `authorization`) — agents that require auth on `initialize` would\n * otherwise 401 the handshake, read as \"stateless server\", and every\n * vector would then be sent session-less. Never applied to the signed\n * vector requests themselves.\n */\n initializeHeaders?: Record<string, string>;\n /**\n * Override the agent's base URL used for the grader's HTTP targets. When set,\n * each vector's `request.url` is rewritten by swapping origin+path under this\n * base — useful when the vectors point at `seller.example.com` but the agent\n * is reachable at a sandbox URL.\n */\n agentUrl?: string;\n /** Per-probe timeout. Default 10s. */\n timeoutMs?: number;\n /**\n * Number of (probe1, probe2) pairs to run for vector neg/016\n * (replayed-nonce). Each pair uses a fresh nonce and a new TCP\n * connection, so on a multi-instance deployment the two probes\n * may land on different instances. K pairs make the failure\n * deterministic: if any second probe is accepted the count and\n * the cross-instance hypothesis surface in the diagnostic.\n * Must be ≥ 2. Default 10.\n */\n replayProbePairs?: number;\n}\n\nexport interface VectorGradeResult {\n vector_id: string;\n kind: 'positive' | 'negative';\n passed: boolean;\n skipped?: boolean;\n skip_reason?: string;\n /** For negatives: the error code the agent returned (from WWW-Authenticate). */\n actual_error_code?: string;\n /** For negatives: the error code the spec says we should see. */\n expected_error_code?: string;\n http_status: number;\n diagnostic?: string;\n probe_duration_ms: number;\n /**\n * For neg/016 (replayed-nonce) only: total number of (probe1, probe2)\n * pairs attempted by the K-pair grader.\n */\n replay_pairs_tried?: number;\n /**\n * For neg/016 (replayed-nonce) only: number of pairs where the second\n * probe was correctly rejected with `request_signature_replayed`.\n * Equal to `replay_pairs_tried` on a passing run.\n */\n replay_pairs_rejected?: number;\n}\n\nexport interface GradeReport {\n agent_url: string;\n harness_mode: 'black_box';\n /**\n * `true` when the test-kit contract declares an endpoint_scope other than\n * `sandbox` — vectors 016 and 020 produce live side effects (a real\n * `create_media_buy` for 016, cap+1 flooding for 020). Treat as a warning\n * to the operator.\n */\n live_endpoint_warning: boolean;\n contract_loaded: boolean;\n positive: VectorGradeResult[];\n negative: VectorGradeResult[];\n passed: boolean;\n passed_count: number;\n failed_count: number;\n skipped_count: number;\n total_duration_ms: number;\n}\n\n/**\n * Grade an agent's RFC 9421 verifier against the 28 conformance vectors.\n *\n * Preconditions the caller owns:\n * - Agent advertises `request_signing.supported: true` in `get_adcp_capabilities`.\n * - Agent has pre-configured its verifier per `test-kits/signed-requests-runner.yaml`:\n * - Runner's signing keyids (`test-ed25519-2026`, `test-es256-2026`) accepted.\n * - `test-revoked-2026` pre-revoked.\n * - Per-keyid rate cap within grading_target_per_keyid_cap_requests.\n * - `agentUrl` targets a sandbox endpoint — the replay-window contract sends\n * a live valid request that will be accepted before the second (rejected)\n * copy fires.\n */\nexport async function gradeRequestSigning(agentUrl: string, options: GradeOptions = {}): Promise<GradeReport> {\n const start = Date.now();\n const loaded = loadRequestSigningVectors(options);\n const contract = loadSignedRequestsRunnerContract(options);\n\n // Auto-initialize MCP session once before all vectors. A single session\n // covers the full batch — the session ID is injected post-signing so\n // Mcp-Session-Id is never a covered component, and negative vectors reach\n // the verifier before MCP session dispatch (the signature check fires at\n // the HTTP middleware layer, ahead of session routing).\n let mcpSessionId: string | undefined = options.mcpSessionId;\n if (options.transport === 'mcp' && mcpSessionId === undefined) {\n const init = await initializeMcpSession(\n agentUrl,\n {\n allowPrivateIp: options.allowPrivateIp === true,\n timeoutMs: options.timeoutMs,\n },\n options.initializeHeaders ?? {}\n );\n if (init.error) {\n throw new Error(`MCP initialize precondition failed: ${init.error}`);\n }\n mcpSessionId = init.sessionId; // undefined without an error = stateless server\n }\n\n const probeOpts = {\n allowPrivateIp: options.allowPrivateIp === true,\n timeoutMs: options.timeoutMs,\n mcpSessionId,\n };\n\n const buildOpts: BuildOptions = { baseUrl: agentUrl, transport: options.transport ?? 'raw' };\n\n const positive: VectorGradeResult[] = [];\n for (const vector of loaded.positive) {\n const skip = preflightSkip(vector, 'positive', contract, options);\n if (skip) {\n positive.push(skip);\n continue;\n }\n const signed = buildPositiveRequest(vector, loaded.keys, buildOpts);\n const probed = await probeSignedRequest(signed, probeOpts);\n positive.push(gradePositive(vector, probed));\n }\n\n const negative: VectorGradeResult[] = [];\n for (const vector of loaded.negative) {\n const skip = preflightSkip(vector, 'negative', contract, options);\n if (skip) {\n negative.push(skip);\n continue;\n }\n negative.push(await gradeNegative(vector, loaded, contract, probeOpts, buildOpts, options));\n }\n\n const all = [...positive, ...negative];\n const passed_count = all.filter(r => r.passed && !r.skipped).length;\n const skipped_count = all.filter(r => r.skipped).length;\n const failed_count = all.filter(r => !r.passed && !r.skipped).length;\n const passed = failed_count === 0;\n\n return {\n agent_url: agentUrl,\n harness_mode: 'black_box',\n // Default to TRUE when no contract is loaded — we can't prove the endpoint\n // is sandbox, so warn the operator that 016/020 could produce live side\n // effects. Only FALSE when a contract is loaded AND declares sandbox.\n live_endpoint_warning: !contract || contract.endpoint_scope !== 'sandbox',\n contract_loaded: Boolean(contract),\n positive,\n negative,\n passed,\n passed_count,\n failed_count,\n skipped_count,\n total_duration_ms: Date.now() - start,\n };\n}\n\n// Positive vectors whose edge-case coverage survives only under raw transport\n// (per-operation endpoint URLs). Listed explicitly rather than heuristically\n// so a spec author adding a new canonicalization-edge vector has to opt into\n// the skip.\nconst MCP_FLATTENED_VECTORS = new Set([\n '005-default-port-stripped',\n '006-dot-segment-path',\n '007-query-byte-preserved',\n '008-percent-encoded-path',\n]);\n\n// Vectors whose failure mode can't reach a live agent through HTTP. Document\n// why each entry can't be graded via probe so adding a new entry isn't a\n// silent coverage loss.\nconst TRANSPORT_UNGRADABLE: Record<string, string> = {\n // fetch() and the Node URL parser normalize U-labels to A-labels before\n // the request leaves the client. A raw non-ASCII Host header reaches the\n // agent as Punycode, defeating the parse-time check. Direct verifier\n // tests exercise this edge.\n '026-non-ascii-host':\n 'HTTP transport punycodes U-labels before the request leaves the client; verified at the library level.',\n};\n\n/**\n * Centralized skip decisions. Checks (in order): onlyVectors filter,\n * operator skipVectors, agent-capability-profile mismatch\n * (`agentCapability` wired), transport-ungradable, MCP-mode URL-edge\n * flattening, rate-abuse opt-out, stateful-contract missing, and the\n * live-side-effect gate.\n */\nfunction preflightSkip(\n vector: PositiveVector | NegativeVector,\n kind: 'positive' | 'negative',\n contract: SignedRequestsRunnerContract | undefined,\n options: GradeOptions\n): VectorGradeResult | undefined {\n const expected_error_code = kind === 'negative' ? (vector as NegativeVector).expected_error_code : undefined;\n const base = {\n vector_id: vector.id,\n kind,\n passed: true, // skipped ≠ failed; overall pass/fail excludes skipped\n http_status: 0,\n probe_duration_ms: 0,\n ...(expected_error_code ? { expected_error_code } : {}),\n } as const;\n\n if (options.onlyVectors && !options.onlyVectors.includes(vector.id)) {\n return { ...base, skipped: true, skip_reason: 'not_in_only_vectors' };\n }\n if (options.skipVectors?.includes(vector.id)) {\n return { ...base, skipped: true, skip_reason: 'operator_skip' };\n }\n if (options.agentCapability) {\n const mismatch = capabilityMismatch(vector, options.agentCapability);\n if (mismatch) {\n // Surface the mismatch in the diagnostic so operators can audit\n // which vectors were dodged. An agent that under-declares its\n // capability (claims `required_for: []` while it actually\n // enforces on multiple ops) would hide negative-vector failures\n // here — the operator needs to see the skip count to catch that\n // pattern. The caller inspects `report.skipped_count` plus the\n // individual `skip_reason`/`diagnostic` pairs.\n return {\n ...base,\n skipped: true,\n skip_reason: 'capability_profile_mismatch',\n diagnostic: mismatch,\n };\n }\n }\n if (!options.agentCapability && options.agentContentDigestPolicy) {\n const policyMismatch = contentDigestPolicyMismatch(vector, kind, options.agentContentDigestPolicy);\n if (policyMismatch) {\n return {\n ...base,\n skipped: true,\n skip_reason: 'capability_profile_mismatch',\n diagnostic: policyMismatch,\n };\n }\n }\n const transportReason = TRANSPORT_UNGRADABLE[vector.id];\n if (transportReason) {\n return { ...base, skipped: true, skip_reason: 'transport_ungradable', diagnostic: transportReason };\n }\n // Canonicalization-edge positive vectors (005–008) bake their edge case\n // into the vector URL path, query, or port. MCP mode flattens every vector\n // to the same baseUrl (JSON-RPC single endpoint), so these vectors become\n // indistinguishable from vector 001 — passing under MCP is not evidence\n // the edge was tested. Skip with a distinct reason so the report doesn't\n // claim coverage it didn't deliver.\n if (kind === 'positive' && options.transport === 'mcp' && MCP_FLATTENED_VECTORS.has(vector.id)) {\n return {\n ...base,\n skipped: true,\n skip_reason: 'mcp_mode_flattens_url_edges',\n diagnostic:\n `Vector ${vector.id} tests a URL-canonicalization edge (port/path/query/encoding) ` +\n `that MCP mode neutralizes by routing every vector to the MCP endpoint. ` +\n `Grade this edge with \\`--transport raw\\` against a per-operation AdCP agent.`,\n };\n }\n if (kind === 'negative') {\n const neg = vector as NegativeVector;\n if (neg.requires_contract === 'rate_abuse' && options.skipRateAbuse) {\n return { ...base, skipped: true, skip_reason: 'rate_abuse_opt_out' };\n }\n if (neg.requires_contract && !contract) {\n return {\n ...base,\n skipped: true,\n skip_reason: 'missing_test_kit_contract',\n diagnostic:\n 'Stateful vector requires `test-kits/signed-requests-runner.yaml` in the compliance cache. Run `npm run sync-schemas`.',\n };\n }\n // Sandbox opt-in: vectors 016 (replay_window) and 020 (rate_abuse) produce\n // live side effects on the agent. Refuse to run unless the contract says\n // sandbox OR the operator explicitly accepts the side effects.\n if (\n (neg.requires_contract === 'replay_window' || neg.requires_contract === 'rate_abuse') &&\n !options.allowLiveSideEffects &&\n contract?.endpoint_scope !== 'sandbox'\n ) {\n return {\n ...base,\n skipped: true,\n skip_reason: 'live_side_effect_opt_in_required',\n diagnostic:\n `Vector ${vector.id} produces live agent-side effects. Pass allowLiveSideEffects: true ` +\n `(or point the grader at an endpoint whose signed-requests-runner contract declares ` +\n `endpoint_scope: sandbox) to run it.`,\n };\n }\n }\n return undefined;\n}\n\n/**\n * Grade a single vector. Loads the vectors+keys+contract on every call; for\n * the storyboard-runner dispatch path where the caller runs many vectors in\n * sequence, prefer `gradeRequestSigning` which loads once.\n */\nexport async function gradeOneVector(\n vectorId: string,\n kind: 'positive' | 'negative',\n agentUrl: string,\n options: GradeOptions = {}\n): Promise<VectorGradeResult> {\n const loaded = loadRequestSigningVectors(options);\n const contract = loadSignedRequestsRunnerContract(options);\n\n // Per-vector session initialization for the storyboard-runner path.\n // Callers that dispatch many vectors in sequence (e.g., storyboard runner)\n // should pre-initialize once with initializeMcpSession() and pass the ID\n // via options.mcpSessionId to avoid per-call round-trips.\n let mcpSessionId: string | undefined = options.mcpSessionId;\n if (options.transport === 'mcp' && mcpSessionId === undefined) {\n const init = await initializeMcpSession(\n agentUrl,\n {\n allowPrivateIp: options.allowPrivateIp === true,\n timeoutMs: options.timeoutMs,\n },\n options.initializeHeaders ?? {}\n );\n if (init.error) {\n throw new Error(`MCP initialize precondition failed: ${init.error}`);\n }\n mcpSessionId = init.sessionId;\n }\n\n const probeOpts = {\n allowPrivateIp: options.allowPrivateIp === true,\n timeoutMs: options.timeoutMs,\n mcpSessionId,\n };\n const buildOpts: BuildOptions = { baseUrl: agentUrl, transport: options.transport ?? 'raw' };\n\n const vector =\n kind === 'positive' ? loaded.positive.find(v => v.id === vectorId) : loaded.negative.find(v => v.id === vectorId);\n if (!vector) throw new Error(`Unknown ${kind} vector \"${vectorId}\"`);\n\n const skip = preflightSkip(vector, kind, contract, options);\n if (skip) return skip;\n\n if (kind === 'positive') {\n const signed = buildPositiveRequest(vector as PositiveVector, loaded.keys, buildOpts);\n const probe = await probeSignedRequest(signed, probeOpts);\n return gradePositive(vector as PositiveVector, probe);\n }\n return gradeNegative(vector as NegativeVector, loaded, contract, probeOpts, buildOpts, options);\n}\n\n// ── Phase helpers ─────────────────────────────────────────────\n\nfunction gradePositive(vector: PositiveVector, probe: ProbeResult): VectorGradeResult {\n const accepted = probe.status >= 200 && probe.status < 300;\n return {\n vector_id: vector.id,\n kind: 'positive',\n passed: accepted && !probe.error,\n http_status: probe.status,\n diagnostic: accepted ? undefined : buildPositiveDiagnostic(vector, probe),\n probe_duration_ms: probe.duration_ms,\n };\n}\n\nfunction buildPositiveDiagnostic(vector: PositiveVector, probe: ProbeResult): string {\n if (probe.error) return `probe error: ${probe.error}`;\n const expected = 'a 2xx status';\n const sigError = probe.wwwAuthenticateErrorCode;\n if (sigError) {\n return `expected ${expected}, got ${probe.status} with WWW-Authenticate error=\"${sigError}\" — signer or agent-side JWKS likely mismatched. Vector: ${vector.name}`;\n }\n return `expected ${expected}, got ${probe.status}. Vector: ${vector.name}`;\n}\n\nasync function gradeNegative(\n vector: NegativeVector,\n loaded: ReturnType<typeof loadRequestSigningVectors>,\n contract: SignedRequestsRunnerContract | undefined,\n probeOpts: { allowPrivateIp: boolean; timeoutMs?: number },\n buildOpts: BuildOptions,\n options: GradeOptions\n): Promise<VectorGradeResult> {\n if (vector.jwks_override) {\n return gradeJwksOverrideNegative(vector);\n }\n switch (vector.requires_contract) {\n case 'replay_window':\n return gradeReplayWindow(vector, loaded, probeOpts, buildOpts, options.replayProbePairs ?? 10);\n case 'rate_abuse':\n return gradeRateAbuse(vector, loaded, contract!, probeOpts, buildOpts, options);\n case 'revocation':\n default:\n return gradeStaticNegative(vector, loaded, probeOpts, buildOpts);\n }\n}\n\n/**\n * Grade vectors that ship an inline `jwks_override` against the library\n * verifier directly. The agent's JWKS can't be mutated per-vector at probe\n * time, so a black-box HTTP grade can't surface these failure modes.\n * Grading the library verifier is the only path that exercises what the\n * vector is testing — the inline JWK's kty/crv/alg consistency rules.\n */\nasync function gradeJwksOverrideNegative(vector: NegativeVector): Promise<VectorGradeResult> {\n const override = vector.jwks_override!;\n const start = Date.now();\n const jwks = new StaticJwksResolver(override.keys as unknown as AdcpJsonWebKey[]);\n const replayStore = new InMemoryReplayStore();\n const revocationStore = new InMemoryRevocationStore();\n const operation = new URL(vector.request.url).pathname.split('/').filter(Boolean).pop() ?? '';\n try {\n await verifyRequestSignature(vector.request, {\n capability: vector.verifier_capability,\n jwks,\n replayStore,\n revocationStore,\n now: () => vector.reference_now,\n operation,\n });\n return {\n vector_id: vector.id,\n kind: 'negative',\n passed: false,\n http_status: 0,\n expected_error_code: vector.expected_error_code,\n diagnostic: `library verifier accepted a request expected to fail with error=\"${vector.expected_error_code}\"`,\n probe_duration_ms: Date.now() - start,\n };\n } catch (err) {\n if (err instanceof RequestSignatureError) {\n const passed = err.code === vector.expected_error_code;\n return {\n vector_id: vector.id,\n kind: 'negative',\n passed,\n http_status: 0,\n expected_error_code: vector.expected_error_code,\n actual_error_code: err.code,\n diagnostic: passed\n ? undefined\n : `library verifier rejected with error=\"${err.code}\" but vector expects \"${vector.expected_error_code}\"`,\n probe_duration_ms: Date.now() - start,\n };\n }\n throw err;\n }\n}\n\nfunction gradeStaticNegative(\n vector: NegativeVector,\n loaded: ReturnType<typeof loadRequestSigningVectors>,\n probeOpts: { allowPrivateIp: boolean; timeoutMs?: number },\n buildOpts: BuildOptions\n): Promise<VectorGradeResult> {\n const signed = buildNegativeRequest(vector, loaded.keys, buildOpts);\n return probeSignedRequest(signed, probeOpts).then(probe => ({\n vector_id: vector.id,\n kind: 'negative',\n passed: negativeAcceptedErrorCode(vector, probe),\n http_status: probe.status,\n expected_error_code: vector.expected_error_code,\n actual_error_code: probe.wwwAuthenticateErrorCode,\n diagnostic: buildNegativeDiagnostic(vector, probe),\n probe_duration_ms: probe.duration_ms,\n }));\n}\n\nasync function gradeReplayWindow(\n vector: NegativeVector,\n loaded: ReturnType<typeof loadRequestSigningVectors>,\n probeOpts: { allowPrivateIp: boolean; timeoutMs?: number },\n buildOpts: BuildOptions,\n pairCount: number\n): Promise<VectorGradeResult> {\n // Run pairCount independent (probe1, probe2) pairs. Each pair uses a fresh\n // nonce so pair N's probe1 doesn't consume pair N+1's replay-window slot.\n // probeSignedRequest already closes its undici Agent on completion, so each\n // call gets a new TCP connection — no keep-alive pinning to the same upstream.\n let totalDurationMs = 0;\n let rejectedCount = 0;\n let lastSecondStatus = 0;\n let lastSecondErrorCode: string | undefined;\n\n for (let i = 0; i < pairCount; i++) {\n const nonce = randomBytes(16).toString('base64url');\n const signed = buildPositiveRequestFromNegative(vector, loaded, { ...buildOpts, nonce });\n\n const first = await probeSignedRequest(signed, probeOpts);\n totalDurationMs += first.duration_ms;\n\n if (first.status < 200 || first.status >= 300) {\n return {\n vector_id: vector.id,\n kind: 'negative',\n passed: false,\n http_status: first.status,\n expected_error_code: vector.expected_error_code,\n actual_error_code: first.wwwAuthenticateErrorCode,\n diagnostic:\n `replay_window contract: first submission MUST be accepted but agent returned ${first.status}` +\n (first.wwwAuthenticateErrorCode ? ` (error=\"${first.wwwAuthenticateErrorCode}\")` : '') +\n '. Check runner JWKS registration with the agent.',\n probe_duration_ms: totalDurationMs,\n replay_pairs_tried: i + 1,\n replay_pairs_rejected: rejectedCount,\n };\n }\n\n const second = await probeSignedRequest(signed, probeOpts);\n totalDurationMs += second.duration_ms;\n lastSecondStatus = second.status;\n lastSecondErrorCode = second.wwwAuthenticateErrorCode;\n\n if (negativeAcceptedErrorCode(vector, second)) {\n rejectedCount++;\n }\n }\n\n if (rejectedCount === pairCount) {\n return {\n vector_id: vector.id,\n kind: 'negative',\n passed: true,\n http_status: lastSecondStatus,\n expected_error_code: vector.expected_error_code,\n actual_error_code: lastSecondErrorCode,\n probe_duration_ms: totalDurationMs,\n replay_pairs_tried: pairCount,\n replay_pairs_rejected: pairCount,\n };\n }\n\n return {\n vector_id: vector.id,\n kind: 'negative',\n passed: false,\n http_status: lastSecondStatus,\n expected_error_code: vector.expected_error_code,\n actual_error_code: lastSecondErrorCode,\n diagnostic: buildReplayWindowFailDiagnostic(vector, rejectedCount, pairCount),\n probe_duration_ms: totalDurationMs,\n replay_pairs_tried: pairCount,\n replay_pairs_rejected: rejectedCount,\n };\n}\n\nfunction buildReplayWindowFailDiagnostic(vector: NegativeVector, rejectedCount: number, pairCount: number): string {\n if (rejectedCount === 0) {\n return (\n `expected 401 with error=\"${vector.expected_error_code}\" on replayed nonce, but all ${pairCount} probe ` +\n `pairs were accepted (got 200 on second submission every time). Verifier has no replay protection for this nonce. ` +\n `If your verifier runs more than one process or machine instance, confirm the replay store is shared across ` +\n `the pool — the default \\`InMemoryReplayStore\\` is per-process. For distributed deployments use ` +\n `\\`PostgresReplayStore\\` from \\`@adcp/sdk/signing/server\\` or a Redis-backed \\`ReplayStore\\` ` +\n `implementation. See https://github.com/adcontextprotocol/adcp-client/pull/1018`\n );\n }\n return (\n `${rejectedCount} of ${pairCount} probe pairs were correctly rejected; ` +\n `${pairCount - rejectedCount} pair(s) had the second submission accepted. ` +\n `This is the classic multi-instance \\`InMemoryReplayStore\\` pattern — the two probes in an ` +\n `accepted pair landed on different load-balanced instances, each with its own per-process replay store. ` +\n `For distributed deployments use \\`PostgresReplayStore\\` from \\`@adcp/sdk/signing/server\\` ` +\n `or a Redis-backed \\`ReplayStore\\` implementation so all instances share one replay cache. ` +\n `See https://github.com/adcontextprotocol/adcp-client/pull/1018`\n );\n}\n\nasync function gradeRateAbuse(\n vector: NegativeVector,\n loaded: ReturnType<typeof loadRequestSigningVectors>,\n contract: SignedRequestsRunnerContract,\n probeOpts: { allowPrivateIp: boolean; timeoutMs?: number },\n buildOpts: BuildOptions,\n options: GradeOptions\n): Promise<VectorGradeResult> {\n const cap =\n options.rateAbuseCap ?? contract.stateful_vector_contract.rate_abuse.grading_target_per_keyid_cap_requests;\n // Fill the cap with cap distinct-nonce requests, then probe one more — that\n // (cap+1)th request is what the vector expects to be rejected.\n let durationMs = 0;\n for (let i = 0; i < cap; i++) {\n const nonce = randomBytes(16).toString('base64url');\n const signed = buildNegativeRequest(vector, loaded.keys, { nonce, ...buildOpts });\n const probe = await probeSignedRequest(signed, probeOpts);\n durationMs += probe.duration_ms;\n }\n const finalNonce = randomBytes(16).toString('base64url');\n const capPlusOne = buildNegativeRequest(vector, loaded.keys, { nonce: finalNonce, ...buildOpts });\n const probe = await probeSignedRequest(capPlusOne, probeOpts);\n durationMs += probe.duration_ms;\n return {\n vector_id: vector.id,\n kind: 'negative',\n passed: negativeAcceptedErrorCode(vector, probe),\n http_status: probe.status,\n expected_error_code: vector.expected_error_code,\n actual_error_code: probe.wwwAuthenticateErrorCode,\n diagnostic: buildNegativeDiagnostic(vector, probe),\n probe_duration_ms: durationMs,\n };\n}\n\nfunction buildPositiveRequestFromNegative(\n vector: NegativeVector,\n loaded: ReturnType<typeof loadRequestSigningVectors>,\n options: BuildOptions & { nonce: string }\n): SignedHttpRequest {\n // Vector 016 is structurally identical to positive/001 — sign it as a positive.\n const pseudoPositive: PositiveVector = {\n kind: 'positive',\n id: vector.id,\n name: vector.name,\n reference_now: vector.reference_now,\n request: vector.request,\n verifier_capability: vector.verifier_capability,\n jwks_ref: vector.jwks_ref,\n jwks_override: vector.jwks_override,\n };\n return buildPositiveRequest(pseudoPositive, loaded.keys, options);\n}\n\nfunction negativeAcceptedErrorCode(vector: NegativeVector, probe: ProbeResult): boolean {\n return probe.status === 401 && probe.wwwAuthenticateErrorCode === vector.expected_error_code;\n}\n\n/**\n * Inspect the vector's `Signature-Input` header to determine whether the\n * signed components cover `content-digest`. Returns `undefined` when the\n * header is absent or unparseable — the vector exercises a no-signature or\n * malformed-header failure path, so the digest shape check doesn't apply\n * (the verifier short-circuits before the components check).\n *\n * Header lookup is canonical-PascalCase + lowercase only. Test fixtures\n * use canonical PascalCase headers; this isn't a general-purpose\n * header-name normalizer.\n */\nfunction vectorSignsContentDigest(vector: PositiveVector | NegativeVector): boolean | undefined {\n const headers = vector.request.headers;\n const sigInput = headers['Signature-Input'] ?? headers['signature-input'];\n if (!sigInput) return undefined;\n try {\n const parsed = parseSignatureInput(sigInput);\n return parsed.components.includes('content-digest');\n } catch {\n return undefined;\n }\n}\n\n/**\n * Return a diagnostic when the vector's actual signed shape is\n * structurally incompatible with `agentCoversContentDigest` — i.e. the\n * verifier rejects the request shape before the vector's intended error\n * path can fire. Returns `undefined` when the shapes can coexist (or the\n * vector exercises a header-absent/malformed path where this check\n * doesn't apply).\n */\nfunction contentDigestStructuralMismatch(\n vector: PositiveVector | NegativeVector,\n agentCoversContentDigest: 'required' | 'forbidden' | 'either'\n): string | undefined {\n const signsCd = vectorSignsContentDigest(vector);\n if (signsCd === undefined) return undefined;\n if (signsCd && agentCoversContentDigest === 'forbidden') {\n return (\n `Vector's Signature-Input covers content-digest but agent declares ` +\n `covers_content_digest='forbidden'. The verifier rejects with ` +\n `request_signature_components_unexpected before the vector's intended ` +\n `error path can fire.`\n );\n }\n if (!signsCd && agentCoversContentDigest === 'required') {\n return (\n `Vector's Signature-Input does not cover content-digest but agent declares ` +\n `covers_content_digest='required'. The verifier rejects with ` +\n `request_signature_components_incomplete before the vector's intended ` +\n `error path can fire.`\n );\n }\n return undefined;\n}\n\n/**\n * Capability-profile mismatch resolver used when the operator passes\n * `agentContentDigestPolicy` without a full `agentCapability` fixture.\n * Combines two checks:\n * - Declared-policy check (negatives only): a negative vector that\n * asserts a strict policy the agent didn't advertise can't surface\n * its intended error path — the agent never rejects the shape the\n * vector is exercising. Positives are unaffected because acceptance\n * under a permissive agent still demonstrates the verifier's\n * acceptance contract.\n * - Structural shape check (positives and negatives): the vector's\n * actual `Signature-Input` shape must coexist with the agent's\n * policy — otherwise the verifier short-circuits with a\n * `request_signature_components_*` error before any other path can\n * fire.\n */\nfunction contentDigestPolicyMismatch(\n vector: PositiveVector | NegativeVector,\n kind: 'positive' | 'negative',\n agentPolicy: 'required' | 'forbidden' | 'either'\n): string | undefined {\n if (kind === 'negative') {\n const vectorCd = vector.verifier_capability.covers_content_digest;\n if (vectorCd !== 'either' && vectorCd !== agentPolicy) {\n return (\n `Vector asserts covers_content_digest='${vectorCd}' but agent declares '${agentPolicy}'. ` +\n `The agent's policy is incompatible with the vector's expected verifier behavior.`\n );\n }\n }\n return contentDigestStructuralMismatch(vector, agentPolicy);\n}\n\n/**\n * Compare a vector's `verifier_capability` fixture and actual signed shape\n * against the agent's declared capability profile. Returns a\n * human-readable diagnostic when the vector can't grade against this\n * profile — or `undefined` when the vector is gradable.\n *\n * Rules (all four must hold for a graded run):\n * - `supported`: must match. A vector with `supported: true` doesn't\n * grade against an agent that declares `supported: false` (the\n * conformance storyboard already skips such agents outright, but\n * defense-in-depth).\n * - `covers_content_digest`: asymmetric. Vector-side `'either'` is\n * permissive only at the declaration level — the structural shape\n * check below still applies. Agent-side `'either'` is NOT permissive\n * against a strict vector — an agent that declares `'either'`\n * accepts covered AND uncovered requests, so it can't pass vectors\n * 007 (`'required'`) or 018 (`'forbidden'`). Those auto-skip with\n * `capability_profile_mismatch`.\n * - structural shape: the vector's actual `Signature-Input` must\n * coexist with the agent's policy regardless of what\n * `verifier_capability.covers_content_digest` declares. A vector\n * signing without `content-digest` can't grade a `'required'`\n * verifier; a vector signing with `content-digest` can't grade a\n * `'forbidden'` verifier. Either short-circuits with a\n * `request_signature_components_*` error before the vector's\n * intended assertion fires.\n * - `required_for` / `protocol_methods_required_for`: if the vector\n * asserts a required_for operation or method, the agent's\n * `required_for` / `protocol_methods_required_for` must include it.\n * The reverse is fine — an agent that requires MORE operations is\n * still conformant against a vector that asserts fewer.\n */\nfunction capabilityMismatch(\n vector: PositiveVector | NegativeVector,\n agentCap: VerifierCapabilityFixture\n): string | undefined {\n const vectorCap = vector.verifier_capability;\n if (vectorCap.supported !== agentCap.supported) {\n return (\n `Vector asserts supported=${vectorCap.supported} but agent declares supported=${agentCap.supported}. ` +\n `Verify the agent's request_signing capability block.`\n );\n }\n // `covers_content_digest` asymmetry: vector-side `'either'` is\n // permissive only if the vector's actual signed shape is compatible\n // with the agent's policy (handled by the structural check below).\n // Agent-side `'either'` is NOT permissive against a strict vector —\n // an agent that declares `'either'` accepts requests with OR without\n // Content-Digest, so vector 007's \"MUST reject uncovered request\"\n // and vector 018's \"MUST reject covered-when-forbidden\" are\n // structurally incompatible with the agent's stance.\n if (\n vectorCap.covers_content_digest !== 'either' &&\n vectorCap.covers_content_digest !== agentCap.covers_content_digest\n ) {\n return (\n `Vector asserts covers_content_digest='${vectorCap.covers_content_digest}' but agent declares '${agentCap.covers_content_digest}'. ` +\n `The vector can't grade against this profile — its expected verifier behavior doesn't match what the agent implements.`\n );\n }\n // Structural shape check: even when vectorCap is permissive (`'either'`),\n // the vector's actual `Signature-Input` either covers `content-digest` or\n // not. A `'required'` verifier rejects every uncovered request with\n // `request_signature_components_incomplete`; a `'forbidden'` verifier\n // rejects every covered request with `request_signature_components_unexpected`.\n // Both fire before the vector's intended error path, masking the result.\n const structural = contentDigestStructuralMismatch(vector, agentCap.covers_content_digest);\n if (structural) return structural;\n // `required_for` on the vector: every op the vector expects to be\n // required must also be required by the agent. Otherwise a negative\n // vector (e.g., missing signature on `create_media_buy`) would test a\n // rejection path the agent didn't opt into.\n const vectorRequiredFor = vectorCap.required_for ?? [];\n const agentRequiredForSet = new Set(agentCap.required_for ?? []);\n const missingRequiredFor = vectorRequiredFor.filter(op => !agentRequiredForSet.has(op));\n if (missingRequiredFor.length > 0) {\n return (\n `Vector asserts required_for includes [${missingRequiredFor.join(', ')}] but agent's required_for does not. ` +\n `Either add the operation to the agent's request_signing.required_for, or accept the skip.`\n );\n }\n // Same check for `protocol_methods_required_for` (adcp#4326 namespace).\n // Negative vectors that grade JSON-RPC protocol methods (e.g. unsigned\n // `tasks/cancel`) auto-skip when the agent doesn't declare the bucket —\n // matching the behavior of `required_for` for AdCP-tool vectors.\n const vectorProtocolMethodsRequiredFor = vectorCap.protocol_methods_required_for ?? [];\n const agentProtocolMethodsRequiredForSet = new Set(agentCap.protocol_methods_required_for ?? []);\n const missingProtocolMethodsRequiredFor = vectorProtocolMethodsRequiredFor.filter(\n method => !agentProtocolMethodsRequiredForSet.has(method)\n );\n if (missingProtocolMethodsRequiredFor.length > 0) {\n return (\n `Vector asserts protocol_methods_required_for includes [${missingProtocolMethodsRequiredFor.join(', ')}] ` +\n `but agent's protocol_methods_required_for does not. Either add the method to the agent's ` +\n `request_signing.protocol_methods_required_for, or accept the skip.`\n );\n }\n return undefined;\n}\n\nfunction buildNegativeDiagnostic(vector: NegativeVector, probe: ProbeResult): string | undefined {\n if (probe.error) return `probe error: ${probe.error}`;\n if (probe.status === 401 && probe.wwwAuthenticateErrorCode === vector.expected_error_code) {\n return undefined;\n }\n const actual = probe.wwwAuthenticateErrorCode ?? '(none)';\n if (probe.status !== 401) {\n return `expected 401 with error=\"${vector.expected_error_code}\", got ${probe.status} (error=\"${actual}\"). Vector: ${vector.name}`;\n }\n return `expected error=\"${vector.expected_error_code}\", got error=\"${actual}\". Check verifier step ordering — several vectors (015/017/020) depend on revocation/cap checks firing BEFORE crypto verify.`;\n}\n"],"mappings":"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","names":["probe"]}
1
+ {"version":3,"sources":["../../../../../src/lib/testing/storyboard/request-signing/grader.ts"],"sourcesContent":["import { randomBytes } from 'crypto';\nimport { buildNegativeRequest, buildPositiveRequest, type BuildOptions, type SignedHttpRequest } from './builder';\nimport { initializeMcpSession, probeSignedRequest, type ProbeResult } from './probe';\nimport { loadRequestSigningVectors, type LoadVectorsOptions } from './vector-loader';\nimport {\n captureA2aRequest,\n createCachedA2aCardFetch,\n operationFromVectorUrl,\n type CapturedA2aRequest,\n} from './a2a-dispatch';\nimport { loadSignedRequestsRunnerContract, type SignedRequestsRunnerContract } from './test-kit';\nimport {\n InMemoryReplayStore,\n InMemoryRevocationStore,\n RequestSignatureError,\n StaticJwksResolver,\n verifyRequestSignature,\n type AdcpJsonWebKey,\n} from '../../../signing';\nimport { parseSignatureInput } from '../../../signing/parser';\nimport { protocolMethodListIncludes } from '../../../signing/protocol-methods';\nimport type { NegativeVector, PositiveVector, VerifierCapabilityFixture } from './types';\n\nexport interface GradeOptions extends LoadVectorsOptions {\n /** Allow http:// and private-IP destinations. Off by default (match fetchProbe). */\n allowPrivateIp?: boolean;\n /** Skip the rate-abuse vector (it sends 100+ requests; slow). Defaults to false. */\n skipRateAbuse?: boolean;\n /**\n * Override the rate-abuse cap the grader targets. Defaults to the contract's\n * `grading_target_per_keyid_cap_requests`. Agents that advertise a smaller\n * per-keyid cap for the test counterparty MAY lower this so grading finishes\n * in a reasonable time — see test-kits/signed-requests-runner.yaml.\n */\n rateAbuseCap?: number;\n /**\n * Vector IDs to skip for operator-driven reasons (SDK-internal vectors,\n * environment-specific quirks, etc.). Capability-profile mismatches\n * don't belong here — pass {@link agentCapability} and the grader auto-\n * skips vectors whose `verifier_capability` can't match the agent.\n */\n skipVectors?: string[];\n /**\n * Agent's declared `request_signing` capability block — exactly the shape\n * in `get_adcp_capabilities.response.request_signing`. When provided, the\n * grader pre-flights every vector's `verifier_capability` against this\n * profile and auto-skips any vector that asserts a policy the agent\n * didn't advertise (e.g., vector 007 requires `covers_content_digest:\n * 'required'`; agent declares `'either'` — auto-skipped with\n * `skip_reason: 'capability_profile_mismatch'`). The grader also parses\n * each vector's `Signature-Input` and auto-skips vectors whose actual\n * signed components are structurally incompatible with the agent's\n * policy (uncovered `content-digest` against a `'required'` verifier,\n * or covered `content-digest` against a `'forbidden'` verifier).\n *\n * Without this option, every vector runs and cap-profile mismatches\n * produce failed vectors that the operator has to manually translate\n * into `skipVectors` entries — fragile and easy to get wrong per\n * profile. Set `agentCapability` and `skipVectors` collapses to just\n * the handful of operator-specific overrides (like vector 025, which\n * exercises the SDK library rather than the agent).\n */\n agentCapability?: VerifierCapabilityFixture;\n /**\n * When set, run only the named vector ids (all others auto-skip). Takes\n * precedence over `skipVectors`. Useful for isolated regression tests\n * against a single vector without hand-maintaining an inverted skip list.\n */\n onlyVectors?: string[];\n /**\n * Opt in to running vectors that produce live agent-side effects — vector\n * 016 (replay_window) sends a valid `create_media_buy`-shaped request the\n * agent will accept, and vector 020 (rate_abuse) floods cap+1 requests.\n * Required unless the test-kit contract declares `endpoint_scope: sandbox`\n * (in which case the agent asserts the operation is side-effect-free).\n * Default: false — side-effectful vectors auto-skip against non-sandbox\n * endpoints.\n */\n allowLiveSideEffects?: boolean;\n /**\n * Agent's declared `covers_content_digest` policy from\n * `get_adcp_capabilities.request_signing.covers_content_digest`. When set\n * without `agentCapability`, the grader auto-skips both positive and\n * negative vectors whose signature shape is structurally incompatible\n * with the agent's policy:\n *\n * - Vectors whose `verifier_capability.covers_content_digest` asserts\n * a strict policy the agent didn't advertise (e.g. `'either'` →\n * skips neg/007 (`'required'`) and neg/018 (`'forbidden'`)).\n * - Vectors whose actual `Signature-Input` covers `content-digest`\n * against a `'forbidden'` agent (rejected with\n * `request_signature_components_unexpected` before the intended\n * error path).\n * - Vectors whose actual `Signature-Input` does not cover\n * `content-digest` against a `'required'` agent (rejected with\n * `request_signature_components_incomplete` before the intended\n * error path).\n *\n * Skipped vectors use `skip_reason: 'capability_profile_mismatch'`.\n *\n * Has no effect when `agentCapability` is provided — the full\n * capability fixture's `covers_content_digest` field governs via\n * `capabilityMismatch()`, which performs the same shape check. Use\n * `agentCapability` when you also need `required_for` skip behavior.\n */\n agentContentDigestPolicy?: 'required' | 'forbidden' | 'either';\n /**\n * Transport shape the agent speaks. `'raw'` (default) POSTs per-operation\n * AdCP endpoints matching the vectors' URL shape. `'mcp'` wraps each\n * vector body in a JSON-RPC `tools/call` envelope and POSTs to the MCP\n * mount path (`agentUrl`) — use when grading an MCP agent whose verifier\n * sits as transport-layer middleware ahead of MCP dispatch.\n *\n * See adcontextprotocol/adcp-client#612 for the MCP-mode rationale.\n */\n transport?: 'raw' | 'mcp' | 'a2a';\n /** Trusted Agent Card fetch seam for A2A tests and custom runtimes. */\n cardFetch?: typeof fetch;\n /**\n * MCP session ID to attach as `Mcp-Session-Id` on every probe after\n * signing. When `transport` is `'mcp'` and this field is `undefined`,\n * `gradeRequestSigning` / `gradeOneVector` automatically performs an\n * `initialize` handshake to acquire a session ID before grading starts.\n *\n * Pass a pre-acquired ID (from `initializeMcpSession`) to reuse one\n * session across multiple calls and avoid repeated handshakes — useful\n * when the storyboard runner initializes the session once at storyboard\n * start and threads it through each per-vector call.\n *\n * Pass `''` (empty string) to opt out of auto-initialization and send\n * requests session-less — for stateless streamable-HTTP agents that do\n * not issue a session ID.\n */\n mcpSessionId?: string;\n /**\n * Headers for the auto-`initialize` handshake only (typically the agent's\n * `authorization`) — agents that require auth on `initialize` would\n * otherwise 401 the handshake, read as \"stateless server\", and every\n * vector would then be sent session-less. Never applied to the signed\n * vector requests themselves.\n */\n initializeHeaders?: Record<string, string>;\n /**\n * Override the agent's base URL used for the grader's HTTP targets. When set,\n * each vector's `request.url` is rewritten by swapping origin+path under this\n * base — useful when the vectors point at `seller.example.com` but the agent\n * is reachable at a sandbox URL.\n */\n agentUrl?: string;\n /** Per-probe timeout. Default 10s. */\n timeoutMs?: number;\n /**\n * Number of (probe1, probe2) pairs to run for vector neg/016\n * (replayed-nonce). Each pair uses a fresh nonce and a new TCP\n * connection, so on a multi-instance deployment the two probes\n * may land on different instances. K pairs make the failure\n * deterministic: if any second probe is accepted the count and\n * the cross-instance hypothesis surface in the diagnostic.\n * Must be ≥ 2. Default 10.\n */\n replayProbePairs?: number;\n}\n\nexport interface VectorGradeResult {\n vector_id: string;\n kind: 'positive' | 'negative';\n passed: boolean;\n skipped?: boolean;\n skip_reason?: string;\n /** For negatives: the error code the agent returned (from WWW-Authenticate). */\n actual_error_code?: string;\n /** For negatives: the error code the spec says we should see. */\n expected_error_code?: string;\n http_status: number;\n /** Actual card-selected A2A endpoint, when applicable. */\n probe_url?: string;\n diagnostic?: string;\n probe_duration_ms: number;\n /**\n * For neg/016 (replayed-nonce) only: total number of (probe1, probe2)\n * pairs attempted by the K-pair grader.\n */\n replay_pairs_tried?: number;\n /**\n * For neg/016 (replayed-nonce) only: number of pairs where the second\n * probe was correctly rejected with `request_signature_replayed`.\n * Equal to `replay_pairs_tried` on a passing run.\n */\n replay_pairs_rejected?: number;\n}\n\nexport interface GradeReport {\n agent_url: string;\n harness_mode: 'black_box';\n /**\n * `true` when the test-kit contract declares an endpoint_scope other than\n * `sandbox` — vectors 016 and 020 produce live side effects (a real\n * `create_media_buy` for 016, cap+1 flooding for 020). Treat as a warning\n * to the operator.\n */\n live_endpoint_warning: boolean;\n contract_loaded: boolean;\n positive: VectorGradeResult[];\n negative: VectorGradeResult[];\n passed: boolean;\n passed_count: number;\n failed_count: number;\n skipped_count: number;\n total_duration_ms: number;\n}\n\n/**\n * Grade an agent's RFC 9421 verifier against the 28 conformance vectors.\n *\n * Preconditions the caller owns:\n * - Agent advertises `request_signing.supported: true` in `get_adcp_capabilities`.\n * - Agent has pre-configured its verifier per `test-kits/signed-requests-runner.yaml`:\n * - Runner's signing keyids (`test-ed25519-2026`, `test-es256-2026`) accepted.\n * - `test-revoked-2026` pre-revoked.\n * - Per-keyid rate cap within grading_target_per_keyid_cap_requests.\n * - `agentUrl` targets a sandbox endpoint — the replay-window contract sends\n * a live valid request that will be accepted before the second (rejected)\n * copy fires.\n */\nexport async function gradeRequestSigning(agentUrl: string, options: GradeOptions = {}): Promise<GradeReport> {\n const start = Date.now();\n const loaded = loadRequestSigningVectors(options);\n const contract = loadSignedRequestsRunnerContract(options);\n\n // Auto-initialize MCP session once before all vectors. A single session\n // covers the full batch — the session ID is injected post-signing so\n // Mcp-Session-Id is never a covered component, and negative vectors reach\n // the verifier before MCP session dispatch (the signature check fires at\n // the HTTP middleware layer, ahead of session routing).\n let mcpSessionId: string | undefined = options.mcpSessionId;\n if (options.transport === 'mcp' && mcpSessionId === undefined) {\n const init = await initializeMcpSession(\n agentUrl,\n {\n allowPrivateIp: options.allowPrivateIp === true,\n timeoutMs: options.timeoutMs,\n },\n options.initializeHeaders ?? {}\n );\n if (init.error) {\n throw new Error(`MCP initialize precondition failed: ${init.error}`);\n }\n mcpSessionId = init.sessionId; // undefined without an error = stateless server\n }\n\n const probeOpts = {\n allowPrivateIp: options.allowPrivateIp === true,\n timeoutMs: options.timeoutMs,\n mcpSessionId,\n };\n\n const transport = options.transport ?? 'raw';\n // A grade constructs a fresh official client per vector so each capture has\n // an isolated fetch interceptor. Cache only the immutable card response for\n // the duration of this grade to avoid rediscovering it 28 times.\n const dispatchOptions =\n transport === 'a2a' ? { ...options, cardFetch: createCachedA2aCardFetch(agentUrl, options) } : options;\n\n const positive: VectorGradeResult[] = [];\n for (const vector of loaded.positive) {\n const skip = preflightSkip(vector, 'positive', contract, options);\n if (skip) {\n positive.push(skip);\n continue;\n }\n const buildOpts = await buildOptionsForVector(vector, agentUrl, transport, dispatchOptions);\n const signed = buildPositiveRequest(vector, loaded.keys, buildOpts);\n const probed = await probeSignedRequest(signed, probeOpts);\n positive.push(withA2aProbeUrl(gradePositive(vector, probed), buildOpts));\n }\n\n const negative: VectorGradeResult[] = [];\n for (const vector of loaded.negative) {\n const skip = preflightSkip(vector, 'negative', contract, options);\n if (skip) {\n negative.push(skip);\n continue;\n }\n const buildOpts = vector.jwks_override\n ? { baseUrl: agentUrl, transport }\n : await buildOptionsForVector(vector, agentUrl, transport, dispatchOptions);\n negative.push(\n withA2aProbeUrl(await gradeNegative(vector, loaded, contract, probeOpts, buildOpts, options), buildOpts)\n );\n }\n\n const all = [...positive, ...negative];\n const passed_count = all.filter(r => r.passed && !r.skipped).length;\n const skipped_count = all.filter(r => r.skipped).length;\n const failed_count = all.filter(r => !r.passed && !r.skipped).length;\n const passed = failed_count === 0;\n\n return {\n agent_url: agentUrl,\n harness_mode: 'black_box',\n // Default to TRUE when no contract is loaded — we can't prove the endpoint\n // is sandbox, so warn the operator that 016/020 could produce live side\n // effects. Only FALSE when a contract is loaded AND declares sandbox.\n live_endpoint_warning: !contract || contract.endpoint_scope !== 'sandbox',\n contract_loaded: Boolean(contract),\n positive,\n negative,\n passed,\n passed_count,\n failed_count,\n skipped_count,\n total_duration_ms: Date.now() - start,\n };\n}\n\n// Positive vectors whose edge-case coverage survives only under raw transport\n// (per-operation endpoint URLs). Listed explicitly rather than heuristically\n// so a spec author adding a new canonicalization-edge vector has to opt into\n// the skip.\nconst TRANSPORT_FLATTENED_VECTORS = new Set([\n '005-default-port-stripped',\n '006-dot-segment-path',\n '007-query-byte-preserved',\n '008-percent-encoded-path',\n '009-percent-encoded-unreserved-decoded',\n '010-percent-encoded-slash-preserved',\n '011-ipv6-authority',\n '012-ipv6-authority-default-port-stripped',\n]);\n\n// Vectors whose failure mode can't reach a live agent through HTTP. Document\n// why each entry can't be graded via probe so adding a new entry isn't a\n// silent coverage loss.\nconst TRANSPORT_UNGRADABLE: Record<string, string> = {\n // fetch() and the Node URL parser normalize U-labels to A-labels before\n // the request leaves the client. A raw non-ASCII Host header reaches the\n // agent as Punycode, defeating the parse-time check. Direct verifier\n // tests exercise this edge.\n '026-non-ascii-host':\n 'HTTP transport punycodes U-labels before the request leaves the client; verified at the library level.',\n};\n\n/**\n * Centralized skip decisions. Checks (in order): onlyVectors filter,\n * operator skipVectors, agent-capability-profile mismatch\n * (`agentCapability` wired), transport-ungradable, MCP-mode URL-edge\n * flattening, rate-abuse opt-out, stateful-contract missing, and the\n * live-side-effect gate.\n */\nfunction preflightSkip(\n vector: PositiveVector | NegativeVector,\n kind: 'positive' | 'negative',\n contract: SignedRequestsRunnerContract | undefined,\n options: GradeOptions\n): VectorGradeResult | undefined {\n const expected_error_code = kind === 'negative' ? (vector as NegativeVector).expected_error_code : undefined;\n const base = {\n vector_id: vector.id,\n kind,\n passed: true, // skipped ≠ failed; overall pass/fail excludes skipped\n http_status: 0,\n probe_duration_ms: 0,\n ...(expected_error_code ? { expected_error_code } : {}),\n } as const;\n const transport = options.transport ?? 'raw';\n\n if (options.onlyVectors && !options.onlyVectors.includes(vector.id)) {\n return { ...base, skipped: true, skip_reason: 'not_in_only_vectors' };\n }\n if (options.skipVectors?.includes(vector.id)) {\n return { ...base, skipped: true, skip_reason: 'operator_skip' };\n }\n if (options.agentCapability) {\n const mismatch = capabilityMismatch(vector, options.agentCapability);\n if (mismatch) {\n // Surface the mismatch in the diagnostic so operators can audit\n // which vectors were dodged. An agent that under-declares its\n // capability (claims `required_for: []` while it actually\n // enforces on multiple ops) would hide negative-vector failures\n // here — the operator needs to see the skip count to catch that\n // pattern. The caller inspects `report.skipped_count` plus the\n // individual `skip_reason`/`diagnostic` pairs.\n return {\n ...base,\n skipped: true,\n skip_reason: 'capability_profile_mismatch',\n diagnostic: mismatch,\n };\n }\n }\n if (!options.agentCapability && options.agentContentDigestPolicy) {\n const policyMismatch = contentDigestPolicyMismatch(vector, kind, options.agentContentDigestPolicy);\n if (policyMismatch) {\n return {\n ...base,\n skipped: true,\n skip_reason: 'capability_profile_mismatch',\n diagnostic: policyMismatch,\n };\n }\n }\n const transportReason = TRANSPORT_UNGRADABLE[vector.id];\n if (transportReason) {\n return { ...base, skipped: true, skip_reason: 'transport_ungradable', diagnostic: transportReason };\n }\n // Canonicalization-edge positive vectors (005–012) bake their edge case\n // into the vector URL path, query, or port. RPC transports flatten every\n // vector to one selected endpoint, so these vectors become\n // indistinguishable from vector 001 — passing under an RPC transport is not evidence\n // the edge was tested. Skip with a distinct reason so the report doesn't\n // claim coverage it didn't deliver.\n if (kind === 'positive' && transport !== 'raw' && TRANSPORT_FLATTENED_VECTORS.has(vector.id)) {\n return {\n ...base,\n skipped: true,\n // Preserve the existing public MCP report value. A2A uses the new\n // transport-neutral reason because it is not running in MCP mode.\n skip_reason: transport === 'mcp' ? 'mcp_mode_flattens_url_edges' : 'transport_flattens_url_edges',\n diagnostic:\n `Vector ${vector.id} tests a URL-canonicalization edge (port/path/query/encoding) ` +\n `that ${transport} mode neutralizes by routing every vector to one endpoint. ` +\n `Grade this edge with \\`--transport raw\\` against a per-operation AdCP agent.`,\n };\n }\n if (kind === 'negative') {\n const neg = vector as NegativeVector;\n if (neg.requires_contract === 'rate_abuse' && options.skipRateAbuse) {\n return { ...base, skipped: true, skip_reason: 'rate_abuse_opt_out' };\n }\n if (neg.requires_contract && !contract) {\n return {\n ...base,\n skipped: true,\n skip_reason: 'missing_test_kit_contract',\n diagnostic:\n 'Stateful vector requires `test-kits/signed-requests-runner.yaml` in the compliance cache. Run `npm run sync-schemas`.',\n };\n }\n // Sandbox opt-in: vectors 016 (replay_window) and 020 (rate_abuse) produce\n // live side effects on the agent. Refuse to run unless the contract says\n // sandbox OR the operator explicitly accepts the side effects.\n if (\n (neg.requires_contract === 'replay_window' || neg.requires_contract === 'rate_abuse') &&\n !options.allowLiveSideEffects &&\n contract?.endpoint_scope !== 'sandbox'\n ) {\n return {\n ...base,\n skipped: true,\n skip_reason: 'live_side_effect_opt_in_required',\n diagnostic:\n `Vector ${vector.id} produces live agent-side effects. Pass allowLiveSideEffects: true ` +\n `(or point the grader at an endpoint whose signed-requests-runner contract declares ` +\n `endpoint_scope: sandbox) to run it.`,\n };\n }\n }\n return undefined;\n}\n\n/**\n * Grade a single vector. Loads the vectors+keys+contract on every call; for\n * the storyboard-runner dispatch path where the caller runs many vectors in\n * sequence, prefer `gradeRequestSigning` which loads once.\n */\nasync function captureA2aRequestForVector(\n vector: PositiveVector | NegativeVector,\n agentUrl: string,\n options: GradeOptions\n): Promise<CapturedA2aRequest> {\n const body = parseA2aVectorBody(vector.id, vector.request.body);\n if (body.jsonrpc === '2.0' && typeof body.method === 'string') {\n if (body.method !== 'tasks/cancel' && body.method !== 'CancelTask') {\n throw new Error(`vector \"${vector.id}\" uses unsupported A2A JSON-RPC method \"${body.method}\"`);\n }\n const params = body.params && typeof body.params === 'object' ? (body.params as Record<string, unknown>) : {};\n const taskId = typeof params.taskId === 'string' ? params.taskId : String(params.id ?? '');\n return captureA2aRequest(agentUrl, { kind: 'cancelTask', taskId }, a2aDispatchOptions(options));\n }\n return captureA2aRequest(\n agentUrl,\n { kind: 'sendMessage', operation: operationFromVectorUrl(vector.request.url), args: body },\n a2aDispatchOptions(options)\n );\n}\n\nasync function buildOptionsForVector(\n vector: PositiveVector | NegativeVector,\n agentUrl: string,\n transport: NonNullable<GradeOptions['transport']>,\n options: GradeOptions\n): Promise<BuildOptions> {\n if (transport !== 'a2a') return { baseUrl: agentUrl, transport };\n return {\n baseUrl: agentUrl,\n transport,\n a2aRequest: await captureA2aRequestForVector(vector, agentUrl, options),\n };\n}\n\nfunction a2aDispatchOptions(options: GradeOptions) {\n return {\n allowPrivateIp: options.allowPrivateIp === true,\n ...(options.timeoutMs !== undefined ? { timeoutMs: options.timeoutMs } : {}),\n ...(options.cardFetch ? { cardFetch: options.cardFetch } : {}),\n };\n}\n\nfunction parseA2aVectorBody(vectorId: string, body: string | undefined): Record<string, unknown> {\n if (!body) return {};\n try {\n const parsed: unknown = JSON.parse(body);\n if (!parsed || typeof parsed !== 'object' || Array.isArray(parsed)) throw new TypeError('not an object');\n return parsed as Record<string, unknown>;\n } catch (cause) {\n throw new Error(`vector \"${vectorId}\" body must be a JSON object for A2A dispatch`, { cause });\n }\n}\n\nexport async function gradeOneVector(\n vectorId: string,\n kind: 'positive' | 'negative',\n agentUrl: string,\n options: GradeOptions = {}\n): Promise<VectorGradeResult> {\n const loaded = loadRequestSigningVectors(options);\n const contract = loadSignedRequestsRunnerContract(options);\n\n // Per-vector session initialization for the storyboard-runner path.\n // Callers that dispatch many vectors in sequence (e.g., storyboard runner)\n // should pre-initialize once with initializeMcpSession() and pass the ID\n // via options.mcpSessionId to avoid per-call round-trips.\n let mcpSessionId: string | undefined = options.mcpSessionId;\n if (options.transport === 'mcp' && mcpSessionId === undefined) {\n const init = await initializeMcpSession(\n agentUrl,\n {\n allowPrivateIp: options.allowPrivateIp === true,\n timeoutMs: options.timeoutMs,\n },\n options.initializeHeaders ?? {}\n );\n if (init.error) {\n throw new Error(`MCP initialize precondition failed: ${init.error}`);\n }\n mcpSessionId = init.sessionId;\n }\n\n const probeOpts = {\n allowPrivateIp: options.allowPrivateIp === true,\n timeoutMs: options.timeoutMs,\n mcpSessionId,\n };\n const vector =\n kind === 'positive' ? loaded.positive.find(v => v.id === vectorId) : loaded.negative.find(v => v.id === vectorId);\n if (!vector) throw new Error(`Unknown ${kind} vector \"${vectorId}\"`);\n\n const skip = preflightSkip(vector, kind, contract, options);\n if (skip) return skip;\n\n const buildOpts =\n kind === 'negative' && (vector as NegativeVector).jwks_override\n ? { baseUrl: agentUrl, transport: options.transport ?? 'raw' }\n : await buildOptionsForVector(vector, agentUrl, options.transport ?? 'raw', options);\n\n if (kind === 'positive') {\n const signed = buildPositiveRequest(vector as PositiveVector, loaded.keys, buildOpts);\n const probe = await probeSignedRequest(signed, probeOpts);\n return withA2aProbeUrl(gradePositive(vector as PositiveVector, probe), buildOpts);\n }\n return withA2aProbeUrl(\n await gradeNegative(vector as NegativeVector, loaded, contract, probeOpts, buildOpts, options),\n buildOpts\n );\n}\n\nfunction withA2aProbeUrl(result: VectorGradeResult, buildOpts: BuildOptions): VectorGradeResult {\n return buildOpts.transport === 'a2a' && buildOpts.a2aRequest\n ? { ...result, probe_url: buildOpts.a2aRequest.url }\n : result;\n}\n\n// ── Phase helpers ─────────────────────────────────────────────\n\nfunction gradePositive(vector: PositiveVector, probe: ProbeResult): VectorGradeResult {\n const accepted = probe.status >= 200 && probe.status < 300;\n return {\n vector_id: vector.id,\n kind: 'positive',\n passed: accepted && !probe.error,\n http_status: probe.status,\n diagnostic: accepted ? undefined : buildPositiveDiagnostic(vector, probe),\n probe_duration_ms: probe.duration_ms,\n };\n}\n\nfunction buildPositiveDiagnostic(vector: PositiveVector, probe: ProbeResult): string {\n if (probe.error) return `probe error: ${probe.error}`;\n const expected = 'a 2xx status';\n const sigError = probe.wwwAuthenticateErrorCode;\n if (sigError) {\n return `expected ${expected}, got ${probe.status} with WWW-Authenticate error=\"${sigError}\" — signer or agent-side JWKS likely mismatched. Vector: ${vector.name}`;\n }\n return `expected ${expected}, got ${probe.status}. Vector: ${vector.name}`;\n}\n\nasync function gradeNegative(\n vector: NegativeVector,\n loaded: ReturnType<typeof loadRequestSigningVectors>,\n contract: SignedRequestsRunnerContract | undefined,\n probeOpts: { allowPrivateIp: boolean; timeoutMs?: number },\n buildOpts: BuildOptions,\n options: GradeOptions\n): Promise<VectorGradeResult> {\n if (vector.jwks_override) {\n return gradeJwksOverrideNegative(vector);\n }\n switch (vector.requires_contract) {\n case 'replay_window':\n return gradeReplayWindow(vector, loaded, probeOpts, buildOpts, options.replayProbePairs ?? 10);\n case 'rate_abuse':\n return gradeRateAbuse(vector, loaded, contract!, probeOpts, buildOpts, options);\n case 'revocation':\n default:\n return gradeStaticNegative(vector, loaded, probeOpts, buildOpts);\n }\n}\n\n/**\n * Grade vectors that ship an inline `jwks_override` against the library\n * verifier directly. The agent's JWKS can't be mutated per-vector at probe\n * time, so a black-box HTTP grade can't surface these failure modes.\n * Grading the library verifier is the only path that exercises what the\n * vector is testing — the inline JWK's kty/crv/alg consistency rules.\n */\nasync function gradeJwksOverrideNegative(vector: NegativeVector): Promise<VectorGradeResult> {\n const override = vector.jwks_override!;\n const start = Date.now();\n const jwks = new StaticJwksResolver(override.keys as unknown as AdcpJsonWebKey[]);\n const replayStore = new InMemoryReplayStore();\n const revocationStore = new InMemoryRevocationStore();\n const operation = new URL(vector.request.url).pathname.split('/').filter(Boolean).pop() ?? '';\n try {\n await verifyRequestSignature(vector.request, {\n capability: vector.verifier_capability,\n jwks,\n replayStore,\n revocationStore,\n now: () => vector.reference_now,\n operation,\n });\n return {\n vector_id: vector.id,\n kind: 'negative',\n passed: false,\n http_status: 0,\n expected_error_code: vector.expected_error_code,\n diagnostic: `library verifier accepted a request expected to fail with error=\"${vector.expected_error_code}\"`,\n probe_duration_ms: Date.now() - start,\n };\n } catch (err) {\n if (err instanceof RequestSignatureError) {\n const passed = err.code === vector.expected_error_code;\n return {\n vector_id: vector.id,\n kind: 'negative',\n passed,\n http_status: 0,\n expected_error_code: vector.expected_error_code,\n actual_error_code: err.code,\n diagnostic: passed\n ? undefined\n : `library verifier rejected with error=\"${err.code}\" but vector expects \"${vector.expected_error_code}\"`,\n probe_duration_ms: Date.now() - start,\n };\n }\n throw err;\n }\n}\n\nfunction gradeStaticNegative(\n vector: NegativeVector,\n loaded: ReturnType<typeof loadRequestSigningVectors>,\n probeOpts: { allowPrivateIp: boolean; timeoutMs?: number },\n buildOpts: BuildOptions\n): Promise<VectorGradeResult> {\n const signed = buildNegativeRequest(vector, loaded.keys, buildOpts);\n return probeSignedRequest(signed, probeOpts).then(probe => ({\n vector_id: vector.id,\n kind: 'negative',\n passed: negativeAcceptedErrorCode(vector, probe),\n http_status: probe.status,\n expected_error_code: vector.expected_error_code,\n actual_error_code: probe.wwwAuthenticateErrorCode,\n diagnostic: buildNegativeDiagnostic(vector, probe),\n probe_duration_ms: probe.duration_ms,\n }));\n}\n\nasync function gradeReplayWindow(\n vector: NegativeVector,\n loaded: ReturnType<typeof loadRequestSigningVectors>,\n probeOpts: { allowPrivateIp: boolean; timeoutMs?: number },\n buildOpts: BuildOptions,\n pairCount: number\n): Promise<VectorGradeResult> {\n // Run pairCount independent (probe1, probe2) pairs. Each pair uses a fresh\n // nonce so pair N's probe1 doesn't consume pair N+1's replay-window slot.\n // probeSignedRequest already closes its undici Agent on completion, so each\n // call gets a new TCP connection — no keep-alive pinning to the same upstream.\n let totalDurationMs = 0;\n let rejectedCount = 0;\n let lastSecondStatus = 0;\n let lastSecondErrorCode: string | undefined;\n\n for (let i = 0; i < pairCount; i++) {\n const nonce = randomBytes(16).toString('base64url');\n const signed = buildPositiveRequestFromNegative(vector, loaded, { ...buildOpts, nonce });\n\n const first = await probeSignedRequest(signed, probeOpts);\n totalDurationMs += first.duration_ms;\n\n if (first.status < 200 || first.status >= 300) {\n return {\n vector_id: vector.id,\n kind: 'negative',\n passed: false,\n http_status: first.status,\n expected_error_code: vector.expected_error_code,\n actual_error_code: first.wwwAuthenticateErrorCode,\n diagnostic:\n `replay_window contract: first submission MUST be accepted but agent returned ${first.status}` +\n (first.wwwAuthenticateErrorCode ? ` (error=\"${first.wwwAuthenticateErrorCode}\")` : '') +\n '. Check runner JWKS registration with the agent.',\n probe_duration_ms: totalDurationMs,\n replay_pairs_tried: i + 1,\n replay_pairs_rejected: rejectedCount,\n };\n }\n\n const second = await probeSignedRequest(signed, probeOpts);\n totalDurationMs += second.duration_ms;\n lastSecondStatus = second.status;\n lastSecondErrorCode = second.wwwAuthenticateErrorCode;\n\n if (negativeAcceptedErrorCode(vector, second)) {\n rejectedCount++;\n }\n }\n\n if (rejectedCount === pairCount) {\n return {\n vector_id: vector.id,\n kind: 'negative',\n passed: true,\n http_status: lastSecondStatus,\n expected_error_code: vector.expected_error_code,\n actual_error_code: lastSecondErrorCode,\n probe_duration_ms: totalDurationMs,\n replay_pairs_tried: pairCount,\n replay_pairs_rejected: pairCount,\n };\n }\n\n return {\n vector_id: vector.id,\n kind: 'negative',\n passed: false,\n http_status: lastSecondStatus,\n expected_error_code: vector.expected_error_code,\n actual_error_code: lastSecondErrorCode,\n diagnostic: buildReplayWindowFailDiagnostic(vector, rejectedCount, pairCount),\n probe_duration_ms: totalDurationMs,\n replay_pairs_tried: pairCount,\n replay_pairs_rejected: rejectedCount,\n };\n}\n\nfunction buildReplayWindowFailDiagnostic(vector: NegativeVector, rejectedCount: number, pairCount: number): string {\n if (rejectedCount === 0) {\n return (\n `expected 401 with error=\"${vector.expected_error_code}\" on replayed nonce, but all ${pairCount} probe ` +\n `pairs were accepted (got 200 on second submission every time). Verifier has no replay protection for this nonce. ` +\n `If your verifier runs more than one process or machine instance, confirm the replay store is shared across ` +\n `the pool — the default \\`InMemoryReplayStore\\` is per-process. For distributed deployments use ` +\n `\\`PostgresReplayStore\\` from \\`@adcp/sdk/signing/server\\` or a Redis-backed \\`ReplayStore\\` ` +\n `implementation. See https://github.com/adcontextprotocol/adcp-client/pull/1018`\n );\n }\n return (\n `${rejectedCount} of ${pairCount} probe pairs were correctly rejected; ` +\n `${pairCount - rejectedCount} pair(s) had the second submission accepted. ` +\n `This is the classic multi-instance \\`InMemoryReplayStore\\` pattern — the two probes in an ` +\n `accepted pair landed on different load-balanced instances, each with its own per-process replay store. ` +\n `For distributed deployments use \\`PostgresReplayStore\\` from \\`@adcp/sdk/signing/server\\` ` +\n `or a Redis-backed \\`ReplayStore\\` implementation so all instances share one replay cache. ` +\n `See https://github.com/adcontextprotocol/adcp-client/pull/1018`\n );\n}\n\nasync function gradeRateAbuse(\n vector: NegativeVector,\n loaded: ReturnType<typeof loadRequestSigningVectors>,\n contract: SignedRequestsRunnerContract,\n probeOpts: { allowPrivateIp: boolean; timeoutMs?: number },\n buildOpts: BuildOptions,\n options: GradeOptions\n): Promise<VectorGradeResult> {\n const cap =\n options.rateAbuseCap ?? contract.stateful_vector_contract.rate_abuse.grading_target_per_keyid_cap_requests;\n // Fill the cap with cap distinct-nonce requests, then probe one more — that\n // (cap+1)th request is what the vector expects to be rejected.\n let durationMs = 0;\n for (let i = 0; i < cap; i++) {\n const nonce = randomBytes(16).toString('base64url');\n const signed = buildNegativeRequest(vector, loaded.keys, { nonce, ...buildOpts });\n const probe = await probeSignedRequest(signed, probeOpts);\n durationMs += probe.duration_ms;\n }\n const finalNonce = randomBytes(16).toString('base64url');\n const capPlusOne = buildNegativeRequest(vector, loaded.keys, { nonce: finalNonce, ...buildOpts });\n const probe = await probeSignedRequest(capPlusOne, probeOpts);\n durationMs += probe.duration_ms;\n return {\n vector_id: vector.id,\n kind: 'negative',\n passed: negativeAcceptedErrorCode(vector, probe),\n http_status: probe.status,\n expected_error_code: vector.expected_error_code,\n actual_error_code: probe.wwwAuthenticateErrorCode,\n diagnostic: buildNegativeDiagnostic(vector, probe),\n probe_duration_ms: durationMs,\n };\n}\n\nfunction buildPositiveRequestFromNegative(\n vector: NegativeVector,\n loaded: ReturnType<typeof loadRequestSigningVectors>,\n options: BuildOptions & { nonce: string }\n): SignedHttpRequest {\n // Vector 016 is structurally identical to positive/001 — sign it as a positive.\n const pseudoPositive: PositiveVector = {\n kind: 'positive',\n id: vector.id,\n name: vector.name,\n reference_now: vector.reference_now,\n request: vector.request,\n verifier_capability: vector.verifier_capability,\n jwks_ref: vector.jwks_ref,\n jwks_override: vector.jwks_override,\n };\n return buildPositiveRequest(pseudoPositive, loaded.keys, options);\n}\n\nfunction negativeAcceptedErrorCode(vector: NegativeVector, probe: ProbeResult): boolean {\n return probe.status === 401 && probe.wwwAuthenticateErrorCode === vector.expected_error_code;\n}\n\n/**\n * Inspect the vector's `Signature-Input` header to determine whether the\n * signed components cover `content-digest`. Returns `undefined` when the\n * header is absent or unparseable — the vector exercises a no-signature or\n * malformed-header failure path, so the digest shape check doesn't apply\n * (the verifier short-circuits before the components check).\n *\n * Header lookup is canonical-PascalCase + lowercase only. Test fixtures\n * use canonical PascalCase headers; this isn't a general-purpose\n * header-name normalizer.\n */\nfunction vectorSignsContentDigest(vector: PositiveVector | NegativeVector): boolean | undefined {\n const headers = vector.request.headers;\n const sigInput = headers['Signature-Input'] ?? headers['signature-input'];\n if (!sigInput) return undefined;\n try {\n const parsed = parseSignatureInput(sigInput);\n return parsed.components.includes('content-digest');\n } catch {\n return undefined;\n }\n}\n\n/**\n * Return a diagnostic when the vector's actual signed shape is\n * structurally incompatible with `agentCoversContentDigest` — i.e. the\n * verifier rejects the request shape before the vector's intended error\n * path can fire. Returns `undefined` when the shapes can coexist (or the\n * vector exercises a header-absent/malformed path where this check\n * doesn't apply).\n */\nfunction contentDigestStructuralMismatch(\n vector: PositiveVector | NegativeVector,\n agentCoversContentDigest: 'required' | 'forbidden' | 'either'\n): string | undefined {\n const signsCd = vectorSignsContentDigest(vector);\n if (signsCd === undefined) return undefined;\n if (signsCd && agentCoversContentDigest === 'forbidden') {\n return (\n `Vector's Signature-Input covers content-digest but agent declares ` +\n `covers_content_digest='forbidden'. The verifier rejects with ` +\n `request_signature_components_unexpected before the vector's intended ` +\n `error path can fire.`\n );\n }\n if (!signsCd && agentCoversContentDigest === 'required') {\n return (\n `Vector's Signature-Input does not cover content-digest but agent declares ` +\n `covers_content_digest='required'. The verifier rejects with ` +\n `request_signature_components_incomplete before the vector's intended ` +\n `error path can fire.`\n );\n }\n return undefined;\n}\n\n/**\n * Capability-profile mismatch resolver used when the operator passes\n * `agentContentDigestPolicy` without a full `agentCapability` fixture.\n * Combines two checks:\n * - Declared-policy check (negatives only): a negative vector that\n * asserts a strict policy the agent didn't advertise can't surface\n * its intended error path — the agent never rejects the shape the\n * vector is exercising. Positives are unaffected because acceptance\n * under a permissive agent still demonstrates the verifier's\n * acceptance contract.\n * - Structural shape check (positives and negatives): the vector's\n * actual `Signature-Input` shape must coexist with the agent's\n * policy — otherwise the verifier short-circuits with a\n * `request_signature_components_*` error before any other path can\n * fire.\n */\nfunction contentDigestPolicyMismatch(\n vector: PositiveVector | NegativeVector,\n kind: 'positive' | 'negative',\n agentPolicy: 'required' | 'forbidden' | 'either'\n): string | undefined {\n if (kind === 'negative') {\n const vectorCd = vector.verifier_capability.covers_content_digest;\n if (vectorCd !== 'either' && vectorCd !== agentPolicy) {\n return (\n `Vector asserts covers_content_digest='${vectorCd}' but agent declares '${agentPolicy}'. ` +\n `The agent's policy is incompatible with the vector's expected verifier behavior.`\n );\n }\n }\n return contentDigestStructuralMismatch(vector, agentPolicy);\n}\n\n/**\n * Compare a vector's `verifier_capability` fixture and actual signed shape\n * against the agent's declared capability profile. Returns a\n * human-readable diagnostic when the vector can't grade against this\n * profile — or `undefined` when the vector is gradable.\n *\n * Rules (all four must hold for a graded run):\n * - `supported`: must match. A vector with `supported: true` doesn't\n * grade against an agent that declares `supported: false` (the\n * conformance storyboard already skips such agents outright, but\n * defense-in-depth).\n * - `covers_content_digest`: asymmetric. Vector-side `'either'` is\n * permissive only at the declaration level — the structural shape\n * check below still applies. Agent-side `'either'` is NOT permissive\n * against a strict vector — an agent that declares `'either'`\n * accepts covered AND uncovered requests, so it can't pass vectors\n * 007 (`'required'`) or 018 (`'forbidden'`). Those auto-skip with\n * `capability_profile_mismatch`.\n * - structural shape: the vector's actual `Signature-Input` must\n * coexist with the agent's policy regardless of what\n * `verifier_capability.covers_content_digest` declares. A vector\n * signing without `content-digest` can't grade a `'required'`\n * verifier; a vector signing with `content-digest` can't grade a\n * `'forbidden'` verifier. Either short-circuits with a\n * `request_signature_components_*` error before the vector's\n * intended assertion fires.\n * - `required_for` / `protocol_methods_required_for`: if the vector\n * asserts a required_for operation or method, the agent's\n * `required_for` / `protocol_methods_required_for` must include it.\n * The reverse is fine — an agent that requires MORE operations is\n * still conformant against a vector that asserts fewer.\n */\nfunction capabilityMismatch(\n vector: PositiveVector | NegativeVector,\n agentCap: VerifierCapabilityFixture\n): string | undefined {\n const vectorCap = vector.verifier_capability;\n if (vectorCap.supported !== agentCap.supported) {\n return (\n `Vector asserts supported=${vectorCap.supported} but agent declares supported=${agentCap.supported}. ` +\n `Verify the agent's request_signing capability block.`\n );\n }\n // `covers_content_digest` asymmetry: vector-side `'either'` is\n // permissive only if the vector's actual signed shape is compatible\n // with the agent's policy (handled by the structural check below).\n // Agent-side `'either'` is NOT permissive against a strict vector —\n // an agent that declares `'either'` accepts requests with OR without\n // Content-Digest, so vector 007's \"MUST reject uncovered request\"\n // and vector 018's \"MUST reject covered-when-forbidden\" are\n // structurally incompatible with the agent's stance.\n if (\n vectorCap.covers_content_digest !== 'either' &&\n vectorCap.covers_content_digest !== agentCap.covers_content_digest\n ) {\n return (\n `Vector asserts covers_content_digest='${vectorCap.covers_content_digest}' but agent declares '${agentCap.covers_content_digest}'. ` +\n `The vector can't grade against this profile — its expected verifier behavior doesn't match what the agent implements.`\n );\n }\n // Structural shape check: even when vectorCap is permissive (`'either'`),\n // the vector's actual `Signature-Input` either covers `content-digest` or\n // not. A `'required'` verifier rejects every uncovered request with\n // `request_signature_components_incomplete`; a `'forbidden'` verifier\n // rejects every covered request with `request_signature_components_unexpected`.\n // Both fire before the vector's intended error path, masking the result.\n const structural = contentDigestStructuralMismatch(vector, agentCap.covers_content_digest);\n if (structural) return structural;\n // `required_for` on the vector: every op the vector expects to be\n // required must also be required by the agent. Otherwise a negative\n // vector (e.g., missing signature on `create_media_buy`) would test a\n // rejection path the agent didn't opt into.\n const vectorRequiredFor = vectorCap.required_for ?? [];\n const agentRequiredForSet = new Set(agentCap.required_for ?? []);\n const missingRequiredFor = vectorRequiredFor.filter(op => !agentRequiredForSet.has(op));\n if (missingRequiredFor.length > 0) {\n return (\n `Vector asserts required_for includes [${missingRequiredFor.join(', ')}] but agent's required_for does not. ` +\n `Either add the operation to the agent's request_signing.required_for, or accept the skip.`\n );\n }\n // Same check for `protocol_methods_required_for` (adcp#4326 namespace).\n // Negative vectors that grade JSON-RPC protocol methods (e.g. unsigned\n // `tasks/cancel`) auto-skip when the agent doesn't declare the bucket —\n // matching the behavior of `required_for` for AdCP-tool vectors.\n const vectorProtocolMethodsRequiredFor = vectorCap.protocol_methods_required_for ?? [];\n const missingProtocolMethodsRequiredFor = vectorProtocolMethodsRequiredFor.filter(\n method => !protocolMethodListIncludes(agentCap.protocol_methods_required_for ?? [], method)\n );\n if (missingProtocolMethodsRequiredFor.length > 0) {\n return (\n `Vector asserts protocol_methods_required_for includes [${missingProtocolMethodsRequiredFor.join(', ')}] ` +\n `but agent's protocol_methods_required_for does not. Either add the method to the agent's ` +\n `request_signing.protocol_methods_required_for, or accept the skip.`\n );\n }\n for (const bucket of ['supported', 'warn'] as const) {\n const field = `protocol_methods_${bucket}_for` as const;\n const expected = vectorCap[field] ?? [];\n const actual = agentCap[field] ?? [];\n const missing = expected.filter(method => !protocolMethodListIncludes(actual, method));\n if (missing.length > 0) {\n return (\n `Vector asserts ${field} includes [${missing.join(', ')}] but agent's ${field} does not. ` +\n `Declare the equivalent stable A2A protocol method spelling, or accept the skip.`\n );\n }\n }\n return undefined;\n}\n\nfunction buildNegativeDiagnostic(vector: NegativeVector, probe: ProbeResult): string | undefined {\n if (probe.error) return `probe error: ${probe.error}`;\n if (probe.status === 401 && probe.wwwAuthenticateErrorCode === vector.expected_error_code) {\n return undefined;\n }\n const actual = probe.wwwAuthenticateErrorCode ?? '(none)';\n if (probe.status !== 401) {\n return `expected 401 with error=\"${vector.expected_error_code}\", got ${probe.status} (error=\"${actual}\"). Vector: ${vector.name}`;\n }\n return `expected error=\"${vector.expected_error_code}\", got error=\"${actual}\". Check verifier step ordering — several vectors (015/017/020) depend on revocation/cap checks firing BEFORE crypto verify.`;\n}\n"],"mappings":"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","names":["probe"]}