@adcp/sdk 14.0.0-rc.37 → 14.0.0-rc.39

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 (622) hide show
  1. package/bin/adcp-storyboard-summary.js +286 -0
  2. package/bin/adcp.js +221 -10
  3. package/dist/lib/conformance/schemaLoader.d.mts +1 -1
  4. package/dist/lib/conformance/schemaLoader.d.ts +1 -1
  5. package/dist/lib/core/AgentClient.d.mts +6 -1
  6. package/dist/lib/core/AgentClient.d.ts +6 -1
  7. package/dist/lib/core/AgentClient.js +9 -0
  8. package/dist/lib/core/AgentClient.mjs +9 -0
  9. package/dist/lib/core/ConversationTypes.d.mts +29 -0
  10. package/dist/lib/core/ConversationTypes.d.ts +29 -0
  11. package/dist/lib/core/SingleAgentClient.d.mts +3 -1
  12. package/dist/lib/core/SingleAgentClient.d.ts +3 -1
  13. package/dist/lib/core/SingleAgentClient.js +9 -1
  14. package/dist/lib/core/SingleAgentClient.mjs +9 -1
  15. package/dist/lib/core/TaskExecutor.d.mts +13 -1
  16. package/dist/lib/core/TaskExecutor.d.ts +13 -1
  17. package/dist/lib/core/TaskExecutor.js +216 -18
  18. package/dist/lib/core/TaskExecutor.mjs +216 -19
  19. package/dist/lib/index.d.mts +5 -2
  20. package/dist/lib/index.d.ts +5 -2
  21. package/dist/lib/index.js +10 -1
  22. package/dist/lib/index.mjs +10 -1
  23. package/dist/lib/media-buy/action-assessment.d.mts +77 -0
  24. package/dist/lib/media-buy/action-assessment.d.ts +77 -0
  25. package/dist/lib/media-buy/action-assessment.js +300 -0
  26. package/dist/lib/media-buy/action-assessment.mjs +284 -0
  27. package/dist/lib/media-buy/action-constraints.d.mts +9 -0
  28. package/dist/lib/media-buy/action-constraints.d.ts +9 -0
  29. package/dist/lib/media-buy/action-constraints.js +170 -0
  30. package/dist/lib/media-buy/action-constraints.mjs +146 -0
  31. package/dist/lib/media-buy/action-contracts.d.mts +40 -0
  32. package/dist/lib/media-buy/action-contracts.d.ts +40 -0
  33. package/dist/lib/media-buy/action-contracts.js +304 -0
  34. package/dist/lib/media-buy/action-contracts.mjs +267 -0
  35. package/dist/lib/media-buy/action-metadata.generated.d.mts +37 -0
  36. package/dist/lib/media-buy/action-metadata.generated.d.ts +37 -0
  37. package/dist/lib/media-buy/action-metadata.generated.js +128 -0
  38. package/dist/lib/media-buy/action-metadata.generated.mjs +101 -0
  39. package/dist/lib/media-buy/action-types.d.mts +106 -0
  40. package/dist/lib/media-buy/action-types.d.ts +106 -0
  41. package/dist/lib/{types/v3-1-beta/tools.generated.js → media-buy/action-types.js} +2 -2
  42. package/dist/lib/media-buy/actions.d.mts +6 -0
  43. package/dist/lib/media-buy/actions.d.ts +6 -0
  44. package/dist/lib/media-buy/actions.js +38 -0
  45. package/dist/lib/media-buy/actions.mjs +9 -0
  46. package/dist/lib/media-buy/available-actions.d.mts +2 -1
  47. package/dist/lib/media-buy/available-actions.d.ts +2 -1
  48. package/dist/lib/media-buy/available-actions.js +4 -3
  49. package/dist/lib/media-buy/available-actions.mjs +4 -3
  50. package/dist/lib/media-buy/compatibility.js +3 -0
  51. package/dist/lib/media-buy/compatibility.mjs +3 -0
  52. package/dist/lib/media-buy/index.d.mts +4 -0
  53. package/dist/lib/media-buy/index.d.ts +4 -0
  54. package/dist/lib/media-buy/index.js +3 -1
  55. package/dist/lib/media-buy/index.mjs +1 -0
  56. package/dist/lib/media-buy/legacy-action-ids.d.mts +1 -0
  57. package/dist/lib/media-buy/legacy-action-ids.d.ts +1 -0
  58. package/dist/lib/media-buy/legacy-action-ids.js +50 -0
  59. package/dist/lib/media-buy/legacy-action-ids.mjs +26 -0
  60. package/dist/lib/media-buy/mutations.d.mts +70 -0
  61. package/dist/lib/media-buy/mutations.d.ts +70 -0
  62. package/dist/lib/media-buy/mutations.js +525 -0
  63. package/dist/lib/media-buy/mutations.mjs +498 -0
  64. package/dist/lib/media-buy/preflight.d.mts +20 -69
  65. package/dist/lib/media-buy/preflight.d.ts +20 -69
  66. package/dist/lib/media-buy/preflight.js +100 -336
  67. package/dist/lib/media-buy/preflight.mjs +111 -333
  68. package/dist/lib/media-buy/targeting-input.d.mts +7 -4
  69. package/dist/lib/media-buy/targeting-input.d.ts +7 -4
  70. package/dist/lib/media-buy/types.d.mts +55 -7
  71. package/dist/lib/media-buy/types.d.ts +55 -7
  72. package/dist/lib/protocols/rawResponseCapture.d.mts +12 -0
  73. package/dist/lib/protocols/rawResponseCapture.d.ts +12 -0
  74. package/dist/lib/protocols/rawResponseCapture.js +33 -3
  75. package/dist/lib/protocols/rawResponseCapture.mjs +32 -3
  76. package/dist/lib/registry/types.generated.d.mts +377 -9
  77. package/dist/lib/registry/types.generated.d.ts +377 -9
  78. package/dist/lib/reporting/content-mismatch.d.mts +126 -0
  79. package/dist/lib/reporting/content-mismatch.d.ts +126 -0
  80. package/dist/lib/reporting/content-mismatch.js +90 -0
  81. package/dist/lib/reporting/content-mismatch.mjs +66 -0
  82. package/dist/lib/reporting/evidence.d.mts +1 -0
  83. package/dist/lib/reporting/evidence.d.ts +1 -0
  84. package/dist/lib/reporting/evidence.js +32 -3
  85. package/dist/lib/reporting/evidence.mjs +31 -3
  86. package/dist/lib/reporting/index.d.mts +3 -1
  87. package/dist/lib/reporting/index.d.ts +3 -1
  88. package/dist/lib/reporting/index.js +3 -0
  89. package/dist/lib/reporting/index.mjs +2 -0
  90. package/dist/lib/reporting/ledger/handler.d.mts +51 -1
  91. package/dist/lib/reporting/ledger/handler.d.ts +51 -1
  92. package/dist/lib/reporting/ledger/handler.js +306 -38
  93. package/dist/lib/reporting/ledger/handler.mjs +304 -37
  94. package/dist/lib/reporting/ledger/health.d.mts +12 -0
  95. package/dist/lib/reporting/ledger/health.d.ts +12 -0
  96. package/dist/lib/reporting/ledger/health.js +15 -2
  97. package/dist/lib/reporting/ledger/health.mjs +13 -1
  98. package/dist/lib/reporting/ledger/index.d.mts +3 -0
  99. package/dist/lib/reporting/ledger/index.d.ts +3 -0
  100. package/dist/lib/reporting/ledger/index.js +7 -1
  101. package/dist/lib/reporting/ledger/index.mjs +3 -0
  102. package/dist/lib/reporting/ledger/lifecycle.d.mts +31 -4
  103. package/dist/lib/reporting/ledger/lifecycle.d.ts +31 -4
  104. package/dist/lib/reporting/ledger/lifecycle.js +244 -37
  105. package/dist/lib/reporting/ledger/lifecycle.mjs +244 -37
  106. package/dist/lib/reporting/ledger/managed-postgres.d.mts +231 -0
  107. package/dist/lib/reporting/ledger/managed-postgres.d.ts +231 -0
  108. package/dist/lib/reporting/ledger/managed-postgres.js +1797 -0
  109. package/dist/lib/reporting/ledger/managed-postgres.mjs +1776 -0
  110. package/dist/lib/reporting/ledger/managed.d.mts +355 -0
  111. package/dist/lib/reporting/ledger/managed.d.ts +355 -0
  112. package/dist/lib/reporting/ledger/managed.js +661 -0
  113. package/dist/lib/reporting/ledger/managed.mjs +633 -0
  114. package/dist/lib/reporting/ledger/notification-activity.d.mts +222 -0
  115. package/dist/lib/reporting/ledger/notification-activity.d.ts +222 -0
  116. package/dist/lib/reporting/ledger/notification-activity.js +1139 -0
  117. package/dist/lib/reporting/ledger/notification-activity.mjs +1110 -0
  118. package/dist/lib/reporting/ledger/postgres.d.mts +161 -1
  119. package/dist/lib/reporting/ledger/postgres.d.ts +161 -1
  120. package/dist/lib/reporting/ledger/postgres.js +1153 -21
  121. package/dist/lib/reporting/ledger/postgres.mjs +1152 -21
  122. package/dist/lib/reporting/ledger/producer.d.mts +8 -0
  123. package/dist/lib/reporting/ledger/producer.d.ts +8 -0
  124. package/dist/lib/reporting/ledger/producer.js +146 -52
  125. package/dist/lib/reporting/ledger/producer.mjs +146 -51
  126. package/dist/lib/reporting/ledger/types.d.mts +358 -1
  127. package/dist/lib/reporting/ledger/types.d.ts +358 -1
  128. package/dist/lib/reporting/ledger/types.js +3 -0
  129. package/dist/lib/reporting/ledger/types.mjs +2 -0
  130. package/dist/lib/reporting/reconciliation.d.mts +362 -2
  131. package/dist/lib/reporting/reconciliation.d.ts +362 -2
  132. package/dist/lib/reporting/reconciliation.js +1051 -7
  133. package/dist/lib/reporting/reconciliation.mjs +1053 -7
  134. package/dist/lib/reporting/service/conformance.d.mts +35 -0
  135. package/dist/lib/reporting/service/conformance.d.ts +35 -0
  136. package/dist/lib/reporting/service/conformance.js +89 -0
  137. package/dist/lib/reporting/service/conformance.mjs +68 -0
  138. package/dist/lib/reporting/service/index.d.mts +182 -0
  139. package/dist/lib/reporting/service/index.d.ts +182 -0
  140. package/dist/lib/reporting/service/index.js +793 -0
  141. package/dist/lib/reporting/service/index.mjs +787 -0
  142. package/dist/lib/reporting/source/index.d.mts +2 -1
  143. package/dist/lib/reporting/source/index.d.ts +2 -1
  144. package/dist/lib/reporting/source/index.js +16 -3
  145. package/dist/lib/reporting/source/index.mjs +12 -1
  146. package/dist/lib/reporting/source/inline.d.mts +88 -1
  147. package/dist/lib/reporting/source/inline.d.ts +88 -1
  148. package/dist/lib/reporting/source/inline.js +1161 -163
  149. package/dist/lib/reporting/source/inline.mjs +1166 -163
  150. package/dist/lib/reporting/source/manifest.js +12 -7
  151. package/dist/lib/reporting/source/manifest.mjs +12 -7
  152. package/dist/lib/reporting/source/source.d.mts +26 -0
  153. package/dist/lib/reporting/source/source.d.ts +26 -0
  154. package/dist/lib/reporting/source/source.js +71 -2
  155. package/dist/lib/reporting/source/source.mjs +65 -1
  156. package/dist/lib/schemas/index.d.mts +22 -1
  157. package/dist/lib/schemas/index.d.ts +22 -1
  158. package/dist/lib/schemas/index.js +7 -0
  159. package/dist/lib/schemas/index.mjs +7 -0
  160. package/dist/lib/schemas-data/v2.5/_provenance.json +1 -1
  161. package/dist/lib/server/create-adcp-server.d.mts +18 -0
  162. package/dist/lib/server/create-adcp-server.d.ts +18 -0
  163. package/dist/lib/server/create-adcp-server.js +52 -2
  164. package/dist/lib/server/create-adcp-server.mjs +52 -2
  165. package/dist/lib/server/decisioning/account.d.mts +1 -1
  166. package/dist/lib/server/decisioning/account.d.ts +1 -1
  167. package/dist/lib/server/decisioning/index.d.mts +1 -0
  168. package/dist/lib/server/decisioning/index.d.ts +1 -0
  169. package/dist/lib/server/decisioning/platform.d.mts +3 -0
  170. package/dist/lib/server/decisioning/platform.d.ts +3 -0
  171. package/dist/lib/server/decisioning/runtime/from-platform.js +88 -10
  172. package/dist/lib/server/decisioning/runtime/from-platform.mjs +88 -10
  173. package/dist/lib/server/decisioning/specialisms/reporting.d.mts +38 -0
  174. package/dist/lib/server/decisioning/specialisms/reporting.d.ts +38 -0
  175. package/dist/lib/{types/v3-1-beta/index.js → server/decisioning/specialisms/reporting.js} +2 -8
  176. package/dist/lib/server/decisioning/specialisms/reporting.mjs +0 -0
  177. package/dist/lib/server/index.d.mts +4 -2
  178. package/dist/lib/server/index.d.ts +4 -2
  179. package/dist/lib/server/index.js +5 -0
  180. package/dist/lib/server/index.mjs +4 -0
  181. package/dist/lib/server/media-buy-action-resolver.d.mts +63 -0
  182. package/dist/lib/server/media-buy-action-resolver.d.ts +63 -0
  183. package/dist/lib/server/media-buy-action-resolver.js +297 -0
  184. package/dist/lib/server/media-buy-action-resolver.mjs +285 -0
  185. package/dist/lib/server/media-buy-actions.d.mts +7 -8
  186. package/dist/lib/server/media-buy-actions.d.ts +7 -8
  187. package/dist/lib/server/media-buy-actions.js +57 -14
  188. package/dist/lib/server/media-buy-actions.mjs +63 -14
  189. package/dist/lib/server/notification-subscriptions/index.d.mts +2 -2
  190. package/dist/lib/server/notification-subscriptions/index.d.ts +2 -2
  191. package/dist/lib/server/notification-subscriptions/index.js +2 -0
  192. package/dist/lib/server/notification-subscriptions/index.mjs +2 -0
  193. package/dist/lib/server/notification-subscriptions/postgres-runtime.d.mts +3 -1
  194. package/dist/lib/server/notification-subscriptions/postgres-runtime.d.ts +3 -1
  195. package/dist/lib/server/notification-subscriptions/postgres-runtime.js +1 -0
  196. package/dist/lib/server/notification-subscriptions/postgres-runtime.mjs +1 -0
  197. package/dist/lib/server/notification-subscriptions/runtime.d.mts +12 -1
  198. package/dist/lib/server/notification-subscriptions/runtime.d.ts +12 -1
  199. package/dist/lib/server/notification-subscriptions/runtime.js +102 -16
  200. package/dist/lib/server/notification-subscriptions/runtime.mjs +101 -16
  201. package/dist/lib/server/notification-subscriptions/types.d.mts +104 -1
  202. package/dist/lib/server/notification-subscriptions/types.d.ts +104 -1
  203. package/dist/lib/server/webhook-emitter.d.mts +40 -5
  204. package/dist/lib/server/webhook-emitter.d.ts +40 -5
  205. package/dist/lib/server/webhook-emitter.js +23 -12
  206. package/dist/lib/server/webhook-emitter.mjs +23 -12
  207. package/dist/lib/storage/interfaces.d.mts +14 -2
  208. package/dist/lib/storage/interfaces.d.ts +14 -2
  209. package/dist/lib/testing/compliance/comply.d.mts +9 -3
  210. package/dist/lib/testing/compliance/comply.d.ts +9 -3
  211. package/dist/lib/testing/compliance/comply.js +158 -3
  212. package/dist/lib/testing/compliance/comply.mjs +159 -4
  213. package/dist/lib/testing/compliance/storyboard-tracks.js +7 -5
  214. package/dist/lib/testing/compliance/storyboard-tracks.mjs +7 -5
  215. package/dist/lib/testing/compliance/summary.js +10 -1
  216. package/dist/lib/testing/compliance/summary.mjs +10 -1
  217. package/dist/lib/testing/index.d.mts +1 -1
  218. package/dist/lib/testing/index.d.ts +1 -1
  219. package/dist/lib/testing/index.js +2 -0
  220. package/dist/lib/testing/index.mjs +3 -1
  221. package/dist/lib/testing/storyboard/agent-routing.d.mts +12 -43
  222. package/dist/lib/testing/storyboard/agent-routing.d.ts +12 -43
  223. package/dist/lib/testing/storyboard/agent-routing.js +75 -13
  224. package/dist/lib/testing/storyboard/agent-routing.mjs +70 -12
  225. package/dist/lib/testing/storyboard/index.d.mts +1 -0
  226. package/dist/lib/testing/storyboard/index.d.ts +1 -0
  227. package/dist/lib/testing/storyboard/index.js +3 -0
  228. package/dist/lib/testing/storyboard/index.mjs +2 -0
  229. package/dist/lib/testing/storyboard/junit.d.mts +1 -1
  230. package/dist/lib/testing/storyboard/junit.d.ts +1 -1
  231. package/dist/lib/testing/storyboard/junit.js +21 -2
  232. package/dist/lib/testing/storyboard/junit.mjs +21 -2
  233. package/dist/lib/testing/storyboard/probes.d.mts +130 -0
  234. package/dist/lib/testing/storyboard/probes.d.ts +130 -0
  235. package/dist/lib/testing/storyboard/probes.js +682 -10
  236. package/dist/lib/testing/storyboard/probes.mjs +683 -3
  237. package/dist/lib/testing/storyboard/request-signing/builder.d.mts +16 -5
  238. package/dist/lib/testing/storyboard/request-signing/builder.d.ts +16 -5
  239. package/dist/lib/testing/storyboard/request-signing/grader.d.mts +44 -1
  240. package/dist/lib/testing/storyboard/request-signing/grader.d.ts +44 -1
  241. package/dist/lib/testing/storyboard/request-signing/grader.js +46 -22
  242. package/dist/lib/testing/storyboard/request-signing/grader.mjs +43 -21
  243. package/dist/lib/testing/storyboard/request-signing/probe-dispatch.d.mts +86 -11
  244. package/dist/lib/testing/storyboard/request-signing/probe-dispatch.d.ts +86 -11
  245. package/dist/lib/testing/storyboard/request-signing/probe-dispatch.js +119 -25
  246. package/dist/lib/testing/storyboard/request-signing/probe-dispatch.mjs +117 -26
  247. package/dist/lib/testing/storyboard/request-signing/synthesize.js +22 -2
  248. package/dist/lib/testing/storyboard/request-signing/synthesize.mjs +22 -2
  249. package/dist/lib/testing/storyboard/runner.d.mts +103 -0
  250. package/dist/lib/testing/storyboard/runner.d.ts +103 -0
  251. package/dist/lib/testing/storyboard/runner.js +1090 -268
  252. package/dist/lib/testing/storyboard/runner.mjs +1096 -261
  253. package/dist/lib/testing/storyboard/seeding.d.mts +4 -1
  254. package/dist/lib/testing/storyboard/seeding.d.ts +4 -1
  255. package/dist/lib/testing/storyboard/seeding.js +55 -24
  256. package/dist/lib/testing/storyboard/seeding.mjs +55 -24
  257. package/dist/lib/testing/storyboard/test-kit.d.mts +37 -3
  258. package/dist/lib/testing/storyboard/test-kit.d.ts +37 -3
  259. package/dist/lib/testing/storyboard/test-kit.js +8 -2
  260. package/dist/lib/testing/storyboard/test-kit.mjs +7 -2
  261. package/dist/lib/testing/storyboard/types.d.mts +132 -10
  262. package/dist/lib/testing/storyboard/types.d.ts +132 -10
  263. package/dist/lib/testing/storyboard/types.js +17 -0
  264. package/dist/lib/testing/storyboard/types.mjs +16 -0
  265. package/dist/lib/testing/storyboard/validations.d.mts +1 -1
  266. package/dist/lib/testing/storyboard/validations.d.ts +1 -1
  267. package/dist/lib/testing/storyboard/validations.js +16 -0
  268. package/dist/lib/testing/storyboard/validations.mjs +16 -0
  269. package/dist/lib/testing/test-controller.d.mts +1 -1
  270. package/dist/lib/testing/test-controller.d.ts +1 -1
  271. package/dist/lib/types/buy-products.d.ts +71 -6
  272. package/dist/lib/types/control-media-buy.d.ts +25 -11
  273. package/dist/lib/types/core.generated.d.mts +69 -10
  274. package/dist/lib/types/core.generated.d.ts +69 -10
  275. package/dist/lib/types/create-media-buy.d.ts +71 -6
  276. package/dist/lib/types/forward-compat-error-codes.d.mts +7 -6
  277. package/dist/lib/types/forward-compat-error-codes.d.ts +7 -6
  278. package/dist/lib/types/index.d.mts +2 -2
  279. package/dist/lib/types/index.d.ts +2 -2
  280. package/dist/lib/types/schemas.generated.d.ts +8040 -8116
  281. package/dist/lib/types/schemas.generated.js +1074 -309
  282. package/dist/lib/types/schemas.generated.mjs +1068 -309
  283. package/dist/lib/types/tools.generated.d.mts +65 -6
  284. package/dist/lib/types/tools.generated.d.ts +65 -6
  285. package/dist/lib/types/update-media-buy.d.ts +71 -6
  286. package/dist/lib/utils/redact-secrets.d.mts +1 -1
  287. package/dist/lib/utils/redact-secrets.d.ts +1 -1
  288. package/dist/lib/utils/redact-secrets.js +1 -1
  289. package/dist/lib/utils/redact-secrets.mjs +1 -1
  290. package/dist/lib/v2/projection/cache-versions.d.mts +0 -1
  291. package/dist/lib/v2/projection/cache-versions.d.ts +0 -1
  292. package/dist/lib/v2/projection/cache-versions.js +1 -15
  293. package/dist/lib/v2/projection/cache-versions.mjs +1 -14
  294. package/dist/lib/v2/projection/canonical-properties.js +2 -2
  295. package/dist/lib/v2/projection/canonical-properties.mjs +3 -3
  296. package/dist/lib/v2/projection/registry.d.mts +1 -1
  297. package/dist/lib/v2/projection/registry.d.ts +1 -1
  298. package/dist/lib/v2/projection/registry.js +2 -2
  299. package/dist/lib/v2/projection/registry.mjs +3 -3
  300. package/dist/lib/validation/schema-loader.d.mts +9 -1
  301. package/dist/lib/validation/schema-loader.d.ts +9 -1
  302. package/dist/lib/validation/schema-loader.js +65 -8
  303. package/dist/lib/validation/schema-loader.mjs +64 -8
  304. package/dist/lib/version.d.mts +5 -5
  305. package/dist/lib/version.d.ts +5 -5
  306. package/dist/lib/version.js +3 -8
  307. package/dist/lib/version.mjs +3 -8
  308. package/dist/lib/wholesale-feed-sync/index.d.mts +1 -0
  309. package/dist/lib/wholesale-feed-sync/index.d.ts +1 -0
  310. package/dist/lib/wholesale-feed-sync/protocol-types.d.mts +42 -0
  311. package/dist/lib/wholesale-feed-sync/protocol-types.d.ts +42 -0
  312. package/dist/lib/wholesale-feed-sync/protocol-types.js +16 -0
  313. package/dist/lib/wholesale-feed-sync/protocol-types.mjs +0 -0
  314. package/dist/lib/wholesale-feed-sync/sync.d.mts +6 -6
  315. package/dist/lib/wholesale-feed-sync/sync.d.ts +6 -6
  316. package/dist/lib/wholesale-feed-sync/sync.js +3 -1
  317. package/dist/lib/wholesale-feed-sync/sync.mjs +3 -1
  318. package/dist/lib/wholesale-feed-sync/types.d.mts +15 -14
  319. package/dist/lib/wholesale-feed-sync/types.d.ts +15 -14
  320. package/dist/lib/wholesale-feed-sync/webhook-notification.d.mts +7 -5
  321. package/dist/lib/wholesale-feed-sync/webhook-notification.d.ts +7 -5
  322. package/dist/lib/wholesale-feed-sync/webhook-notification.js +45 -0
  323. package/dist/lib/wholesale-feed-sync/webhook-notification.mjs +44 -0
  324. package/docs/CLI.md +1 -1
  325. package/docs/TYPE-SUMMARY.md +118 -4
  326. package/docs/guides/ASYNC-API-REFERENCE.md +62 -1
  327. package/docs/guides/ASYNC-DEVELOPER-GUIDE.md +25 -0
  328. package/docs/guides/ASYNC-DOCUMENTATION-INDEX.md +3 -0
  329. package/docs/guides/BUYER-QUICKSTART-3.2.md +5 -0
  330. package/docs/guides/DURABLE-BUYER-WRITES.md +337 -0
  331. package/docs/guides/EXISTING-PLATFORM.md +80 -1
  332. package/docs/guides/MEDIA-BUY-3.2-COMPATIBILITY.md +57 -0
  333. package/docs/guides/MEDIA-BUY-ACTION-ASSESSMENT.md +300 -0
  334. package/docs/guides/REPORTING-LEDGER.md +654 -3
  335. package/docs/guides/REPORTING-RECONCILIATION.md +50 -0
  336. package/docs/guides/REPORTING-SOURCE-EXECUTOR.md +63 -1
  337. package/docs/guides/SELLER-QUICKSTART-3.2.md +2 -0
  338. package/docs/guides/VALIDATE-YOUR-AGENT.md +35 -0
  339. package/docs/guides/idempotency-crash-recovery.md +4 -0
  340. package/docs/llms.txt +4 -2
  341. package/docs/migration-14.x-rc-worksheet.md +60 -5
  342. package/docs/migration-7.9-to-7.10.md +7 -5
  343. package/examples/README.md +17 -0
  344. package/examples/durable-buyer-writes/caller.ts +745 -0
  345. package/examples/durable-buyer-writes/worker.ts +240 -0
  346. package/examples/reliable-reporting-service/README.md +100 -0
  347. package/examples/seller-3.2-starter.ts +7 -8
  348. package/examples/targeting-input-existing-platform.ts +153 -0
  349. package/package.json +41 -29
  350. package/skills/build-seller-agent/SKILL.md +2 -0
  351. package/skills/build-seller-agent/specialisms/signed-requests.md +11 -1
  352. package/skills/cross-cutting.md +28 -11
  353. package/compliance/cache/3.1.0-beta.7/domains/brand/index.yaml +0 -160
  354. package/compliance/cache/3.1.0-beta.7/domains/brand/scenarios/distributed_brand_resolution.yaml +0 -415
  355. package/compliance/cache/3.1.0-beta.7/domains/brand/scenarios/single_side_trust_extension.yaml +0 -454
  356. package/compliance/cache/3.1.0-beta.7/domains/creative/index.yaml +0 -339
  357. package/compliance/cache/3.1.0-beta.7/domains/creative/scenarios/billing_out_of_band.yaml +0 -153
  358. package/compliance/cache/3.1.0-beta.7/domains/creative/scenarios/creative_lifecycle_webhooks.yaml +0 -389
  359. package/compliance/cache/3.1.0-beta.7/domains/creative/scenarios/native_in_feed.yaml +0 -543
  360. package/compliance/cache/3.1.0-beta.7/domains/governance/index.yaml +0 -682
  361. package/compliance/cache/3.1.0-beta.7/domains/media-buy/index.yaml +0 -781
  362. package/compliance/cache/3.1.0-beta.7/domains/media-buy/scenarios/audience_buy_flow.yaml +0 -380
  363. package/compliance/cache/3.1.0-beta.7/domains/media-buy/scenarios/available_actions.yaml +0 -565
  364. package/compliance/cache/3.1.0-beta.7/domains/media-buy/scenarios/billing_finality_delivery.yaml +0 -354
  365. package/compliance/cache/3.1.0-beta.7/domains/media-buy/scenarios/canonical_formats.yaml +0 -711
  366. package/compliance/cache/3.1.0-beta.7/domains/media-buy/scenarios/clicks_buy_flow.yaml +0 -264
  367. package/compliance/cache/3.1.0-beta.7/domains/media-buy/scenarios/completed_views_buy_flow.yaml +0 -344
  368. package/compliance/cache/3.1.0-beta.7/domains/media-buy/scenarios/create_media_buy_async.yaml +0 -234
  369. package/compliance/cache/3.1.0-beta.7/domains/media-buy/scenarios/creative_fate_after_cancellation.yaml +0 -419
  370. package/compliance/cache/3.1.0-beta.7/domains/media-buy/scenarios/creative_reception.yaml +0 -247
  371. package/compliance/cache/3.1.0-beta.7/domains/media-buy/scenarios/delivery_reporting.yaml +0 -357
  372. package/compliance/cache/3.1.0-beta.7/domains/media-buy/scenarios/dependency_impairment.yaml +0 -633
  373. package/compliance/cache/3.1.0-beta.7/domains/media-buy/scenarios/dependency_impairment_cardinality.yaml +0 -800
  374. package/compliance/cache/3.1.0-beta.7/domains/media-buy/scenarios/event_dedup_flow.yaml +0 -399
  375. package/compliance/cache/3.1.0-beta.7/domains/media-buy/scenarios/frequency_cap_enforcement.yaml +0 -309
  376. package/compliance/cache/3.1.0-beta.7/domains/media-buy/scenarios/governance_approved.yaml +0 -214
  377. package/compliance/cache/3.1.0-beta.7/domains/media-buy/scenarios/governance_conditions.yaml +0 -199
  378. package/compliance/cache/3.1.0-beta.7/domains/media-buy/scenarios/governance_denied.yaml +0 -204
  379. package/compliance/cache/3.1.0-beta.7/domains/media-buy/scenarios/governance_denied_recovery.yaml +0 -252
  380. package/compliance/cache/3.1.0-beta.7/domains/media-buy/scenarios/invalid_transitions.yaml +0 -289
  381. package/compliance/cache/3.1.0-beta.7/domains/media-buy/scenarios/inventory_list_no_match.yaml +0 -148
  382. package/compliance/cache/3.1.0-beta.7/domains/media-buy/scenarios/inventory_list_targeting.yaml +0 -276
  383. package/compliance/cache/3.1.0-beta.7/domains/media-buy/scenarios/measurement_accountability.yaml +0 -244
  384. package/compliance/cache/3.1.0-beta.7/domains/media-buy/scenarios/measurement_terms_rejected.yaml +0 -203
  385. package/compliance/cache/3.1.0-beta.7/domains/media-buy/scenarios/pending_creatives_to_start.yaml +0 -274
  386. package/compliance/cache/3.1.0-beta.7/domains/media-buy/scenarios/per_creative_conversion_attribution.yaml +0 -500
  387. package/compliance/cache/3.1.0-beta.7/domains/media-buy/scenarios/performance_buy_flow.yaml +0 -428
  388. package/compliance/cache/3.1.0-beta.7/domains/media-buy/scenarios/performance_buy_flow_roas.yaml +0 -470
  389. package/compliance/cache/3.1.0-beta.7/domains/media-buy/scenarios/product_signal_targeting.yaml +0 -373
  390. package/compliance/cache/3.1.0-beta.7/domains/media-buy/scenarios/proposal_finalize.yaml +0 -399
  391. package/compliance/cache/3.1.0-beta.7/domains/media-buy/scenarios/proposal_finalize_asap_timing.yaml +0 -264
  392. package/compliance/cache/3.1.0-beta.7/domains/media-buy/scenarios/proposal_not_found_errors.yaml +0 -257
  393. package/compliance/cache/3.1.0-beta.7/domains/media-buy/scenarios/provenance_audit_observation.yaml +0 -333
  394. package/compliance/cache/3.1.0-beta.7/domains/media-buy/scenarios/provenance_enforcement.yaml +0 -517
  395. package/compliance/cache/3.1.0-beta.7/domains/media-buy/scenarios/provenance_truth_of_claim.yaml +0 -294
  396. package/compliance/cache/3.1.0-beta.7/domains/media-buy/scenarios/reach_buy_flow.yaml +0 -823
  397. package/compliance/cache/3.1.0-beta.7/domains/media-buy/scenarios/refine_finalize_exclusivity.yaml +0 -360
  398. package/compliance/cache/3.1.0-beta.7/domains/media-buy/scenarios/refine_products.yaml +0 -148
  399. package/compliance/cache/3.1.0-beta.7/domains/media-buy/scenarios/vendor_metric_accountability.yaml +0 -293
  400. package/compliance/cache/3.1.0-beta.7/domains/media-buy/scenarios/vendor_metric_catalog_precondition.yaml +0 -307
  401. package/compliance/cache/3.1.0-beta.7/domains/media-buy/scenarios/vendor_metric_optimization_flow.yaml +0 -576
  402. package/compliance/cache/3.1.0-beta.7/domains/media-buy/state-machine.yaml +0 -442
  403. package/compliance/cache/3.1.0-beta.7/domains/signals/index.yaml +0 -266
  404. package/compliance/cache/3.1.0-beta.7/domains/sponsored-intelligence/index.yaml +0 -256
  405. package/compliance/cache/3.1.0-beta.7/index.json +0 -356
  406. package/compliance/cache/3.1.0-beta.7/protocols/brand/index.yaml +0 -160
  407. package/compliance/cache/3.1.0-beta.7/protocols/brand/scenarios/distributed_brand_resolution.yaml +0 -415
  408. package/compliance/cache/3.1.0-beta.7/protocols/brand/scenarios/single_side_trust_extension.yaml +0 -454
  409. package/compliance/cache/3.1.0-beta.7/protocols/creative/index.yaml +0 -339
  410. package/compliance/cache/3.1.0-beta.7/protocols/creative/scenarios/billing_out_of_band.yaml +0 -153
  411. package/compliance/cache/3.1.0-beta.7/protocols/creative/scenarios/creative_lifecycle_webhooks.yaml +0 -389
  412. package/compliance/cache/3.1.0-beta.7/protocols/creative/scenarios/native_in_feed.yaml +0 -543
  413. package/compliance/cache/3.1.0-beta.7/protocols/governance/index.yaml +0 -682
  414. package/compliance/cache/3.1.0-beta.7/protocols/media-buy/index.yaml +0 -781
  415. package/compliance/cache/3.1.0-beta.7/protocols/media-buy/scenarios/audience_buy_flow.yaml +0 -380
  416. package/compliance/cache/3.1.0-beta.7/protocols/media-buy/scenarios/available_actions.yaml +0 -565
  417. package/compliance/cache/3.1.0-beta.7/protocols/media-buy/scenarios/billing_finality_delivery.yaml +0 -354
  418. package/compliance/cache/3.1.0-beta.7/protocols/media-buy/scenarios/canonical_formats.yaml +0 -711
  419. package/compliance/cache/3.1.0-beta.7/protocols/media-buy/scenarios/clicks_buy_flow.yaml +0 -264
  420. package/compliance/cache/3.1.0-beta.7/protocols/media-buy/scenarios/completed_views_buy_flow.yaml +0 -344
  421. package/compliance/cache/3.1.0-beta.7/protocols/media-buy/scenarios/create_media_buy_async.yaml +0 -234
  422. package/compliance/cache/3.1.0-beta.7/protocols/media-buy/scenarios/creative_fate_after_cancellation.yaml +0 -419
  423. package/compliance/cache/3.1.0-beta.7/protocols/media-buy/scenarios/creative_reception.yaml +0 -247
  424. package/compliance/cache/3.1.0-beta.7/protocols/media-buy/scenarios/delivery_reporting.yaml +0 -357
  425. package/compliance/cache/3.1.0-beta.7/protocols/media-buy/scenarios/dependency_impairment.yaml +0 -633
  426. package/compliance/cache/3.1.0-beta.7/protocols/media-buy/scenarios/dependency_impairment_cardinality.yaml +0 -800
  427. package/compliance/cache/3.1.0-beta.7/protocols/media-buy/scenarios/event_dedup_flow.yaml +0 -399
  428. package/compliance/cache/3.1.0-beta.7/protocols/media-buy/scenarios/frequency_cap_enforcement.yaml +0 -309
  429. package/compliance/cache/3.1.0-beta.7/protocols/media-buy/scenarios/governance_approved.yaml +0 -214
  430. package/compliance/cache/3.1.0-beta.7/protocols/media-buy/scenarios/governance_conditions.yaml +0 -199
  431. package/compliance/cache/3.1.0-beta.7/protocols/media-buy/scenarios/governance_denied.yaml +0 -204
  432. package/compliance/cache/3.1.0-beta.7/protocols/media-buy/scenarios/governance_denied_recovery.yaml +0 -252
  433. package/compliance/cache/3.1.0-beta.7/protocols/media-buy/scenarios/invalid_transitions.yaml +0 -289
  434. package/compliance/cache/3.1.0-beta.7/protocols/media-buy/scenarios/inventory_list_no_match.yaml +0 -148
  435. package/compliance/cache/3.1.0-beta.7/protocols/media-buy/scenarios/inventory_list_targeting.yaml +0 -276
  436. package/compliance/cache/3.1.0-beta.7/protocols/media-buy/scenarios/measurement_accountability.yaml +0 -244
  437. package/compliance/cache/3.1.0-beta.7/protocols/media-buy/scenarios/measurement_terms_rejected.yaml +0 -203
  438. package/compliance/cache/3.1.0-beta.7/protocols/media-buy/scenarios/pending_creatives_to_start.yaml +0 -274
  439. package/compliance/cache/3.1.0-beta.7/protocols/media-buy/scenarios/per_creative_conversion_attribution.yaml +0 -500
  440. package/compliance/cache/3.1.0-beta.7/protocols/media-buy/scenarios/performance_buy_flow.yaml +0 -428
  441. package/compliance/cache/3.1.0-beta.7/protocols/media-buy/scenarios/performance_buy_flow_roas.yaml +0 -470
  442. package/compliance/cache/3.1.0-beta.7/protocols/media-buy/scenarios/product_signal_targeting.yaml +0 -373
  443. package/compliance/cache/3.1.0-beta.7/protocols/media-buy/scenarios/proposal_finalize.yaml +0 -399
  444. package/compliance/cache/3.1.0-beta.7/protocols/media-buy/scenarios/proposal_finalize_asap_timing.yaml +0 -264
  445. package/compliance/cache/3.1.0-beta.7/protocols/media-buy/scenarios/proposal_not_found_errors.yaml +0 -257
  446. package/compliance/cache/3.1.0-beta.7/protocols/media-buy/scenarios/provenance_audit_observation.yaml +0 -333
  447. package/compliance/cache/3.1.0-beta.7/protocols/media-buy/scenarios/provenance_enforcement.yaml +0 -517
  448. package/compliance/cache/3.1.0-beta.7/protocols/media-buy/scenarios/provenance_truth_of_claim.yaml +0 -294
  449. package/compliance/cache/3.1.0-beta.7/protocols/media-buy/scenarios/reach_buy_flow.yaml +0 -823
  450. package/compliance/cache/3.1.0-beta.7/protocols/media-buy/scenarios/refine_finalize_exclusivity.yaml +0 -360
  451. package/compliance/cache/3.1.0-beta.7/protocols/media-buy/scenarios/refine_products.yaml +0 -148
  452. package/compliance/cache/3.1.0-beta.7/protocols/media-buy/scenarios/vendor_metric_accountability.yaml +0 -293
  453. package/compliance/cache/3.1.0-beta.7/protocols/media-buy/scenarios/vendor_metric_catalog_precondition.yaml +0 -307
  454. package/compliance/cache/3.1.0-beta.7/protocols/media-buy/scenarios/vendor_metric_optimization_flow.yaml +0 -576
  455. package/compliance/cache/3.1.0-beta.7/protocols/media-buy/state-machine.yaml +0 -442
  456. package/compliance/cache/3.1.0-beta.7/protocols/signals/index.yaml +0 -266
  457. package/compliance/cache/3.1.0-beta.7/protocols/sponsored-intelligence/index.yaml +0 -256
  458. package/compliance/cache/3.1.0-beta.7/specialisms/audience-sync/index.yaml +0 -313
  459. package/compliance/cache/3.1.0-beta.7/specialisms/brand-rights/index.yaml +0 -350
  460. package/compliance/cache/3.1.0-beta.7/specialisms/brand-rights/scenarios/governance_denied.yaml +0 -226
  461. package/compliance/cache/3.1.0-beta.7/specialisms/collection-lists/index.yaml +0 -359
  462. package/compliance/cache/3.1.0-beta.7/specialisms/content-standards/index.yaml +0 -572
  463. package/compliance/cache/3.1.0-beta.7/specialisms/creative-ad-server/index.yaml +0 -409
  464. package/compliance/cache/3.1.0-beta.7/specialisms/creative-generative/generative-seller.yaml +0 -807
  465. package/compliance/cache/3.1.0-beta.7/specialisms/creative-generative/index.yaml +0 -758
  466. package/compliance/cache/3.1.0-beta.7/specialisms/creative-template/index.yaml +0 -510
  467. package/compliance/cache/3.1.0-beta.7/specialisms/governance-aware-seller/index.yaml +0 -143
  468. package/compliance/cache/3.1.0-beta.7/specialisms/governance-aware-seller/scenarios/governance_multi_agent_rejected.yaml +0 -117
  469. package/compliance/cache/3.1.0-beta.7/specialisms/governance-delivery-monitor/index.yaml +0 -441
  470. package/compliance/cache/3.1.0-beta.7/specialisms/governance-spend-authority/denied.yaml +0 -221
  471. package/compliance/cache/3.1.0-beta.7/specialisms/governance-spend-authority/index.yaml +0 -330
  472. package/compliance/cache/3.1.0-beta.7/specialisms/property-lists/index.yaml +0 -482
  473. package/compliance/cache/3.1.0-beta.7/specialisms/sales-broadcast-tv/index.yaml +0 -738
  474. package/compliance/cache/3.1.0-beta.7/specialisms/sales-catalog-driven/index.yaml +0 -840
  475. package/compliance/cache/3.1.0-beta.7/specialisms/sales-guaranteed/index.yaml +0 -601
  476. package/compliance/cache/3.1.0-beta.7/specialisms/sales-non-guaranteed/index.yaml +0 -546
  477. package/compliance/cache/3.1.0-beta.7/specialisms/sales-proposal-mode/index.yaml +0 -586
  478. package/compliance/cache/3.1.0-beta.7/specialisms/sales-social/index.yaml +0 -919
  479. package/compliance/cache/3.1.0-beta.7/specialisms/signal-marketplace/index.yaml +0 -424
  480. package/compliance/cache/3.1.0-beta.7/specialisms/signal-marketplace/scenarios/governance_denied.yaml +0 -211
  481. package/compliance/cache/3.1.0-beta.7/specialisms/signal-owned/index.yaml +0 -317
  482. package/compliance/cache/3.1.0-beta.7/specialisms/sponsored-intelligence/index.yaml +0 -59
  483. package/compliance/cache/3.1.0-beta.7/test-kits/acme-outdoor-live.yaml +0 -78
  484. package/compliance/cache/3.1.0-beta.7/test-kits/acme-outdoor.yaml +0 -223
  485. package/compliance/cache/3.1.0-beta.7/test-kits/billing-gate-runner.yaml +0 -115
  486. package/compliance/cache/3.1.0-beta.7/test-kits/bistro-oranje.yaml +0 -126
  487. package/compliance/cache/3.1.0-beta.7/test-kits/distributed-brand-runner.yaml +0 -281
  488. package/compliance/cache/3.1.0-beta.7/test-kits/nova-motors.yaml +0 -262
  489. package/compliance/cache/3.1.0-beta.7/test-kits/osei-natural.yaml +0 -126
  490. package/compliance/cache/3.1.0-beta.7/test-kits/parallel-dispatch-runner.yaml +0 -196
  491. package/compliance/cache/3.1.0-beta.7/test-kits/rate-limit-trip-runner.yaml +0 -172
  492. package/compliance/cache/3.1.0-beta.7/test-kits/signed-requests-runner.yaml +0 -155
  493. package/compliance/cache/3.1.0-beta.7/test-kits/single-side-trust-runner.yaml +0 -294
  494. package/compliance/cache/3.1.0-beta.7/test-kits/substitution-observer-runner.yaml +0 -688
  495. package/compliance/cache/3.1.0-beta.7/test-kits/summit-foods.yaml +0 -125
  496. package/compliance/cache/3.1.0-beta.7/test-kits/webhook-receiver-runner.yaml +0 -265
  497. package/compliance/cache/3.1.0-beta.7/test-vectors/plan-hash/001-minimal-plan.json +0 -43
  498. package/compliance/cache/3.1.0-beta.7/test-vectors/plan-hash/002-full-plan.json +0 -217
  499. package/compliance/cache/3.1.0-beta.7/test-vectors/plan-hash/003-bookkeeping-stripped.json +0 -60
  500. package/compliance/cache/3.1.0-beta.7/test-vectors/plan-hash/004a-human-review-omitted.json +0 -43
  501. package/compliance/cache/3.1.0-beta.7/test-vectors/plan-hash/004b-human-review-explicit-null.json +0 -49
  502. package/compliance/cache/3.1.0-beta.7/test-vectors/plan-hash/005a-policy-categories-order-1.json +0 -53
  503. package/compliance/cache/3.1.0-beta.7/test-vectors/plan-hash/005b-policy-categories-order-2.json +0 -57
  504. package/compliance/cache/3.1.0-beta.7/test-vectors/plan-hash/006a-ext-trace-v1.json +0 -49
  505. package/compliance/cache/3.1.0-beta.7/test-vectors/plan-hash/006b-ext-trace-v2.json +0 -53
  506. package/compliance/cache/3.1.0-beta.7/test-vectors/plan-hash/007-unicode-objectives.json +0 -43
  507. package/compliance/cache/3.1.0-beta.7/test-vectors/plan-hash/008-numeric-canonicalization.json +0 -65
  508. package/compliance/cache/3.1.0-beta.7/test-vectors/request-signing/README.md +0 -220
  509. package/compliance/cache/3.1.0-beta.7/test-vectors/request-signing/canonicalization.json +0 -241
  510. package/compliance/cache/3.1.0-beta.7/test-vectors/request-signing/keys.json +0 -60
  511. package/compliance/cache/3.1.0-beta.7/test-vectors/request-signing/negative/001-no-signature-header.json +0 -24
  512. package/compliance/cache/3.1.0-beta.7/test-vectors/request-signing/negative/002-wrong-tag.json +0 -26
  513. package/compliance/cache/3.1.0-beta.7/test-vectors/request-signing/negative/003-expired-signature.json +0 -26
  514. package/compliance/cache/3.1.0-beta.7/test-vectors/request-signing/negative/004-window-too-long.json +0 -26
  515. package/compliance/cache/3.1.0-beta.7/test-vectors/request-signing/negative/005-alg-not-allowed.json +0 -26
  516. package/compliance/cache/3.1.0-beta.7/test-vectors/request-signing/negative/006-missing-covered-component.json +0 -26
  517. package/compliance/cache/3.1.0-beta.7/test-vectors/request-signing/negative/007-missing-content-digest.json +0 -26
  518. package/compliance/cache/3.1.0-beta.7/test-vectors/request-signing/negative/008-unknown-keyid.json +0 -26
  519. package/compliance/cache/3.1.0-beta.7/test-vectors/request-signing/negative/009-key-ops-missing-verify.json +0 -27
  520. package/compliance/cache/3.1.0-beta.7/test-vectors/request-signing/negative/010-content-digest-mismatch.json +0 -33
  521. package/compliance/cache/3.1.0-beta.7/test-vectors/request-signing/negative/011-malformed-header.json +0 -27
  522. package/compliance/cache/3.1.0-beta.7/test-vectors/request-signing/negative/012-missing-expires-param.json +0 -26
  523. package/compliance/cache/3.1.0-beta.7/test-vectors/request-signing/negative/013-expires-le-created.json +0 -27
  524. package/compliance/cache/3.1.0-beta.7/test-vectors/request-signing/negative/014-missing-nonce-param.json +0 -27
  525. package/compliance/cache/3.1.0-beta.7/test-vectors/request-signing/negative/015-signature-invalid.json +0 -28
  526. package/compliance/cache/3.1.0-beta.7/test-vectors/request-signing/negative/016-replayed-nonce.json +0 -35
  527. package/compliance/cache/3.1.0-beta.7/test-vectors/request-signing/negative/017-key-revoked.json +0 -38
  528. package/compliance/cache/3.1.0-beta.7/test-vectors/request-signing/negative/018-digest-covered-when-forbidden.json +0 -28
  529. package/compliance/cache/3.1.0-beta.7/test-vectors/request-signing/negative/019-signature-without-signature-input.json +0 -26
  530. package/compliance/cache/3.1.0-beta.7/test-vectors/request-signing/negative/020-rate-abuse.json +0 -34
  531. package/compliance/cache/3.1.0-beta.7/test-vectors/request-signing/negative/021-duplicate-signature-input-label.json +0 -31
  532. package/compliance/cache/3.1.0-beta.7/test-vectors/request-signing/negative/022-multi-valued-content-type.json +0 -31
  533. package/compliance/cache/3.1.0-beta.7/test-vectors/request-signing/negative/023-multi-valued-content-digest.json +0 -32
  534. package/compliance/cache/3.1.0-beta.7/test-vectors/request-signing/negative/024-unquoted-string-param.json +0 -31
  535. package/compliance/cache/3.1.0-beta.7/test-vectors/request-signing/negative/025-jwk-alg-crv-mismatch.json +0 -43
  536. package/compliance/cache/3.1.0-beta.7/test-vectors/request-signing/negative/026-non-ascii-host.json +0 -31
  537. package/compliance/cache/3.1.0-beta.7/test-vectors/request-signing/negative/027-webhook-registration-authentication-unsigned.json +0 -25
  538. package/compliance/cache/3.1.0-beta.7/test-vectors/request-signing/negative/028-unsigned-protocol-method-required.json +0 -26
  539. package/compliance/cache/3.1.0-beta.7/test-vectors/request-signing/positive/001-basic-post.json +0 -30
  540. package/compliance/cache/3.1.0-beta.7/test-vectors/request-signing/positive/002-post-with-content-digest.json +0 -31
  541. package/compliance/cache/3.1.0-beta.7/test-vectors/request-signing/positive/003-es256-post.json +0 -30
  542. package/compliance/cache/3.1.0-beta.7/test-vectors/request-signing/positive/004-multiple-signature-labels.json +0 -26
  543. package/compliance/cache/3.1.0-beta.7/test-vectors/request-signing/positive/005-default-port-stripped.json +0 -30
  544. package/compliance/cache/3.1.0-beta.7/test-vectors/request-signing/positive/006-dot-segment-path.json +0 -30
  545. package/compliance/cache/3.1.0-beta.7/test-vectors/request-signing/positive/007-query-byte-preserved.json +0 -30
  546. package/compliance/cache/3.1.0-beta.7/test-vectors/request-signing/positive/008-percent-encoded-path.json +0 -30
  547. package/compliance/cache/3.1.0-beta.7/test-vectors/request-signing/positive/009-percent-encoded-unreserved-decoded.json +0 -30
  548. package/compliance/cache/3.1.0-beta.7/test-vectors/request-signing/positive/010-percent-encoded-slash-preserved.json +0 -30
  549. package/compliance/cache/3.1.0-beta.7/test-vectors/request-signing/positive/011-ipv6-authority.json +0 -30
  550. package/compliance/cache/3.1.0-beta.7/test-vectors/request-signing/positive/012-ipv6-authority-default-port-stripped.json +0 -30
  551. package/compliance/cache/3.1.0-beta.7/test-vectors/webhook-signing/README.md +0 -211
  552. package/compliance/cache/3.1.0-beta.7/test-vectors/webhook-signing/keys.json +0 -61
  553. package/compliance/cache/3.1.0-beta.7/test-vectors/webhook-signing/negative/001-wrong-tag.json +0 -26
  554. package/compliance/cache/3.1.0-beta.7/test-vectors/webhook-signing/negative/002-expired-signature.json +0 -26
  555. package/compliance/cache/3.1.0-beta.7/test-vectors/webhook-signing/negative/003-window-too-long.json +0 -26
  556. package/compliance/cache/3.1.0-beta.7/test-vectors/webhook-signing/negative/004-alg-not-allowed.json +0 -26
  557. package/compliance/cache/3.1.0-beta.7/test-vectors/webhook-signing/negative/005-missing-authority-component.json +0 -26
  558. package/compliance/cache/3.1.0-beta.7/test-vectors/webhook-signing/negative/006-missing-content-digest.json +0 -25
  559. package/compliance/cache/3.1.0-beta.7/test-vectors/webhook-signing/negative/007-unknown-keyid.json +0 -26
  560. package/compliance/cache/3.1.0-beta.7/test-vectors/webhook-signing/negative/008-wrong-adcp-use.json +0 -26
  561. package/compliance/cache/3.1.0-beta.7/test-vectors/webhook-signing/negative/009-content-digest-mismatch.json +0 -26
  562. package/compliance/cache/3.1.0-beta.7/test-vectors/webhook-signing/negative/010-malformed-signature-input.json +0 -26
  563. package/compliance/cache/3.1.0-beta.7/test-vectors/webhook-signing/negative/011-signature-without-input.json +0 -25
  564. package/compliance/cache/3.1.0-beta.7/test-vectors/webhook-signing/negative/012-missing-expires-param.json +0 -26
  565. package/compliance/cache/3.1.0-beta.7/test-vectors/webhook-signing/negative/013-expires-le-created.json +0 -26
  566. package/compliance/cache/3.1.0-beta.7/test-vectors/webhook-signing/negative/014-missing-nonce-param.json +0 -26
  567. package/compliance/cache/3.1.0-beta.7/test-vectors/webhook-signing/negative/015-signature-invalid.json +0 -26
  568. package/compliance/cache/3.1.0-beta.7/test-vectors/webhook-signing/negative/016-replayed-nonce.json +0 -37
  569. package/compliance/cache/3.1.0-beta.7/test-vectors/webhook-signing/negative/017-key-revoked.json +0 -32
  570. package/compliance/cache/3.1.0-beta.7/test-vectors/webhook-signing/negative/018-rate-abuse.json +0 -33
  571. package/compliance/cache/3.1.0-beta.7/test-vectors/webhook-signing/negative/019-revocation-stale.json +0 -32
  572. package/compliance/cache/3.1.0-beta.7/test-vectors/webhook-signing/negative/020-key-ops-missing-verify.json +0 -41
  573. package/compliance/cache/3.1.0-beta.7/test-vectors/webhook-signing/negative/021-base64-alphabet-mixing.json +0 -26
  574. package/compliance/cache/3.1.0-beta.7/test-vectors/webhook-signing/positive/001-basic-post.json +0 -24
  575. package/compliance/cache/3.1.0-beta.7/test-vectors/webhook-signing/positive/002-es256-post.json +0 -24
  576. package/compliance/cache/3.1.0-beta.7/test-vectors/webhook-signing/positive/003-multiple-signature-labels.json +0 -24
  577. package/compliance/cache/3.1.0-beta.7/test-vectors/webhook-signing/positive/004-default-port-stripped.json +0 -24
  578. package/compliance/cache/3.1.0-beta.7/test-vectors/webhook-signing/positive/005-percent-encoded-path.json +0 -24
  579. package/compliance/cache/3.1.0-beta.7/test-vectors/webhook-signing/positive/006-query-byte-preserved.json +0 -24
  580. package/compliance/cache/3.1.0-beta.7/test-vectors/webhook-signing/positive/007-body-without-idempotency-key.json +0 -25
  581. package/compliance/cache/3.1.0-beta.7/universal/billing-gate-dispatch.yaml +0 -450
  582. package/compliance/cache/3.1.0-beta.7/universal/canonical-format-validate-input.yaml +0 -640
  583. package/compliance/cache/3.1.0-beta.7/universal/capability-discovery.yaml +0 -125
  584. package/compliance/cache/3.1.0-beta.7/universal/collection-lists-pagination-integrity.yaml +0 -306
  585. package/compliance/cache/3.1.0-beta.7/universal/comply-controller-mode-gate.yaml +0 -141
  586. package/compliance/cache/3.1.0-beta.7/universal/content-standards-pagination-integrity.yaml +0 -326
  587. package/compliance/cache/3.1.0-beta.7/universal/deterministic-testing.yaml +0 -1430
  588. package/compliance/cache/3.1.0-beta.7/universal/error-compliance-signals.yaml +0 -377
  589. package/compliance/cache/3.1.0-beta.7/universal/error-compliance.yaml +0 -528
  590. package/compliance/cache/3.1.0-beta.7/universal/fictional-entities.yaml +0 -307
  591. package/compliance/cache/3.1.0-beta.7/universal/get-media-buys-pagination-integrity.yaml +0 -160
  592. package/compliance/cache/3.1.0-beta.7/universal/get-signals-pagination-integrity.yaml +0 -211
  593. package/compliance/cache/3.1.0-beta.7/universal/idempotency.yaml +0 -861
  594. package/compliance/cache/3.1.0-beta.7/universal/notification-config-event-scope.yaml +0 -119
  595. package/compliance/cache/3.1.0-beta.7/universal/notification-config-lifecycle.yaml +0 -337
  596. package/compliance/cache/3.1.0-beta.7/universal/notification-config-rejections.yaml +0 -107
  597. package/compliance/cache/3.1.0-beta.7/universal/pagination-integrity-creative-formats.yaml +0 -265
  598. package/compliance/cache/3.1.0-beta.7/universal/pagination-integrity-list-accounts.yaml +0 -245
  599. package/compliance/cache/3.1.0-beta.7/universal/pagination-integrity.yaml +0 -263
  600. package/compliance/cache/3.1.0-beta.7/universal/property-lists-pagination-integrity.yaml +0 -307
  601. package/compliance/cache/3.1.0-beta.7/universal/read-tool-idempotency.yaml +0 -405
  602. package/compliance/cache/3.1.0-beta.7/universal/runner-output-contract.yaml +0 -1266
  603. package/compliance/cache/3.1.0-beta.7/universal/schema-validation-signals.yaml +0 -181
  604. package/compliance/cache/3.1.0-beta.7/universal/schema-validation.yaml +0 -548
  605. package/compliance/cache/3.1.0-beta.7/universal/security.yaml +0 -539
  606. package/compliance/cache/3.1.0-beta.7/universal/signed-requests.yaml +0 -217
  607. package/compliance/cache/3.1.0-beta.7/universal/stale-response-advisory.yaml +0 -295
  608. package/compliance/cache/3.1.0-beta.7/universal/storyboard-schema.yaml +0 -2136
  609. package/compliance/cache/3.1.0-beta.7/universal/v3-envelope-integrity.yaml +0 -117
  610. package/compliance/cache/3.1.0-beta.7/universal/version-negotiation.yaml +0 -130
  611. package/compliance/cache/3.1.0-beta.7/universal/webhook-emission.yaml +0 -411
  612. package/compliance/cache/3.1.0-beta.7/universal/wholesale-feed-bulk-webhooks.yaml +0 -82
  613. package/compliance/cache/3.1.0-beta.7/universal/wholesale-feed-product-webhooks.yaml +0 -83
  614. package/compliance/cache/3.1.0-beta.7/universal/wholesale-feed-products.yaml +0 -151
  615. package/compliance/cache/3.1.0-beta.7/universal/wholesale-feed-signal-webhooks.yaml +0 -83
  616. package/compliance/cache/3.1.0-beta.7/universal/wholesale-feed-signals.yaml +0 -149
  617. package/dist/lib/types/v3-1-beta/index.d.mts +0 -1
  618. package/dist/lib/types/v3-1-beta/index.d.ts +0 -1
  619. package/dist/lib/types/v3-1-beta/index.mjs +0 -1
  620. package/dist/lib/types/v3-1-beta/tools.generated.d.mts +0 -26788
  621. package/dist/lib/types/v3-1-beta/tools.generated.d.ts +0 -26788
  622. /package/dist/lib/{types/v3-1-beta/tools.generated.mjs → media-buy/action-types.mjs} +0 -0
@@ -67,19 +67,39 @@ import {
67
67
  probeOauthAuthServerMetadata,
68
68
  fetchProbe,
69
69
  rawMcpProbe,
70
+ rawMcpSessionProbe,
70
71
  generateRandomInvalidApiKey,
71
72
  generateRandomInvalidJwt
72
73
  } from "./probes.mjs";
73
74
  import { readBrandJsonUrl } from "../../signing/agent-resolver/capabilities-types.mjs";
74
75
  import { selectAgentByUrl } from "../../signing/agent-resolver/select-agent.mjs";
75
- import { resolveDeclaredTestKit, selectProbeTask, validateTestKit } from "./test-kit.mjs";
76
+ import {
77
+ PROBE_TASK_ALLOWLIST,
78
+ PROBE_TASK_ALLOWLIST_SUMMARY,
79
+ resolveDeclaredTestKit,
80
+ validateTestKit
81
+ } from "./test-kit.mjs";
82
+ import { MUTATING_TASKS } from "../../utils/idempotency.mjs";
83
+ import { TOOL_REQUEST_SCHEMAS } from "../../utils/tool-request-schemas.mjs";
84
+ import {
85
+ ACCOUNT_TOOLS,
86
+ BRAND_RIGHTS_TOOLS,
87
+ CREATIVE_TOOLS,
88
+ EVENT_TRACKING_TOOLS,
89
+ GOVERNANCE_TOOLS,
90
+ MEDIA_BUY_TOOLS,
91
+ PROTOCOL_TOOLS,
92
+ SIGNALS_TOOLS
93
+ } from "../../utils/capabilities.mjs";
76
94
  import { normalizeValidationOnlyTasks, validateStoryboardShape, VALIDATION_ONLY_TASK } from "./loader.mjs";
77
95
  import { evaluatePhaseCondition, phaseConditionUsesContext } from "./phase-condition.mjs";
78
96
  import { trustedStoryboardComplianceRoot } from "./provenance.mjs";
79
97
  import { probeRequestSigningVector } from "./request-signing/probe-dispatch.mjs";
98
+ import { REQUEST_SIGNING_PROBE_TASK } from "./request-signing/synthesize.mjs";
80
99
  import { createWebhookReceiver } from "./webhook-receiver.mjs";
81
100
  import { WEBHOOK_ASSERTION_TASKS, armWebhookAssertions, executeWebhookAssertionStep } from "./webhook-assertions.mjs";
82
101
  import { runControllerSeeding } from "./seeding.mjs";
102
+ import { callControllerRaw } from "../test-controller.mjs";
83
103
  import { applyFixtureBindingsToRequest } from "./fixture-resolution.mjs";
84
104
  import { getComplianceCacheDir } from "./compliance.mjs";
85
105
  import { signWebhook } from "../../signing/client.mjs";
@@ -105,9 +125,13 @@ import {
105
125
  buildRoutingContext,
106
126
  DiscoveryFailure,
107
127
  resolveAgentForStep,
128
+ routedAgentOptions,
129
+ hasAnyRequiredTool,
130
+ normalizeAgentToolNames,
131
+ resolveTaskName,
108
132
  RoutingError
109
133
  } from "./agent-routing.mjs";
110
- import { DETAILED_SKIP_TO_CANONICAL, KNOWN_REQUIREMENTS } from "./types.mjs";
134
+ import { DETAILED_SKIP_TO_CANONICAL, KNOWN_REQUIREMENTS, MCP_SESSION_PROBE_TASK } from "./types.mjs";
111
135
  import {
112
136
  resolveAssertions,
113
137
  stepDisablesAssertion,
@@ -179,11 +203,26 @@ const DETAILED_SKIP_DETAILS = {
179
203
  rate_abuse_opt_out: "Rate-abuse vector was excluded by request_signing.skipRateAbuse.",
180
204
  capability_profile_mismatch: "Vector is outside the agent capability profile selected for this run.",
181
205
  transport_ungradable: "Vector cannot be graded faithfully by the selected transport.",
206
+ signing_transport_unavailable: "Request-signing vectors have no shape this run's protocol can carry, so no verifier behavior was graded.",
182
207
  rate_limit_not_triggered: "No RATE_LIMITED response was observed within the configured max_attempts."
183
208
  };
184
209
  const CANONICAL_SKIP_DETAILS = {
185
- rate_limit_not_triggered: "rate_limit_not_triggered"
210
+ rate_limit_not_triggered: "rate_limit_not_triggered",
211
+ // Same shape as `rate_limit_not_triggered` above, which
212
+ // runner-output-contract.yaml registers under
213
+ // `canonical_detail_sub_reasons.not_applicable` with a test-kit
214
+ // `spec_source`: emit the sub-reason token *exactly* as `skip.detail`,
215
+ // with empty validations and no pass/fail counter movement. The
216
+ // operator-facing remedy travels on the probe result (`response.error`),
217
+ // which is where the renderers read it.
218
+ //
219
+ // Upstream ask, tracked as the remaining external blocker: register
220
+ // `not_applicable.signing_transport_unavailable` with
221
+ // `spec_source: test-kits/signed-requests-runner.yaml`. Emitting the
222
+ // registered *shape* now means that registration changes nothing here.
223
+ signing_transport_unavailable: "signing_transport_unavailable"
186
224
  };
225
+ const MCP_SESSION_PROBE_REQUEST_TIMEOUT_MS = 5e3;
187
226
  const REPLAY_WEBHOOK_VECTOR_TASK = "replay_webhook_vector";
188
227
  const REPLAY_TRUSTED_MATCH_CONTEXT_VECTOR_TASK = "replay_trusted_match_context_vector";
189
228
  const WEBHOOK_REPLAY_DEFAULT_TIMEOUT_MS = 1e4;
@@ -526,6 +565,42 @@ function resetClientSessions(clients) {
526
565
  if (typeof reset === "function") reset.call(client);
527
566
  }
528
567
  }
568
+ async function resetControllerState(client, storyboard, options) {
569
+ const controller = options._controllerCapabilities;
570
+ if (controller?.detected !== true || !controller.scenarios.includes("reset_state")) return void 0;
571
+ const outcome = await runStep(
572
+ "Reset test-controller state",
573
+ "comply_test_controller",
574
+ () => callControllerRaw(
575
+ client,
576
+ {
577
+ scenario: "reset_state",
578
+ context: { correlation_id: `${storyboard.id}--__reset_state__` }
579
+ },
580
+ options
581
+ )
582
+ );
583
+ if (!outcome.step.passed) return outcome.step;
584
+ const raw = outcome.result;
585
+ const data = raw?.data;
586
+ if (raw?.success && data?.success === true) return void 0;
587
+ if (raw?.success && data?.success === false && data.error === "UNKNOWN_SCENARIO") return void 0;
588
+ return {
589
+ ...outcome.step,
590
+ passed: false,
591
+ error: data?.error_detail ?? data?.error ?? raw?.error ?? "comply_test_controller reset_state failed"
592
+ };
593
+ }
594
+ async function resetControllerStates(targets, storyboard) {
595
+ const seen = /* @__PURE__ */ new Set();
596
+ for (const target of targets) {
597
+ if (seen.has(target.client)) continue;
598
+ seen.add(target.client);
599
+ const failure = await resetControllerState(target.client, storyboard, target.options);
600
+ if (failure) return failure;
601
+ }
602
+ return void 0;
603
+ }
529
604
  function isPollEligibleEnvelope(data) {
530
605
  if (data == null || typeof data !== "object") return false;
531
606
  const obj = data;
@@ -645,6 +720,15 @@ function __redactSecretsForTest(value) {
645
720
  function __filterResponseHeadersForTest(headers) {
646
721
  return filterResponseHeaders(headers);
647
722
  }
723
+ function __selectProtectedToolTargetForTest(tools) {
724
+ return selectProtectedToolTarget(tools);
725
+ }
726
+ function __protectedToolCandidatesForTest(tools) {
727
+ return protectedToolCandidates(tools);
728
+ }
729
+ function __sessionControlCredentialsForTest(mechanism, options, client, agentUrl) {
730
+ return sessionControlCredentials(mechanism, options, client, agentUrl);
731
+ }
648
732
  function __defaultAuthHeadersForRawProbeForTest(options) {
649
733
  return defaultAuthHeadersForRawProbe(options);
650
734
  }
@@ -711,7 +795,7 @@ async function runStoryboardBody(agentUrlOrUrls, storyboard, options) {
711
795
  );
712
796
  }
713
797
  const hasCapabilityGate = storyboardCapabilityPredicates(storyboard).length > 0;
714
- const deferCapabilityAndRequires = hasCapabilityGate && options._profile === void 0;
798
+ const deferCapabilityAndRequires = options.agents !== void 0 || hasCapabilityGate && options._profile === void 0;
715
799
  if (hasCapabilityGate && !deferCapabilityAndRequires) {
716
800
  const unmetDetail = evaluateStoryboardCapabilityGates(
717
801
  storyboard,
@@ -728,8 +812,25 @@ async function runStoryboardBody(agentUrlOrUrls, storyboard, options) {
728
812
  }
729
813
  }
730
814
  const allRequires = resolveStoryboardRequires(storyboard, options);
731
- if (allRequires.length && !deferCapabilityAndRequires) {
732
- const requirementCheck = await checkRequires(allRequires, storyboard, options, options._profile);
815
+ const preflightDefersRequirement = (requirement) => {
816
+ switch (requirement) {
817
+ case "controller":
818
+ return options.agents !== void 0 || !options.agentTools;
819
+ case "request_signer":
820
+ return options.agents !== void 0 || !options._profile?.raw_capabilities;
821
+ default:
822
+ return false;
823
+ }
824
+ };
825
+ const firstDeferred = allRequires.findIndex(preflightDefersRequirement);
826
+ const earlyRequires = hasCapabilityGate ? [] : allRequires.slice(0, firstDeferred < 0 ? void 0 : firstDeferred);
827
+ if (earlyRequires.length && (!deferCapabilityAndRequires || options.agents && !hasCapabilityGate)) {
828
+ const requirementCheck = await checkRequires(
829
+ earlyRequires,
830
+ storyboard,
831
+ options,
832
+ options.agents ? void 0 : options._profile
833
+ );
733
834
  if ("requirement" in requirementCheck) {
734
835
  const resultAgentUrls = options.agents ? Object.values(options.agents).map((e) => e.url) : agentUrls;
735
836
  return {
@@ -998,20 +1099,7 @@ function buildRequiredAnyOfToolsMissingResult(agentUrls, storyboard, detail) {
998
1099
  notices: []
999
1100
  };
1000
1101
  }
1001
- function normalizeAgentToolNames(tools) {
1002
- if (!Array.isArray(tools)) return void 0;
1003
- const names = [];
1004
- for (const tool of tools) {
1005
- if (typeof tool === "string") {
1006
- names.push(tool);
1007
- } else if (tool && typeof tool === "object") {
1008
- const name = tool.name;
1009
- if (typeof name === "string") names.push(name);
1010
- }
1011
- }
1012
- return names.length > 0 ? names : void 0;
1013
- }
1014
- async function checkRequires(requires, storyboard, options, profile) {
1102
+ async function checkRequires(requires, storyboard, options, profile, precomputed) {
1015
1103
  let preparedPublisherAuthProbes = getPreparedTrustedMatchPublisherAuth(options);
1016
1104
  for (const requirement of requires) {
1017
1105
  if (!isKnownRequirement(requirement)) {
@@ -1020,6 +1108,13 @@ async function checkRequires(requires, storyboard, options, profile) {
1020
1108
  detail: `Storyboard requires unknown runtime requirement '${requirement}'. This SDK does not know how to satisfy it, so the requirement is treated as unmet for forward compatibility.`
1021
1109
  };
1022
1110
  }
1111
+ const established = precomputed?.get(requirement);
1112
+ if (established) {
1113
+ if (established.status === "unmet") {
1114
+ return { requirement: established.requirement, detail: established.detail };
1115
+ }
1116
+ continue;
1117
+ }
1023
1118
  switch (requirement) {
1024
1119
  case "controller": {
1025
1120
  if (!options.agentTools) continue;
@@ -1181,6 +1276,28 @@ function detectImplicitRequires(storyboard, options = {}) {
1181
1276
  if (needsSigner) requires.push("request_signer");
1182
1277
  return requires;
1183
1278
  }
1279
+ function probeResponseStatus(response) {
1280
+ if (response === null || typeof response !== "object") return 0;
1281
+ const status = response.status;
1282
+ return typeof status === "number" ? status : 0;
1283
+ }
1284
+ function signingCoverage(steps) {
1285
+ const probes = steps.filter((step) => step.task === REQUEST_SIGNING_PROBE_TASK);
1286
+ if (probes.length === 0) return "not_probed";
1287
+ if (probes.some((step) => step.skipped !== true && probeResponseStatus(step.response) > 0 && !isProbeFault(step.response)))
1288
+ return "graded";
1289
+ if (probes.some((step) => isProbeFault(step.response))) return "probe_errored";
1290
+ if (probes.some((step) => step.skip_reason === "signing_transport_unavailable")) return "transport_unverified";
1291
+ if (probes.every((step) => step.skipped === true)) return "scope_excluded";
1292
+ return "self_check_only";
1293
+ }
1294
+ function isProbeFault(response) {
1295
+ return response !== null && typeof response === "object" && response.probe_error === true;
1296
+ }
1297
+ function signingCoverageUnverified(steps) {
1298
+ const coverage = signingCoverage(steps);
1299
+ return coverage !== "not_probed" && coverage !== "graded";
1300
+ }
1184
1301
  function buildDiscoveryFailedResult(agentUrls, storyboard, discoveryStep) {
1185
1302
  const detail = discoveryStep.error ?? "Discovery failed (no agent tools advertised).";
1186
1303
  const syntheticStep = {
@@ -1400,7 +1517,7 @@ async function executeStoryboardPass(agentUrls, storyboard, options, dispatchOff
1400
1517
  try {
1401
1518
  routingContext = await buildRoutingContext(storyboard, options);
1402
1519
  } catch (err) {
1403
- const detail = err?.message ?? String(err);
1520
+ const detail = redactOAuthUrlsInText(err?.message ?? String(err));
1404
1521
  const failedStep = {
1405
1522
  step: err instanceof DiscoveryFailure ? `Discover agent capabilities (${err.agentKey})` : "Build agent routing index",
1406
1523
  passed: false,
@@ -1417,11 +1534,7 @@ async function executeStoryboardPass(agentUrls, storyboard, options, dispatchOff
1417
1534
  for (const p of routingContext.profiles.values()) {
1418
1535
  for (const t of normalizeAgentToolNames(p.tools) ?? []) unionedTools.add(t);
1419
1536
  }
1420
- if (!options.agentTools) {
1421
- options = { ...options, agentTools: [...unionedTools], _profile: profile };
1422
- } else if (profile && !options._profile) {
1423
- options = { ...options, _profile: profile };
1424
- }
1537
+ options = { ...options, agentTools: [...unionedTools], _profile: profile };
1425
1538
  } else {
1426
1539
  const clientResolutions = agentUrls.map((url) => getOrCreateClientResolution(url, options));
1427
1540
  clients = clientResolutions.map((r) => r.client);
@@ -1460,9 +1573,126 @@ async function executeStoryboardPass(agentUrls, storyboard, options, dispatchOff
1460
1573
  }
1461
1574
  }
1462
1575
  }
1576
+ if (preSeeded === void 0) {
1577
+ const resetTargets = routingContext && options.agents ? [...routingContext.profiles.entries()].map(([key, profile2]) => ({
1578
+ client: routingContext.clients.get(key),
1579
+ options: routedAgentOptions(options.agents[key], options, profile2)
1580
+ })) : clients.map((client) => ({ client, options }));
1581
+ const resetFailure = await resetControllerStates(resetTargets, storyboard);
1582
+ if (resetFailure) {
1583
+ if (!callerOwnsClients) await closeScopedConnections(options.protocol);
1584
+ return buildDiscoveryFailedResult(agentUrls, storyboard, resetFailure);
1585
+ }
1586
+ }
1587
+ const allRequires = resolveStoryboardRequires(storyboard, options);
1588
+ let dispatch = routingContext && options.agents ? createRoutingDispatcher(routingContext, options, options.agents) : createDispatcher(agentUrls, clients, "round-robin", dispatchOffset, profile);
1589
+ const routedStepCapabilitySkips = /* @__PURE__ */ new Map();
1590
+ const routedPhaseCapabilitySkips = /* @__PURE__ */ new Map();
1591
+ const routedStepRequirements = /* @__PURE__ */ new Map();
1592
+ const routedRootCapabilitySkips = [];
1593
+ const routedRootRequirementSkips = [];
1594
+ const routedControllerRoutes = /* @__PURE__ */ new Map();
1595
+ const routedErrors = /* @__PURE__ */ new Map();
1596
+ const reportedRoutingErrors = /* @__PURE__ */ new Set();
1597
+ let context = { ...storyboard.context, ...options.context };
1598
+ const routingFailedStep = (step, phaseId, err) => {
1599
+ const detail = redactOAuthUrlsInText(
1600
+ err instanceof RoutingError ? err.message : err?.message ?? String(err)
1601
+ );
1602
+ const failedAgentKey = step.agent ?? options.default_agent;
1603
+ const failedAgentUrl = failedAgentKey ? options.agents?.[failedAgentKey]?.url : void 0;
1604
+ const failedAgentIndex = failedAgentKey ? Object.keys(options.agents ?? {}).indexOf(failedAgentKey) : -1;
1605
+ return {
1606
+ storyboard_id: storyboard.id,
1607
+ step_id: step.id,
1608
+ phase_id: phaseId,
1609
+ title: step.title,
1610
+ task: step.task,
1611
+ passed: false,
1612
+ duration_ms: 0,
1613
+ validations: [],
1614
+ context,
1615
+ error: detail,
1616
+ ...failedAgentUrl && { agent_url: redactOAuthUrlForOutput(failedAgentUrl) },
1617
+ ...failedAgentIndex >= 0 && { agent_index: failedAgentIndex + 1 },
1618
+ extraction: { path: "none" }
1619
+ };
1620
+ };
1621
+ if (routingContext) {
1622
+ for (const phase of storyboard.phases) {
1623
+ for (const step of phase.steps) {
1624
+ if (step.task === VALIDATION_ONLY_TASK) continue;
1625
+ try {
1626
+ const selected = dispatch.nextFor(step);
1627
+ const selectedOptions = selected.options;
1628
+ const rootDetail = evaluateStoryboardCapabilityGates(
1629
+ storyboard,
1630
+ selected.profile,
1631
+ selectedOptions.agentTools,
1632
+ options.adcpVersion
1633
+ );
1634
+ let requirementSkip;
1635
+ if (rootDetail === null && allRequires.includes("request_signer")) {
1636
+ const requirement = await checkRequires(["request_signer"], storyboard, selectedOptions, {
1637
+ ...selected.profile,
1638
+ // Routed discovery is authoritative. A legacy agent without a
1639
+ // capabilities response did not opt into request signing.
1640
+ raw_capabilities: selected.profile.raw_capabilities ?? {}
1641
+ });
1642
+ if ("requirement" in requirement) {
1643
+ requirementSkip = requirement;
1644
+ routedStepRequirements.set(step, requirement.requirement);
1645
+ }
1646
+ }
1647
+ const phaseDetail = phase.requires_capability ? evaluateRequiresCapabilityGate(
1648
+ phase.requires_capability,
1649
+ selected.profile,
1650
+ selectedOptions.agentTools,
1651
+ options.adcpVersion
1652
+ ) : null;
1653
+ if (allRequires.includes("controller") && rootDetail === null && phaseDetail === null) {
1654
+ const routeKey = selected.agentKey ?? selected.agentUrl;
1655
+ const routeTools = selectedOptions.agentTools ?? [];
1656
+ const resolvedTask = resolveTaskName(step, selectedOptions) ?? step.task;
1657
+ const previous = routedControllerRoutes.get(routeKey);
1658
+ routedControllerRoutes.set(routeKey, {
1659
+ tools: routeTools,
1660
+ // A `comply_test_controller` step is the back-channel itself,
1661
+ // not the state under test, so it cannot vouch for the route it
1662
+ // is dispatched to. One state-exercising step is enough to mark
1663
+ // the route, whatever order the steps arrive in.
1664
+ stateExercising: (previous?.stateExercising ?? false) || resolvedTask !== "comply_test_controller"
1665
+ });
1666
+ }
1667
+ if (rootDetail !== null) routedRootCapabilitySkips.push(rootDetail);
1668
+ else if (requirementSkip) routedRootRequirementSkips.push(requirementSkip);
1669
+ const detail = rootDetail ?? requirementSkip?.detail ?? phaseDetail;
1670
+ if (detail !== null) routedStepCapabilitySkips.set(step, detail);
1671
+ } catch (error) {
1672
+ routedErrors.set(step, error);
1673
+ }
1674
+ }
1675
+ const callableSteps = phase.steps.filter((step) => step.task !== VALIDATION_ONLY_TASK);
1676
+ if (callableSteps.length && callableSteps.every((step) => routedStepCapabilitySkips.has(step))) {
1677
+ routedPhaseCapabilitySkips.set(phase.id, routedStepCapabilitySkips.get(callableSteps[0]));
1678
+ }
1679
+ }
1680
+ }
1681
+ const routedPreflightAssignment = routingContext ? (step) => {
1682
+ if (routedStepCapabilitySkips.has(step)) return void 0;
1683
+ try {
1684
+ return dispatch.nextFor(step);
1685
+ } catch {
1686
+ return void 0;
1687
+ }
1688
+ } : void 0;
1463
1689
  const preflightNotices = collectCapabilityNotices(storyboard, options._profile);
1690
+ const callableStepCount = storyboard.phases.reduce(
1691
+ (n, phase) => n + phase.steps.filter((step) => step.task !== VALIDATION_ONLY_TASK).length,
1692
+ 0
1693
+ );
1464
1694
  if (storyboardCapabilityPredicates(storyboard).length > 0) {
1465
- const unmetDetail = evaluateStoryboardCapabilityGates(storyboard, profile, options.agentTools, options.adcpVersion);
1695
+ const unmetDetail = routingContext ? routedRootCapabilitySkips.length > 0 && routedRootCapabilitySkips.length === callableStepCount ? routedRootCapabilitySkips[0] : null : evaluateStoryboardCapabilityGates(storyboard, profile, options.agentTools, options.adcpVersion);
1466
1696
  if (unmetDetail !== null) {
1467
1697
  if (!callerOwnsClients) await closeScopedConnections(options.protocol);
1468
1698
  return {
@@ -1471,21 +1701,71 @@ async function executeStoryboardPass(agentUrls, storyboard, options, dispatchOff
1471
1701
  };
1472
1702
  }
1473
1703
  }
1474
- const allRequires = resolveStoryboardRequires(storyboard, options);
1704
+ const establishedRequirements = /* @__PURE__ */ new Map();
1705
+ if (routingContext && allRequires.includes("controller")) {
1706
+ const decided = [...routedControllerRoutes].filter(([, route]) => route.stateExercising);
1707
+ const routes = decided.length > 0 ? decided : [...routedControllerRoutes];
1708
+ if (routedErrors.size > 0 || routes.length === 0) {
1709
+ establishedRequirements.set("controller", { status: "unknown" });
1710
+ } else if (routes.some(([, route]) => route.tools.includes("comply_test_controller"))) {
1711
+ establishedRequirements.set("controller", { status: "met" });
1712
+ } else {
1713
+ const exercised = routes.map(([key]) => key);
1714
+ const exercisedKeys = new Set(exercised);
1715
+ const peersWithController = [...routingContext.profiles.entries()].filter(
1716
+ ([key, peer]) => !exercisedKeys.has(key) && normalizeAgentToolNames(peer.tools)?.includes("comply_test_controller")
1717
+ ).map(([key]) => key);
1718
+ establishedRequirements.set("controller", {
1719
+ status: "unmet",
1720
+ requirement: "controller",
1721
+ detail: `Storyboard requires 'controller'; no route serving this storyboard's steps advertises comply_test_controller. Route(s) exercised: [${exercised.join(", ")}]. ` + (peersWithController.length ? `Agent(s) [${peersWithController.join(", ")}] in this map do advertise it, but a peer route's controller cannot seed another route's state \u2014 a run-level tool union does not grant it. ` : "") + `Add comply_test_controller to the route that owns the state, or pin the seeding step to that route with 'agent:'.`
1722
+ });
1723
+ }
1724
+ }
1725
+ if (routingContext && allRequires.includes("request_signer")) {
1726
+ establishedRequirements.set(
1727
+ "request_signer",
1728
+ routedErrors.size === 0 && routedRootRequirementSkips.length > 0 && routedRootRequirementSkips.length === callableStepCount ? { status: "unmet", ...routedRootRequirementSkips[0] } : { status: "unknown" }
1729
+ );
1730
+ }
1475
1731
  if (allRequires.length) {
1476
- const requirementCheck = await checkRequires(allRequires, storyboard, options, profile);
1732
+ const requirementCheck = await checkRequires(
1733
+ allRequires,
1734
+ storyboard,
1735
+ options,
1736
+ routingContext ? void 0 : profile,
1737
+ establishedRequirements
1738
+ );
1477
1739
  if ("requirement" in requirementCheck) {
1478
1740
  if (!callerOwnsClients) await closeScopedConnections(options.protocol);
1479
- return {
1480
- ...buildRequirementUnmetResult(agentUrls, storyboard, requirementCheck.requirement, requirementCheck.detail),
1481
- notices: preflightNotices
1482
- };
1741
+ const result2 = buildRequirementUnmetResult(
1742
+ agentUrls,
1743
+ storyboard,
1744
+ requirementCheck.requirement,
1745
+ requirementCheck.detail
1746
+ );
1747
+ for (const phase of storyboard.phases) {
1748
+ const failures = phase.steps.filter((step) => routedErrors.has(step)).map((step) => routingFailedStep(step, phase.id, routedErrors.get(step)));
1749
+ if (failures.length) {
1750
+ result2.phases.push({
1751
+ phase_id: phase.id,
1752
+ phase_title: phase.title,
1753
+ passed: false,
1754
+ steps: failures,
1755
+ duration_ms: 0
1756
+ });
1757
+ result2.failed_count += failures.length;
1758
+ result2.overall_passed = false;
1759
+ }
1760
+ }
1761
+ return { ...result2, notices: preflightNotices };
1483
1762
  }
1484
1763
  if (requirementCheck.preparedPublisherAuthProbes) {
1485
1764
  options = withPreparedTrustedMatchPublisherAuth(options, requirementCheck.preparedPublisherAuthProbes);
1765
+ if (routingContext && options.agents) dispatch = createRoutingDispatcher(routingContext, options, options.agents);
1486
1766
  }
1487
1767
  }
1488
- if (storyboard.required_any_of_tools?.length && options.agentTools) {
1768
+ if (storyboard.required_any_of_tools?.length && options.agentTools && !routingContext?.discoveryFailures.length && routedErrors.size === 0) {
1489
1769
  const agentTools = new Set(options.agentTools);
1490
1770
  const missing = storyboard.required_any_of_tools.find((family) => !family.tools.some((tool) => agentTools.has(tool)));
1491
1771
  if (missing) {
@@ -1497,8 +1777,8 @@ async function executeStoryboardPass(agentUrls, storyboard, options, dispatchOff
1497
1777
  };
1498
1778
  }
1499
1779
  }
1500
- if (storyboard.required_tools?.length && options.agentTools) {
1501
- const hasAnyRequired = storyboard.required_tools.some((t) => options.agentTools.includes(t));
1780
+ if (storyboard.required_tools?.length && options.agentTools && !routingContext?.discoveryFailures.length && routedErrors.size === 0) {
1781
+ const hasAnyRequired = hasAnyRequiredTool(storyboard.required_tools, options.agentTools);
1502
1782
  if (!hasAnyRequired) {
1503
1783
  if (!callerOwnsClients) await closeScopedConnections(options.protocol);
1504
1784
  return {
@@ -1511,18 +1791,26 @@ async function executeStoryboardPass(agentUrls, storyboard, options, dispatchOff
1511
1791
  };
1512
1792
  }
1513
1793
  }
1514
- let context = { ...storyboard.context, ...options.context };
1515
1794
  if (storyboard.context) forwardAliasCache(storyboard.context, context);
1516
1795
  if (options.context) forwardAliasCache(options.context, context);
1517
1796
  const contributions = /* @__PURE__ */ new Set();
1518
1797
  const contributionSources = /* @__PURE__ */ new Map();
1519
1798
  const priorStepResults = /* @__PURE__ */ new Map();
1520
1799
  const priorProbes = /* @__PURE__ */ new Map();
1800
+ const routedPriorProbes = /* @__PURE__ */ new Map();
1521
1801
  const contextProvenance = /* @__PURE__ */ new Map();
1522
1802
  const priorA2aEnvelopes = /* @__PURE__ */ new Map();
1523
1803
  const stepRequestStarts = /* @__PURE__ */ new Map();
1524
1804
  const responseDerivedNotApplicableContextKeys = /* @__PURE__ */ new Map();
1525
1805
  const capabilityUnavailableContextKeysByPhase = /* @__PURE__ */ new Map();
1806
+ const missingPrerequisiteContextKeysByPhase = /* @__PURE__ */ new Map();
1807
+ const recordUnavailableOutputs = (phaseId, step, keysByPhase = capabilityUnavailableContextKeysByPhase) => {
1808
+ const keys = keysByPhase.get(phaseId) ?? /* @__PURE__ */ new Set();
1809
+ for (const output of step.context_outputs ?? []) {
1810
+ if (output.key) keys.add(output.key);
1811
+ }
1812
+ keysByPhase.set(phaseId, keys);
1813
+ };
1526
1814
  const phaseResults = [];
1527
1815
  let passedCount = 0;
1528
1816
  let failedCount = 0;
@@ -1533,28 +1821,31 @@ async function executeStoryboardPass(agentUrls, storyboard, options, dispatchOff
1533
1821
  const branchSetsByPhaseId = resolveBranchSets(storyboard);
1534
1822
  const effectiveDependsOn = (phase, prior) => phase.depends_on ?? prior;
1535
1823
  const cascadeForPhase = (phase, prior) => {
1536
- if (phaseStatefulCascades.has(phase.id)) {
1537
- return { tripped: true, trigger: phaseStatefulCascades.get(phase.id) ?? null };
1538
- }
1539
1824
  const ownSpec = branchSetsByPhaseId.get(phase.id);
1540
1825
  const ownAnyOfBranchSet = ownSpec?.semantics === "any_of" ? ownSpec.id : void 0;
1541
- for (const depId of effectiveDependsOn(phase, prior)) {
1542
- if (ownAnyOfBranchSet !== void 0 && branchSetsByPhaseId.get(depId)?.id === ownAnyOfBranchSet) {
1826
+ let capabilityTrigger;
1827
+ let missingStateTrigger;
1828
+ for (const depId of [phase.id, ...effectiveDependsOn(phase, prior)]) {
1829
+ if (depId !== phase.id && ownAnyOfBranchSet !== void 0 && branchSetsByPhaseId.get(depId)?.id === ownAnyOfBranchSet) {
1543
1830
  continue;
1544
1831
  }
1545
1832
  if (phaseStatefulCascades.has(depId)) {
1546
- return { tripped: true, trigger: phaseStatefulCascades.get(depId) ?? null };
1833
+ const trigger2 = phaseStatefulCascades.get(depId) ?? null;
1834
+ if (trigger2 === null) return { tripped: true, trigger: null };
1835
+ if (trigger2.capabilityUnavailable) capabilityTrigger ??= trigger2;
1836
+ else missingStateTrigger ??= trigger2;
1547
1837
  }
1548
1838
  }
1549
- return { tripped: false };
1839
+ const trigger = missingStateTrigger ?? capabilityTrigger;
1840
+ return trigger ? { tripped: true, trigger } : { tripped: false };
1550
1841
  };
1551
- const capabilityUnavailableContextKeysForPhase = (phase, prior) => {
1552
- const keys = /* @__PURE__ */ new Set();
1842
+ const unavailableContextKeysForPhase = (phase, prior, keysByPhase = capabilityUnavailableContextKeysByPhase) => {
1843
+ const keys = new Set(keysByPhase.get(phase.id));
1553
1844
  const ownSpec = branchSetsByPhaseId.get(phase.id);
1554
1845
  const ownAnyOfBranchSet = ownSpec?.semantics === "any_of" ? ownSpec.id : void 0;
1555
1846
  for (const depId of effectiveDependsOn(phase, prior)) {
1556
1847
  if (ownAnyOfBranchSet !== void 0 && branchSetsByPhaseId.get(depId)?.id === ownAnyOfBranchSet) continue;
1557
- for (const key of capabilityUnavailableContextKeysByPhase.get(depId) ?? []) keys.add(key);
1848
+ for (const key of keysByPhase.get(depId) ?? []) keys.add(key);
1558
1849
  }
1559
1850
  return keys;
1560
1851
  };
@@ -1572,7 +1863,6 @@ async function executeStoryboardPass(agentUrls, storyboard, options, dispatchOff
1572
1863
  });
1573
1864
  if (webhookReceiver) armWebhookAssertions(storyboard, runnerVars, webhookReceiver);
1574
1865
  const allSteps = flattenSteps(storyboard);
1575
- const dispatch = routingContext && options.agents ? createRoutingDispatcher(routingContext, options, options.agents) : createDispatcher(agentUrls, clients, "round-robin", dispatchOffset, profile);
1576
1866
  const assertions = resolveAssertions(storyboard.invariants);
1577
1867
  validateStepInvariants(storyboard, assertions);
1578
1868
  const assertionContexts = /* @__PURE__ */ new Map();
@@ -1590,12 +1880,7 @@ async function executeStoryboardPass(agentUrls, storyboard, options, dispatchOff
1590
1880
  if (spec.onStart) await spec.onStart(assertionContexts.get(spec.id));
1591
1881
  }
1592
1882
  const hasExecutableSteps = storyboard.phases.some((p) => p.steps.length > 0);
1593
- const phaseCapabilitySkipDetails = collectPhaseCapabilitySkipDetails(
1594
- storyboard,
1595
- profile,
1596
- options.agentTools,
1597
- options.adcpVersion
1598
- );
1883
+ const phaseCapabilitySkipDetails = routingContext ? routedPhaseCapabilitySkips : collectPhaseCapabilitySkipDetails(storyboard, profile, options.agentTools, options.adcpVersion);
1599
1884
  const skipControllerSeedingForPhaseGates = allExecutablePhasesCapabilitySkipped(
1600
1885
  storyboard,
1601
1886
  phaseCapabilitySkipDetails
@@ -1626,7 +1911,8 @@ async function executeStoryboardPass(agentUrls, storyboard, options, dispatchOff
1626
1911
  storyboardRequiresRequestSigner: allRequires.includes("request_signer"),
1627
1912
  storyboardRequiresPublisherAuthRunner: storyboard.requires?.includes("trusted_match_publisher_auth_runner") === true
1628
1913
  },
1629
- preflightExcludedPhaseIds
1914
+ preflightExcludedPhaseIds,
1915
+ routedPreflightAssignment
1630
1916
  );
1631
1917
  let creativeAssetFixtureGapRecorded = false;
1632
1918
  if (!hasExecutableSteps) {
@@ -1671,22 +1957,36 @@ async function executeStoryboardPass(agentUrls, storyboard, options, dispatchOff
1671
1957
  let fixtureResolutionRecords;
1672
1958
  let fixtureCoverageGap;
1673
1959
  {
1674
- let fixtureSeedClient = clients[0];
1675
- let fixtureDiscoveryClient = clients[0];
1676
- if (routingContext && options.agents) {
1677
- const fixtureStep = (task) => ({
1678
- id: `__fixture_resolution_${task}__`,
1679
- title: `Fixture resolution via ${task}`,
1680
- task
1960
+ let seeding;
1961
+ try {
1962
+ seeding = creativeAssetFixtureGap || skipControllerSeedingForPhaseGates ? null : preSeeded !== void 0 ? preSeeded.result : await runControllerSeeding(
1963
+ clients[0],
1964
+ storyboard,
1965
+ options,
1966
+ context,
1967
+ clients[0],
1968
+ routingContext ? (task) => {
1969
+ if (!options.agentTools?.includes(task))
1970
+ return { client: clients[0], options: { ...options, agentTools: [] } };
1971
+ const selected = dispatch.nextFor({
1972
+ id: `__fixture_resolution_${task}__`,
1973
+ title: `Fixture resolution via ${task}`,
1974
+ task
1975
+ });
1976
+ return { client: selected.client, options: selected.options };
1977
+ } : void 0
1978
+ );
1979
+ } catch (error) {
1980
+ if (webhookReceiver) await webhookReceiver.close();
1981
+ if (!(error instanceof RoutingError)) throw error;
1982
+ if (!callerOwnsClients) await closeScopedConnections(options.protocol);
1983
+ return buildDiscoveryFailedResult(agentUrls, storyboard, {
1984
+ step: "Resolve fixture agent routes",
1985
+ passed: false,
1986
+ duration_ms: 0,
1987
+ error: redactOAuthUrlsInText(error.message)
1681
1988
  });
1682
- if (options.agentTools?.includes("comply_test_controller")) {
1683
- fixtureSeedClient = dispatch.nextFor(fixtureStep("comply_test_controller")).client;
1684
- }
1685
- if (options.agentTools?.includes("get_products")) {
1686
- fixtureDiscoveryClient = dispatch.nextFor(fixtureStep("get_products")).client;
1687
- }
1688
1989
  }
1689
- const seeding = creativeAssetFixtureGap ? null : skipControllerSeedingForPhaseGates ? null : preSeeded !== void 0 ? preSeeded.result : await runControllerSeeding(fixtureSeedClient, storyboard, options, context, fixtureDiscoveryClient);
1690
1990
  if (seeding) {
1691
1991
  const attach = preSeeded === void 0 || preSeeded.attach;
1692
1992
  if (attach) {
@@ -1758,7 +2058,8 @@ async function executeStoryboardPass(agentUrls, storyboard, options, dispatchOff
1758
2058
  context,
1759
2059
  options,
1760
2060
  buildExecutionState(),
1761
- preflightExcludedPhaseIds
2061
+ preflightExcludedPhaseIds,
2062
+ routedPreflightAssignment
1762
2063
  );
1763
2064
  }
1764
2065
  for (const phase of storyboard.phases) {
@@ -1803,7 +2104,25 @@ async function executeStoryboardPass(agentUrls, storyboard, options, dispatchOff
1803
2104
  }
1804
2105
  const phaseCapabilitySkipDetail = phaseCapabilitySkipDetails.get(phase.id);
1805
2106
  if (phaseCapabilitySkipDetail !== void 0) {
1806
- const skippedSteps = buildPhaseCapabilitySkippedSteps(storyboard, phase, phaseCapabilitySkipDetail, context);
2107
+ const skippedSteps = routingContext ? phase.steps.map((step) => {
2108
+ const selected = step.task === VALIDATION_ONLY_TASK ? void 0 : dispatch.nextFor(step);
2109
+ const skipped = buildPhaseCapabilitySkippedSteps(
2110
+ storyboard,
2111
+ { ...phase, steps: [step] },
2112
+ routedStepCapabilitySkips.get(step) ?? phaseCapabilitySkipDetail,
2113
+ context
2114
+ )[0];
2115
+ return {
2116
+ ...skipped,
2117
+ ...routedStepRequirements.has(step) && {
2118
+ skip: { ...skipped.skip, requirement: routedStepRequirements.get(step) }
2119
+ },
2120
+ ...selected && {
2121
+ agent_url: redactOAuthUrlForOutput(selected.agentUrl),
2122
+ agent_index: selected.instanceIndex + 1
2123
+ }
2124
+ };
2125
+ }) : buildPhaseCapabilitySkippedSteps(storyboard, phase, phaseCapabilitySkipDetail, context);
1807
2126
  phaseResults.push({
1808
2127
  phase_id: phase.id,
1809
2128
  phase_title: phase.title,
@@ -1813,13 +2132,9 @@ async function executeStoryboardPass(agentUrls, storyboard, options, dispatchOff
1813
2132
  });
1814
2133
  skippedCount += skippedSteps.length;
1815
2134
  phaseCapabilitySkippedIds.add(phase.id);
1816
- const unavailableKeys = /* @__PURE__ */ new Set();
1817
2135
  for (const step of phase.steps) {
1818
- for (const output of step.context_outputs ?? []) {
1819
- if (output.key) unavailableKeys.add(output.key);
1820
- }
2136
+ recordUnavailableOutputs(phase.id, step);
1821
2137
  }
1822
- capabilityUnavailableContextKeysByPhase.set(phase.id, unavailableKeys);
1823
2138
  if (phase.steps.some((s) => s.stateful)) {
1824
2139
  phaseStatefulCascades.set(phase.id, {
1825
2140
  stepId: phase.steps.find((s) => s.stateful).id,
@@ -1833,6 +2148,7 @@ async function executeStoryboardPass(agentUrls, storyboard, options, dispatchOff
1833
2148
  const stepResults = [];
1834
2149
  let phasePassed = true;
1835
2150
  let phasePendingNotApplicable = null;
2151
+ let phaseInheritedCapabilityTrigger;
1836
2152
  let phaseEstablishedStatefulState = false;
1837
2153
  const phaseSubstitutes = /* @__PURE__ */ new Map();
1838
2154
  for (const declaringStep of phase.steps) {
@@ -1845,13 +2161,27 @@ async function executeStoryboardPass(agentUrls, storyboard, options, dispatchOff
1845
2161
  phaseSubstitutes.set(target, arr);
1846
2162
  }
1847
2163
  }
1848
- let phasePendingMissingTool = null;
2164
+ const phasePendingMissingTool = { trigger: null };
1849
2165
  const phaseRescuedTargets = /* @__PURE__ */ new Set();
1850
2166
  const phaseRescueSource = /* @__PURE__ */ new Map();
1851
2167
  const phaseStatefulStepIds = phase.steps.filter((s) => s.stateful).map((s) => s.id);
1852
2168
  let phaseAbsent = false;
2169
+ const routedOauthAbsent = /* @__PURE__ */ new Set();
1853
2170
  let presenceDetected = false;
2171
+ const routedOauthPresent = /* @__PURE__ */ new Set();
1854
2172
  if (shouldSkipPhase(phase, options, context)) {
2173
+ const skippedRoutingFailures = routingContext ? phase.steps.filter((step) => routedErrors.has(step)) : [];
2174
+ const skippedCapabilitySteps = routingContext ? phase.steps.filter((step) => routedStepCapabilitySkips.has(step)) : [];
2175
+ for (const step of skippedCapabilitySteps) recordUnavailableOutputs(phase.id, step);
2176
+ if (skippedRoutingFailures.length > 0) {
2177
+ for (const step of skippedRoutingFailures) {
2178
+ recordUnavailableOutputs(phase.id, step, missingPrerequisiteContextKeysByPhase);
2179
+ }
2180
+ if (skippedRoutingFailures.some((step) => step.stateful)) phaseStatefulCascades.set(phase.id, null);
2181
+ }
2182
+ if (skippedRoutingFailures.length > 0 || skippedCapabilitySteps.length > 0) {
2183
+ priorPhaseIds.push(phase.id);
2184
+ }
1855
2185
  phaseResults.push({
1856
2186
  phase_id: phase.id,
1857
2187
  phase_title: phase.title,
@@ -1871,7 +2201,8 @@ async function executeStoryboardPass(agentUrls, storyboard, options, dispatchOff
1871
2201
  context,
1872
2202
  options,
1873
2203
  buildExecutionState(),
1874
- preflightExcludedPhaseIds
2204
+ preflightExcludedPhaseIds,
2205
+ routedPreflightAssignment
1875
2206
  );
1876
2207
  if (creativeAssetFixtureGap?.target.phaseId === phase.id) {
1877
2208
  const gapStep = buildCreativeAssetFixtureUnavailableStep(
@@ -1897,7 +2228,7 @@ async function executeStoryboardPass(agentUrls, storyboard, options, dispatchOff
1897
2228
  continue;
1898
2229
  }
1899
2230
  }
1900
- if (!phaseAbsent && phaseContainsOauthMetadataProbe(phase) && !agentAdvertisesOauth(profile)) {
2231
+ if (!routingContext && phaseContainsOauthMetadataProbe(phase) && !agentAdvertisesOauth(profile)) {
1901
2232
  phaseAbsent = true;
1902
2233
  }
1903
2234
  context = { ...context };
@@ -1939,9 +2270,66 @@ async function executeStoryboardPass(agentUrls, storyboard, options, dispatchOff
1939
2270
  skippedCount += cascadeSteps.length;
1940
2271
  continue;
1941
2272
  }
2273
+ const recordHardPrerequisiteFailure = (step, realFailure = false) => {
2274
+ if (realFailure) {
2275
+ phaseStatefulCascades.set(phase.id, null);
2276
+ } else if (!phaseStatefulCascades.has(phase.id) || phaseStatefulCascades.get(phase.id)?.capabilityUnavailable === true) {
2277
+ phaseStatefulCascades.set(phase.id, { stepId: step.id, reason: "prerequisite_failed" });
2278
+ }
2279
+ };
2280
+ const recordHardMissingState = (step, result2) => {
2281
+ const substitutes = phaseSubstitutes.get(step.id);
2282
+ if (substitutes && substitutes.length > 0) {
2283
+ if (phasePendingMissingTool.trigger === null) {
2284
+ phasePendingMissingTool.trigger = {
2285
+ stepId: step.id,
2286
+ reason: result2.skip_reason ?? "missing_tool",
2287
+ substitutes
2288
+ };
2289
+ }
2290
+ } else {
2291
+ const hasStatefulPeers = phaseStatefulStepIds.length > 1;
2292
+ if (hasStatefulPeers && !phaseStatefulCascades.has(phase.id)) {
2293
+ phaseStatefulCascades.set(phase.id, {
2294
+ stepId: step.id,
2295
+ reason: result2.skip_reason ?? "missing_tool"
2296
+ });
2297
+ } else if (!hasStatefulPeers && result2.skip) {
2298
+ result2.skip = {
2299
+ ...result2.skip,
2300
+ detail: result2.skip.detail + soleStatefulExemptionDetail(phase.id)
2301
+ };
2302
+ }
2303
+ }
2304
+ };
1942
2305
  for (const step of phase.steps) {
1943
2306
  options.signal?.throwIfAborted();
1944
- if (phaseAbsent) {
2307
+ if (routingContext && step.task === VALIDATION_ONLY_TASK) {
2308
+ const result3 = validationOnlyCoverageGap(step, phase.id, context, allSteps, runnerVars, storyboard.id);
2309
+ stepResults.push(result3);
2310
+ priorStepResults.set(step.id, result3);
2311
+ skippedCount++;
2312
+ continue;
2313
+ }
2314
+ let assignment;
2315
+ try {
2316
+ if (routingContext) assignment = dispatch.nextFor(step);
2317
+ } catch (err) {
2318
+ const failed = routingFailedStep(step, phase.id, err);
2319
+ reportedRoutingErrors.add(step);
2320
+ stepResults.push(failed);
2321
+ countedAsFailed.add(failed);
2322
+ priorStepResults.set(step.id, failed);
2323
+ failedCount++;
2324
+ phasePassed = false;
2325
+ recordUnavailableOutputs(phase.id, step, missingPrerequisiteContextKeysByPhase);
2326
+ if (step.stateful) phaseStatefulCascades.set(phase.id, null);
2327
+ continue;
2328
+ }
2329
+ if (routingContext && assignment && phaseContainsOauthMetadataProbe(phase) && !agentAdvertisesOauth(assignment.profile)) {
2330
+ routedOauthAbsent.add(assignment.instanceIndex);
2331
+ }
2332
+ if ((phaseAbsent || assignment && routedOauthAbsent.has(assignment.instanceIndex)) && !routedStepCapabilitySkips.has(step)) {
1945
2333
  const cascadeResult = {
1946
2334
  storyboard_id: storyboard.id,
1947
2335
  step_id: step.id,
@@ -1962,21 +2350,25 @@ async function executeStoryboardPass(agentUrls, storyboard, options, dispatchOff
1962
2350
  skippedCount++;
1963
2351
  continue;
1964
2352
  }
2353
+ const selectedOptions = assignment?.options ?? options;
2354
+ const routedCapabilityDetail = routedStepCapabilitySkips.get(step);
1965
2355
  const cascade = step.stateful ? cascadeForPhase(phase, priorPhaseIds) : { tripped: false };
1966
- if (cascade.tripped && step.stateful) {
1967
- const resolvedTask = resolveTaskName(step, options);
1968
- if (options.agentTools && resolvedTask && !options.agentTools.includes(resolvedTask)) {
1969
- const toolDetail = `Agent did not advertise tool "${resolvedTask}"; agent tools: [${options.agentTools.join(", ")}].`;
2356
+ if (cascade.tripped && step.stateful && routedCapabilityDetail === void 0) {
2357
+ const resolvedTask = resolveTaskName(step, selectedOptions);
2358
+ const missingTool = selectedOptions.agentTools && (routingContext && step.requires_tool && !selectedOptions.agentTools.includes(step.requires_tool) ? step.requires_tool : resolvedTask && resolvedTask !== MCP_SESSION_PROBE_TASK && !selectedOptions.agentTools.includes(resolvedTask) ? resolvedTask : void 0);
2359
+ if (missingTool) {
2360
+ const missingReason = routingContext && missingTool === "comply_test_controller" ? "missing_test_controller" : "missing_tool";
2361
+ const toolDetail = `Agent did not advertise tool "${missingTool}"; agent tools: [${selectedOptions.agentTools.join(", ")}].`;
1970
2362
  const missingToolResult = {
1971
2363
  storyboard_id: storyboard.id,
1972
2364
  step_id: step.id,
1973
2365
  phase_id: phase.id,
1974
2366
  title: step.title,
1975
- task: resolvedTask,
2367
+ task: resolvedTask ?? step.task,
1976
2368
  passed: true,
1977
2369
  skipped: true,
1978
- skip_reason: "missing_tool",
1979
- skip: buildSkip("missing_tool", toolDetail),
2370
+ skip_reason: missingReason,
2371
+ skip: buildSkip(missingReason, toolDetail),
1980
2372
  duration_ms: 0,
1981
2373
  validations: [],
1982
2374
  context,
@@ -1984,12 +2376,42 @@ async function executeStoryboardPass(agentUrls, storyboard, options, dispatchOff
1984
2376
  };
1985
2377
  stepResults.push(missingToolResult);
1986
2378
  priorStepResults.set(step.id, missingToolResult);
2379
+ if (routingContext) {
2380
+ recordUnavailableOutputs(phase.id, step, missingPrerequisiteContextKeysByPhase);
2381
+ recordHardMissingState(step, missingToolResult);
2382
+ }
1987
2383
  skippedCount++;
1988
2384
  continue;
1989
2385
  }
1990
2386
  const trigger = cascade.trigger;
1991
- const detail = trigger ? trigger.substitution_chain ? `Skipped: prior stateful step "${trigger.stepId}" skipped (${trigger.reason}); ${trigger.substitution_chain}; state never materialized.` : `Skipped: prior stateful step "${trigger.stepId}" skipped (${trigger.reason}); state never materialized.` : "Skipped: prior stateful step failed.";
1992
- const capabilityUnavailable = trigger?.capabilityUnavailable === true;
2387
+ let detail = trigger ? trigger.substitution_chain ? `Skipped: prior stateful step "${trigger.stepId}" skipped (${trigger.reason}); ${trigger.substitution_chain}; state never materialized.` : `Skipped: prior stateful step "${trigger.stepId}" skipped (${trigger.reason}); state never materialized.` : "Skipped: prior stateful step failed.";
2388
+ let capabilityUnavailable = trigger?.capabilityUnavailable === true;
2389
+ if (capabilityUnavailable && routingContext && !TRUSTED_MATCH_PUBLISHER_AUTH_TASKS.has(step.task) && !PROBE_TASKS.has(step.task) && !WEBHOOK_ASSERTION_TASKS.has(step.task) && step.task !== REPLAY_WEBHOOK_VECTOR_TASK && (!step.requires_contract || (selectedOptions.contracts ?? []).includes(step.requires_contract))) {
2390
+ const hardKeys = unavailableContextKeysForPhase(phase, priorPhaseIds, missingPrerequisiteContextKeysByPhase);
2391
+ if (hardKeys.size > 0) {
2392
+ const effectiveRequest = buildEffectiveStepRequest(
2393
+ { ...step, task: resolvedTask ?? step.task },
2394
+ context,
2395
+ selectedOptions,
2396
+ buildExecutionState(assignment?.agentUrl, assignment?.profile)
2397
+ );
2398
+ const missingKeys = /* @__PURE__ */ new Set([
2399
+ ...(effectiveRequest.ok ? findUnresolvedContextVars(effectiveRequest.request) : []).filter((v) => hardKeys.has(v.key)).map((v) => v.key),
2400
+ ...(step.context_inputs ?? []).filter((input) => !(input.key in context) && hardKeys.has(input.key)).map((input) => input.key)
2401
+ ]);
2402
+ if (missingKeys.size > 0) {
2403
+ capabilityUnavailable = false;
2404
+ detail = `Skipped: context required from a failed or unavailable prerequisite is missing: ${[...missingKeys].join(", ")}.`;
2405
+ }
2406
+ }
2407
+ }
2408
+ if (capabilityUnavailable) {
2409
+ recordUnavailableOutputs(phase.id, step);
2410
+ if (routingContext) phaseInheritedCapabilityTrigger ??= trigger ?? void 0;
2411
+ } else if (routingContext) {
2412
+ recordUnavailableOutputs(phase.id, step, missingPrerequisiteContextKeysByPhase);
2413
+ recordHardPrerequisiteFailure(step, trigger === null);
2414
+ }
1993
2415
  stepResults.push({
1994
2416
  storyboard_id: storyboard.id,
1995
2417
  step_id: step.id,
@@ -2017,46 +2439,47 @@ async function executeStoryboardPass(agentUrls, storyboard, options, dispatchOff
2017
2439
  skippedCount++;
2018
2440
  continue;
2019
2441
  }
2020
- let assignment;
2021
- try {
2022
- assignment = dispatch.nextFor(step);
2023
- } catch (err) {
2024
- const detail = err instanceof RoutingError ? err.message : err?.message ?? String(err);
2025
- const failed = {
2026
- storyboard_id: storyboard.id,
2027
- step_id: step.id,
2028
- phase_id: phase.id,
2029
- title: step.title,
2030
- task: step.task,
2031
- passed: false,
2032
- duration_ms: 0,
2033
- validations: [],
2034
- context,
2035
- error: detail,
2036
- extraction: { path: "none" }
2037
- };
2038
- stepResults.push(failed);
2039
- priorStepResults.set(step.id, failed);
2040
- failedCount++;
2041
- phasePassed = false;
2042
- continue;
2043
- }
2442
+ assignment ??= dispatch.nextFor(step);
2044
2443
  const stepExecutionState = buildExecutionState(assignment.agentUrl, assignment.profile);
2045
- stepExecutionState.capabilityUnavailableContextKeys = capabilityUnavailableContextKeysForPhase(
2046
- phase,
2047
- priorPhaseIds
2048
- );
2049
- const rawResult = await executeStep(
2444
+ if (routingContext) {
2445
+ let probes = routedPriorProbes.get(assignment.instanceIndex);
2446
+ if (!probes) {
2447
+ probes = /* @__PURE__ */ new Map();
2448
+ routedPriorProbes.set(assignment.instanceIndex, probes);
2449
+ }
2450
+ stepExecutionState.priorProbes = probes;
2451
+ stepExecutionState.allowPriorProbeFallback = false;
2452
+ }
2453
+ stepExecutionState.capabilityUnavailableContextKeys = unavailableContextKeysForPhase(phase, priorPhaseIds);
2454
+ if (routingContext) {
2455
+ stepExecutionState.missingPrerequisiteContextKeys = unavailableContextKeysForPhase(
2456
+ phase,
2457
+ priorPhaseIds,
2458
+ missingPrerequisiteContextKeysByPhase
2459
+ );
2460
+ }
2461
+ const rawResult = routedCapabilityDetail !== void 0 ? buildPhaseCapabilitySkippedSteps(
2462
+ storyboard,
2463
+ { ...phase, steps: [step] },
2464
+ routedCapabilityDetail,
2465
+ context
2466
+ )[0] : await executeStep(
2050
2467
  assignment.client,
2051
2468
  step,
2052
2469
  storyboard.id,
2053
2470
  phase.id,
2054
2471
  context,
2055
2472
  allSteps,
2056
- options,
2473
+ assignment.options ?? options,
2057
2474
  stepExecutionState
2058
2475
  );
2059
2476
  const result2 = { ...rawResult, storyboard_id: storyboard.id };
2477
+ if (routedCapabilityDetail !== void 0 || result2.skip_reason === "capability_prerequisite_unavailable") {
2478
+ recordUnavailableOutputs(phase.id, step);
2479
+ }
2480
+ if (routedCapabilityDetail !== void 0 && routedStepRequirements.has(step)) {
2481
+ result2.skip = { ...result2.skip, requirement: routedStepRequirements.get(step) };
2482
+ }
2060
2483
  if (isMultiInstance || useRouting) {
2061
2484
  result2.agent_url = redactOAuthUrlForOutput(assignment.agentUrl);
2062
2485
  result2.agent_index = assignment.instanceIndex + 1;
@@ -2102,11 +2525,13 @@ async function executeStoryboardPass(agentUrls, storyboard, options, dispatchOff
2102
2525
  }
2103
2526
  if (step.task === "protected_resource_metadata") {
2104
2527
  if (result2.skipped && result2.skip_reason === "oauth_not_advertised") {
2105
- phaseAbsent = true;
2528
+ if (routingContext) routedOauthAbsent.add(assignment.instanceIndex);
2529
+ else phaseAbsent = true;
2106
2530
  } else {
2107
2531
  const status = result2.response?.status;
2108
2532
  if (typeof status === "number" && status >= 200 && status < 300) {
2109
- presenceDetected = true;
2533
+ if (routingContext) routedOauthPresent.add(assignment.instanceIndex);
2534
+ else presenceDetected = true;
2110
2535
  }
2111
2536
  }
2112
2537
  }
@@ -2122,34 +2547,26 @@ async function executeStoryboardPass(agentUrls, storyboard, options, dispatchOff
2122
2547
  if (result2.skipped) {
2123
2548
  skippedCount++;
2124
2549
  context = result2.context;
2550
+ const hardPrerequisite = isHardMissingStateSkipReason(result2.skip_reason) || result2.skip_reason === "prerequisite_failed";
2551
+ if (result2.skip_reason === "prerequisite_failed" && !result2.passed) phasePassed = false;
2552
+ if (routingContext && hardPrerequisite) {
2553
+ recordUnavailableOutputs(phase.id, step, missingPrerequisiteContextKeysByPhase);
2554
+ if (!result2.passed) {
2555
+ phasePassed = false;
2556
+ if (step.stateful) recordHardPrerequisiteFailure(step);
2557
+ }
2558
+ }
2125
2559
  if (step.stateful) {
2126
2560
  if (isHardMissingStateSkipReason(result2.skip_reason)) {
2127
- const substitutes = phaseSubstitutes.get(step.id);
2128
- if (substitutes && substitutes.length > 0) {
2129
- if (phasePendingMissingTool === null) {
2130
- phasePendingMissingTool = {
2131
- stepId: step.id,
2132
- reason: result2.skip_reason ?? "missing_tool",
2133
- substitutes
2134
- };
2135
- }
2136
- } else {
2137
- const hasStatefulPeers = phaseStatefulStepIds.length > 1;
2138
- if (hasStatefulPeers && !phaseStatefulCascades.has(phase.id)) {
2139
- phaseStatefulCascades.set(phase.id, {
2140
- stepId: step.id,
2141
- reason: result2.skip_reason ?? "missing_tool"
2142
- });
2143
- } else if (!hasStatefulPeers && result2.skip) {
2144
- result2.skip = {
2145
- ...result2.skip,
2146
- detail: result2.skip.detail + soleStatefulExemptionDetail(phase.id)
2147
- };
2148
- }
2149
- }
2150
- } else if (result2.skip_reason === "not_applicable") {
2151
- if (phasePendingNotApplicable === null) {
2152
- phasePendingNotApplicable = { stepId: step.id, reason: "not_applicable" };
2561
+ recordHardMissingState(step, result2);
2562
+ } else if (result2.skip_reason === "not_applicable" || result2.skip_reason === "capability_prerequisite_unavailable") {
2563
+ const capabilityUnavailable = routedCapabilityDetail !== void 0 || result2.skip_reason === "capability_prerequisite_unavailable";
2564
+ if (phasePendingNotApplicable === null || phasePendingNotApplicable.capabilityUnavailable === true && !capabilityUnavailable) {
2565
+ phasePendingNotApplicable = {
2566
+ stepId: step.id,
2567
+ reason: result2.skip_reason,
2568
+ ...capabilityUnavailable ? { capabilityUnavailable: true } : {}
2569
+ };
2153
2570
  }
2154
2571
  }
2155
2572
  }
@@ -2171,7 +2588,7 @@ async function executeStoryboardPass(agentUrls, storyboard, options, dispatchOff
2171
2588
  }
2172
2589
  } else {
2173
2590
  phasePassed = false;
2174
- if (!phase.optional || presenceDetected) {
2591
+ if (!phase.optional || (routingContext ? routedOauthPresent.has(assignment.instanceIndex) : presenceDetected)) {
2175
2592
  failedCount++;
2176
2593
  countedAsFailed.add(result2);
2177
2594
  }
@@ -2193,7 +2610,8 @@ async function executeStoryboardPass(agentUrls, storyboard, options, dispatchOff
2193
2610
  context,
2194
2611
  options,
2195
2612
  stepExecutionState,
2196
- preflightExcludedPhaseIds
2613
+ preflightExcludedPhaseIds,
2614
+ routedPreflightAssignment
2197
2615
  );
2198
2616
  }
2199
2617
  if (creativeAssetFixtureGap) {
@@ -2216,6 +2634,15 @@ async function executeStoryboardPass(agentUrls, storyboard, options, dispatchOff
2216
2634
  }
2217
2635
  }
2218
2636
  }
2637
+ if (phasePendingMissingTool.trigger && !phaseRescuedTargets.has(phasePendingMissingTool.trigger.stepId) && !phaseStatefulCascades.has(phase.id)) {
2638
+ const subs = phasePendingMissingTool.trigger.substitutes;
2639
+ const subsList = subs.length === 1 ? `"${subs[0]}"` : subs.map((s) => `"${s}"`).join(", ");
2640
+ phaseStatefulCascades.set(phase.id, {
2641
+ stepId: phasePendingMissingTool.trigger.stepId,
2642
+ reason: phasePendingMissingTool.trigger.reason,
2643
+ substitution_chain: `declared substitute ${subsList} did not pass`
2644
+ });
2645
+ }
2219
2646
  if (phasePendingNotApplicable && !phaseEstablishedStatefulState && !phaseStatefulCascades.has(phase.id)) {
2220
2647
  const hadStatefulPeers = phaseStatefulStepIds.some((id) => id !== phasePendingNotApplicable.stepId);
2221
2648
  if (hadStatefulPeers) {
@@ -2230,14 +2657,8 @@ async function executeStoryboardPass(agentUrls, storyboard, options, dispatchOff
2230
2657
  }
2231
2658
  }
2232
2659
  }
2233
- if (phasePendingMissingTool && !phaseRescuedTargets.has(phasePendingMissingTool.stepId) && !phaseStatefulCascades.has(phase.id)) {
2234
- const subs = phasePendingMissingTool.substitutes;
2235
- const subsList = subs.length === 1 ? `"${subs[0]}"` : subs.map((s) => `"${s}"`).join(", ");
2236
- phaseStatefulCascades.set(phase.id, {
2237
- stepId: phasePendingMissingTool.stepId,
2238
- reason: phasePendingMissingTool.reason,
2239
- substitution_chain: `declared substitute ${subsList} did not pass`
2240
- });
2660
+ if (phaseInheritedCapabilityTrigger && !phaseStatefulCascades.has(phase.id)) {
2661
+ phaseStatefulCascades.set(phase.id, phaseInheritedCapabilityTrigger);
2241
2662
  }
2242
2663
  for (const target of phaseRescuedTargets) {
2243
2664
  const sourceId = phaseRescueSource.get(target);
@@ -2258,6 +2679,27 @@ async function executeStoryboardPass(agentUrls, storyboard, options, dispatchOff
2258
2679
  });
2259
2680
  priorPhaseIds.push(phase.id);
2260
2681
  }
2682
+ for (const phase of storyboard.phases) {
2683
+ const result2 = phaseResults.find((p) => p.phase_id === phase.id);
2684
+ for (const step of phase.steps) {
2685
+ if (!routedErrors.has(step) || reportedRoutingErrors.has(step)) continue;
2686
+ const failed = routingFailedStep(step, phase.id, routedErrors.get(step));
2687
+ const existingIndex = result2.steps.findIndex((row) => row.step_id === step.id);
2688
+ if (existingIndex >= 0) {
2689
+ const existing = result2.steps[existingIndex];
2690
+ if (existing.skipped) skippedCount--;
2691
+ if (countedAsFailed.delete(existing)) failedCount--;
2692
+ result2.steps[existingIndex] = failed;
2693
+ } else {
2694
+ result2.steps.push(failed);
2695
+ }
2696
+ reportedRoutingErrors.add(step);
2697
+ countedAsFailed.add(failed);
2698
+ result2.passed = false;
2699
+ priorStepResults.set(step.id, failed);
2700
+ failedCount++;
2701
+ }
2702
+ }
2261
2703
  const branchSetDelta = creativeAssetFixtureGap ? { skippedDelta: 0 } : applyBranchSetGrading(
2262
2704
  storyboard.phases,
2263
2705
  phaseResults,
@@ -2294,8 +2736,9 @@ async function executeStoryboardPass(agentUrls, storyboard, options, dispatchOff
2294
2736
  const phaseResult = phaseResults.find((p) => p.phase_id === phaseDef.id);
2295
2737
  return !!phaseResult && phaseResult.passed && phaseResult.steps.some((s) => !s.skipped && s.passed);
2296
2738
  });
2297
- const requiredPhasesPassed = !hasExecutableSteps || requiredPhaseHasExecutedPass || requiredPhasesNonFailingSkipped || failedCount === 0 && requiredPhasesCoveredByCapabilityGates;
2739
+ const requiredPhasesPassed = !hasExecutableSteps || requiredPhaseDefs.every((phaseDef) => phaseResults.find((p) => p.phase_id === phaseDef.id)?.passed === true) && (requiredPhaseHasExecutedPass || requiredPhasesNonFailingSkipped || failedCount === 0 && requiredPhasesCoveredByCapabilityGates);
2298
2740
  const storyboardWideFixtureUnavailable = (seedingUnsupported || fixtureUnsatisfied || creativeAssetFixtureGap !== void 0) && failedCount === 0;
2741
+ const hasUnverifiedCoverage = signingCoverageUnverified(phaseResults.flatMap((phase) => phase.steps));
2299
2742
  if (seedingPhaseResult) phaseResults.unshift(seedingPhaseResult);
2300
2743
  const schemasUsed = collectSchemasUsed(phaseResults);
2301
2744
  const strictSummary = summarizeStrictValidation(phaseResults);
@@ -2319,7 +2762,7 @@ async function executeStoryboardPass(agentUrls, storyboard, options, dispatchOff
2319
2762
  Object.entries(routingContext.agentMap).map(([specialism, url]) => [specialism, redactOAuthUrlForOutput(url)])
2320
2763
  )
2321
2764
  },
2322
- overall_passed: failedCount === 0 && (requiredPhasesPassed || storyboardWideFixtureUnavailable) && !assertionsFailed,
2765
+ overall_passed: failedCount === 0 && (requiredPhasesPassed || storyboardWideFixtureUnavailable) && !assertionsFailed && !hasUnverifiedCoverage,
2323
2766
  phases: phaseResults,
2324
2767
  context,
2325
2768
  total_duration_ms: Date.now() - start,
@@ -2372,6 +2815,14 @@ async function runMultiPass(agentUrls, storyboard, options) {
2372
2815
  ...options.agentTools ? {} : { agentTools: normalizeAgentToolNames(preSeedProfile.tools) }
2373
2816
  };
2374
2817
  }
2818
+ const resetFailure = await resetControllerStates(
2819
+ preSeedClients.map((client) => ({ client, options })),
2820
+ storyboard
2821
+ );
2822
+ if (resetFailure) {
2823
+ await closeScopedConnections(options.protocol);
2824
+ return buildDiscoveryFailedResult(agentUrls, storyboard, resetFailure);
2825
+ }
2375
2826
  if (storyboardCapabilityPredicates(storyboard).length > 0) {
2376
2827
  const unmetDetail = evaluateStoryboardCapabilityGates(
2377
2828
  storyboard,
@@ -2704,6 +3155,38 @@ async function runStoryboardStepBody(agentUrl, storyboard, stepId, options) {
2704
3155
  if (ownsWebhookReceiver && webhookReceiver) await webhookReceiver.close();
2705
3156
  return { ...result, contributions: Array.from(contributions) };
2706
3157
  }
3158
+ function unresolvedStepContextVars(step, request, context, runState) {
3159
+ const unavailableInputs = (step.context_inputs ?? []).filter(
3160
+ (input) => !(input.key in context) && (runState.capabilityUnavailableContextKeys?.has(input.key) === true || runState.missingPrerequisiteContextKeys?.has(input.key) === true)
3161
+ );
3162
+ return [
3163
+ ...findUnresolvedContextVars(request),
3164
+ ...unavailableInputs.map((input) => ({ key: input.key, token: `$context.${input.key}` }))
3165
+ ];
3166
+ }
3167
+ function buildStepRequest(step, effectiveStep, context, options, runnerVars) {
3168
+ let request;
3169
+ if (options.request) {
3170
+ request = injectContext({ ...options.request }, context, runnerVars);
3171
+ } else if (step.expect_error && step.sample_request) {
3172
+ request = injectContext({ ...step.sample_request }, context, runnerVars);
3173
+ } else if (hasRequestEnricher(effectiveStep.task)) {
3174
+ request = enrichRequest(effectiveStep, context, options, runnerVars);
3175
+ } else if (step.sample_request) {
3176
+ request = injectContext({ ...step.sample_request }, context, runnerVars);
3177
+ } else {
3178
+ request = {};
3179
+ }
3180
+ if (step.context_inputs?.length) {
3181
+ request = applyContextInputs(request, step.context_inputs, context);
3182
+ }
3183
+ request = applyBrandInvariant(request, options, effectiveStep.task, { omit_account: step.omit_account });
3184
+ if (options.disable_sandbox === true) {
3185
+ request = applyDisableSandboxHint(request, effectiveStep.task);
3186
+ }
3187
+ request = applyIdempotencyInvariant(request, effectiveStep.task, step);
3188
+ return request;
3189
+ }
2707
3190
  async function executeStep(client, step, storyboardId, phaseId, context, allSteps, options, state) {
2708
3191
  const runState = state ?? {
2709
3192
  contributions: /* @__PURE__ */ new Set(),
@@ -2807,6 +3290,9 @@ async function executeStep(client, step, storyboardId, phaseId, context, allStep
2807
3290
  extraction: { path: "none" }
2808
3291
  };
2809
3292
  }
3293
+ if (effectiveStep.task === MCP_SESSION_PROBE_TASK) {
3294
+ return executeProbeStep(client, effectiveStep, phaseId, context, allSteps, options, runState);
3295
+ }
2810
3296
  if (effectiveStep.task === "sync_accounts") {
2811
3297
  const rawCaps = options._profile?.raw_capabilities;
2812
3298
  if (rawCaps !== void 0) {
@@ -2852,47 +3338,7 @@ async function executeStep(client, step, storyboardId, phaseId, context, allStep
2852
3338
  extraction: { path: "none" }
2853
3339
  };
2854
3340
  }
2855
- let request;
2856
- if (options.request) {
2857
- request = injectContext({ ...options.request }, context, runState.runnerVars);
2858
- } else if (step.expect_error && step.sample_request) {
2859
- request = injectContext({ ...step.sample_request }, context, runState.runnerVars);
2860
- } else if (hasRequestEnricher(effectiveStep.task)) {
2861
- request = enrichRequest(effectiveStep, context, options, runState.runnerVars);
2862
- } else if (step.sample_request) {
2863
- request = injectContext({ ...step.sample_request }, context, runState.runnerVars);
2864
- } else {
2865
- request = {};
2866
- }
2867
- if (step.context_inputs?.length) {
2868
- request = applyContextInputs(request, step.context_inputs, context);
2869
- }
2870
- const unavailableContextInputs = (step.context_inputs ?? []).filter(
2871
- (input) => !(input.key in context) && runState.capabilityUnavailableContextKeys?.has(input.key) === true
2872
- );
2873
- if (unavailableContextInputs.length > 0) {
2874
- const detail = "Skipped: context required by a capability-gated phase is unavailable: " + unavailableContextInputs.map((input) => input.key).join(", ") + ".";
2875
- return {
2876
- step_id: step.id,
2877
- phase_id: phaseId,
2878
- title: step.title,
2879
- task: step.task,
2880
- passed: true,
2881
- skipped: true,
2882
- skip_reason: "capability_prerequisite_unavailable",
2883
- skip: buildSkip("not_applicable", detail),
2884
- duration_ms: 0,
2885
- validations: [],
2886
- context,
2887
- next: getNextStepPreview(step.id, allSteps, context, runState.runnerVars),
2888
- extraction: { path: "none" }
2889
- };
2890
- }
2891
- request = applyBrandInvariant(request, options, effectiveStep.task, { omit_account: step.omit_account });
2892
- if (options.disable_sandbox === true) {
2893
- request = applyDisableSandboxHint(request, effectiveStep.task);
2894
- }
2895
- request = applyIdempotencyInvariant(request, effectiveStep.task, step);
3341
+ let request = buildStepRequest(step, effectiveStep, context, options, runState.runnerVars);
2896
3342
  const fixtureBinding = applyFixtureBindingsSafely(request, effectiveStep.task, options, runState);
2897
3343
  if (!fixtureBinding.ok) {
2898
3344
  const next2 = getNextStepPreview(step.id, allSteps, context, runState.runnerVars);
@@ -2935,7 +3381,7 @@ async function executeStep(client, step, storyboardId, phaseId, context, allStep
2935
3381
  effectiveStep.task
2936
3382
  );
2937
3383
  }
2938
- const unresolvedContextVars = findUnresolvedContextVars(request);
3384
+ const unresolvedContextVars = unresolvedStepContextVars(step, request, context, runState);
2939
3385
  const unresolvedAssetDirectives = findUnresolvedCreativeAssetDirectives(request).map((path) => ({
2940
3386
  key: path,
2941
3387
  token: BUILD_ASSETS_FROM_FORMAT_DIRECTIVE
@@ -2944,11 +3390,14 @@ async function executeStep(client, step, storyboardId, phaseId, context, allStep
2944
3390
  const hasCapabilityUnavailableContext = unresolvedContextVars.some(
2945
3391
  (v) => runState.capabilityUnavailableContextKeys?.has(v.key) === true
2946
3392
  );
2947
- if (unresolvedAssetDirectives.length > 0 || unresolvedContextVars.length > 0 && (!step.expect_error || hasCapabilityUnavailableContext)) {
3393
+ const hasMissingToolUnavailableContext = unresolvedContextVars.some(
3394
+ (v) => runState.missingPrerequisiteContextKeys?.has(v.key) === true
3395
+ );
3396
+ if (unresolvedAssetDirectives.length > 0 || unresolvedContextVars.length > 0 && (!step.expect_error || hasCapabilityUnavailableContext || hasMissingToolUnavailableContext)) {
2948
3397
  const next2 = getNextStepPreview(step.id, allSteps, context, runState.runnerVars);
2949
3398
  const responseDerivedDetails = unresolvedVars.map((v) => runState.responseDerivedNotApplicableContextKeys?.get(v.key)).filter((d) => typeof d === "string");
2950
- const allResponseDerived = responseDerivedDetails.length === unresolvedVars.length && responseDerivedDetails.length > 0;
2951
- const allCapabilityUnavailable = unresolvedContextVars.length === unresolvedVars.length && unresolvedContextVars.length > 0 && unresolvedContextVars.every((v) => runState.capabilityUnavailableContextKeys?.has(v.key) === true);
3399
+ const allResponseDerived = !hasMissingToolUnavailableContext && responseDerivedDetails.length === unresolvedVars.length && responseDerivedDetails.length > 0;
3400
+ const allCapabilityUnavailable = !hasMissingToolUnavailableContext && unresolvedContextVars.length === unresolvedVars.length && unresolvedContextVars.length > 0 && unresolvedContextVars.every((v) => runState.capabilityUnavailableContextKeys?.has(v.key) === true);
2952
3401
  const detail = allResponseDerived ? [...new Set(responseDerivedDetails)].join("; ") : allCapabilityUnavailable ? `Skipped: context required by a capability-gated phase is unavailable: ${unresolvedVars.map((v) => v.key).join(", ")}.` : `Skipped: unresolved context variables from prior steps: ${unresolvedVars.map((v) => v.key).join(", ")}.`;
2953
3402
  const synthesized = [];
2954
3403
  if (!allResponseDerived && !allCapabilityUnavailable) {
@@ -3814,6 +4263,9 @@ async function executeProbeStep(client, step, phaseId, context, allSteps, option
3814
4263
  fetchFn: options.transport?.trustedFetchFn
3815
4264
  };
3816
4265
  let requestRecordOverride;
4266
+ let sessionProbeStage;
4267
+ let sessionProbeDetail;
4268
+ let sessionProbeTool;
3817
4269
  const contractsInScope = new Set(options.contracts ?? []);
3818
4270
  if (step.requires_contract) {
3819
4271
  if (!contractsInScope.has(step.requires_contract)) {
@@ -3895,10 +4347,48 @@ async function executeProbeStep(client, step, phaseId, context, allSteps, option
3895
4347
  httpResult.skip_reason = "oauth_not_advertised";
3896
4348
  }
3897
4349
  } else if (step.task === "oauth_auth_server_metadata") {
3898
- const prior = runState.priorProbes.get("protected_resource_metadata") ?? findPriorProbe(runState.priorStepResults);
4350
+ const prior = runState.priorProbes.get("protected_resource_metadata") ?? (runState.allowPriorProbeFallback !== false ? findPriorProbe(runState.priorStepResults) : void 0);
3899
4351
  httpResult = await probeOauthAuthServerMetadata(prior, probeOpts);
3900
4352
  } else if (step.task === "assert_contribution") {
3901
4353
  httpResult = void 0;
4354
+ } else if (step.task === MCP_SESSION_PROBE_TASK) {
4355
+ const plan = planMcpSessionSentinel(step, options, client, runState.agentUrl);
4356
+ if (plan.kind === "error") {
4357
+ httpResult = { url: runState.agentUrl, status: 0, headers: {}, body: null, error: plan.error };
4358
+ } else if (plan.kind === "skip") {
4359
+ httpResult = {
4360
+ url: runState.agentUrl,
4361
+ status: 0,
4362
+ headers: {},
4363
+ body: null,
4364
+ skipped: true,
4365
+ skip_reason: plan.reason,
4366
+ error: plan.detail
4367
+ };
4368
+ } else {
4369
+ const probe = await rawMcpSessionProbe({
4370
+ agentUrl: runState.agentUrl,
4371
+ headers: plan.headers,
4372
+ toolName: plan.toolNames,
4373
+ control: plan.control,
4374
+ // Values the probe withholds but the run's ordinary steps do send, so
4375
+ // a stateful agent's echo cannot land them in this step's evidence.
4376
+ redactValues: runCredentialValues(options),
4377
+ allowPrivateIp: options.allow_http === true,
4378
+ // Honour run cancellation and cap each request well under the shared
4379
+ // 10 s `ssrfSafeFetch` default. The probe additionally bounds the
4380
+ // whole step — candidate walk included — with one shared request /
4381
+ // byte / wall-clock budget, so a tarpitting agent cannot multiply this
4382
+ // per-request cap by the length of its own tool list.
4383
+ ...options.signal && { signal: options.signal },
4384
+ timeoutMs: MCP_SESSION_PROBE_REQUEST_TIMEOUT_MS,
4385
+ ...options.transport?.trustedFetchFn && { fetchFn: options.transport.trustedFetchFn }
4386
+ });
4387
+ httpResult = probe.httpResult;
4388
+ sessionProbeStage = probe.stage;
4389
+ sessionProbeDetail = probe.detail;
4390
+ sessionProbeTool = probe.gradedTool;
4391
+ }
3902
4392
  } else if (step.task === "request_signing_probe") {
3903
4393
  httpResult = await probeRequestSigningVector(step.id, runState.agentUrl, options);
3904
4394
  } else if (step.task === "fetch_brand_jwks") {
@@ -3975,30 +4465,35 @@ async function executeProbeStep(client, step, phaseId, context, allSteps, option
3975
4465
  };
3976
4466
  }
3977
4467
  const resolvedTargetRequest = targetRequestResult.request;
3978
- const unresolvedContextVars = findUnresolvedContextVars(resolvedTargetRequest);
4468
+ const advertisedTools = resolveAdvertisedTools(options);
4469
+ const routedPrerequisites = runState.missingPrerequisiteContextKeys !== void 0 && (!advertisedTools || advertisedTools.includes(rateLimitTrip.trip_target_task));
4470
+ const unresolvedContextVars = routedPrerequisites ? unresolvedStepContextVars(targetStep, resolvedTargetRequest, context, runState) : findUnresolvedContextVars(resolvedTargetRequest);
3979
4471
  const unresolvedAssetDirectives = findUnresolvedCreativeAssetDirectives(resolvedTargetRequest).map((path) => ({
3980
4472
  key: path,
3981
4473
  token: BUILD_ASSETS_FROM_FORMAT_DIRECTIVE
3982
4474
  }));
3983
4475
  const unresolvedVars = [...unresolvedContextVars, ...unresolvedAssetDirectives];
3984
- if (unresolvedAssetDirectives.length > 0 || unresolvedContextVars.length > 0 && !targetStep.expect_error) {
4476
+ const hardUnavailable = routedPrerequisites && unresolvedContextVars.some((v) => runState.missingPrerequisiteContextKeys?.has(v.key));
4477
+ const capabilityUnavailable = routedPrerequisites && unresolvedContextVars.some((v) => runState.capabilityUnavailableContextKeys?.has(v.key));
4478
+ if (unresolvedAssetDirectives.length > 0 || unresolvedContextVars.length > 0 && (!targetStep.expect_error || hardUnavailable || capabilityUnavailable)) {
3985
4479
  const next = getNextStepPreview(step.id, allSteps, context, runState.runnerVars);
3986
- const detail = `Skipped: unresolved context variables from rate_limit_trip.trip_target_sample_request: ${unresolvedVars.map((v) => v.key).join(", ")}.`;
4480
+ const allCapabilityUnavailable = capabilityUnavailable && !hardUnavailable && unresolvedAssetDirectives.length === 0 && unresolvedContextVars.every((v) => runState.capabilityUnavailableContextKeys?.has(v.key));
4481
+ const detail = allCapabilityUnavailable ? `Skipped: context required by a capability-gated phase is unavailable: ${unresolvedVars.map((v) => v.key).join(", ")}.` : `Skipped: unresolved context variables from rate_limit_trip.trip_target_sample_request: ${unresolvedVars.map((v) => v.key).join(", ")}.`;
3987
4482
  return {
3988
4483
  step_id: step.id,
3989
4484
  phase_id: phaseId,
3990
4485
  title: step.title,
3991
4486
  task: step.task,
3992
- passed: false,
4487
+ passed: allCapabilityUnavailable,
3993
4488
  skipped: true,
3994
- skip_reason: "prerequisite_failed",
3995
- skip: buildSkip("prerequisite_failed", detail),
4489
+ skip_reason: allCapabilityUnavailable ? "capability_prerequisite_unavailable" : "prerequisite_failed",
4490
+ skip: buildSkip(allCapabilityUnavailable ? "not_applicable" : "prerequisite_failed", detail),
3996
4491
  duration_ms: Date.now() - start,
3997
4492
  validations: [],
3998
4493
  context,
3999
4494
  next,
4000
4495
  extraction: { path: "none" },
4001
- error: detail
4496
+ ...!allCapabilityUnavailable && { error: detail }
4002
4497
  };
4003
4498
  }
4004
4499
  const unresolvedRunnerTokens = findUnresolvedRunnerTokens(resolvedTargetRequest);
@@ -4024,7 +4519,6 @@ async function executeProbeStep(client, step, phaseId, context, allSteps, option
4024
4519
  ...isPrerequisiteFailure ? { error: detail } : {}
4025
4520
  };
4026
4521
  }
4027
- const advertisedTools = resolveAdvertisedTools(options);
4028
4522
  if (advertisedTools && !advertisedTools.includes(rateLimitTrip.trip_target_task)) {
4029
4523
  const next = getNextStepPreview(step.id, allSteps, context, runState.runnerVars);
4030
4524
  const detail = `Agent did not advertise tool "${rateLimitTrip.trip_target_task}"; agent tools: [${advertisedTools.join(", ")}].`;
@@ -4120,7 +4614,7 @@ async function executeProbeStep(client, step, phaseId, context, allSteps, option
4120
4614
  if (httpResult?.skipped) {
4121
4615
  const detailedReason = httpResult.skip_reason ?? "probe_skipped";
4122
4616
  const canonicalReason = DETAILED_SKIP_TO_CANONICAL[detailedReason] ?? "not_applicable";
4123
- const detail = CANONICAL_SKIP_DETAILS[detailedReason] ?? httpResult.error ?? DETAILED_SKIP_DETAILS[detailedReason] ?? SKIP_DETAILS[canonicalReason];
4617
+ const detail = CANONICAL_SKIP_DETAILS[detailedReason] ?? redactedHttpResult?.error ?? DETAILED_SKIP_DETAILS[detailedReason] ?? SKIP_DETAILS[canonicalReason];
4124
4618
  const selectionResult = selectionForProbeSkip(detailedReason, detail);
4125
4619
  return {
4126
4620
  step_id: step.id,
@@ -4167,7 +4661,8 @@ async function executeProbeStep(client, step, phaseId, context, allSteps, option
4167
4661
  const allValidationsPassed = validations.every((v) => !validationFailsStep(v));
4168
4662
  const fetchOk = httpResult ? !httpResult.error : true;
4169
4663
  const passed = fetchOk && allValidationsPassed;
4170
- const extraction = httpResult ? httpResult.error ? { path: "error" } : { path: "structured_content", note: "http-probe body parsed as JSON" } : { path: "none" };
4664
+ const probeNote = sessionProbeStage !== void 0 ? `MCP session probe graded ${sessionProbeTool ?? "unknown tool"} at ${sessionProbeStage} (${sessionProbeDetail ?? "no detail"})` : "http-probe body parsed as JSON";
4665
+ const extraction = httpResult ? httpResult.error ? { path: "error" } : { path: "structured_content", note: probeNote } : { path: "none" };
4171
4666
  return {
4172
4667
  step_id: step.id,
4173
4668
  phase_id: phaseId,
@@ -4178,7 +4673,9 @@ async function executeProbeStep(client, step, phaseId, context, allSteps, option
4178
4673
  response: redactedHttpResult ?? void 0,
4179
4674
  validations,
4180
4675
  context,
4181
- error: httpResult?.error ?? (passed ? void 0 : "Probe validations failed."),
4676
+ // Redacted copy on both branches: the sibling skip branch reads the same
4677
+ // seam, and a probe error can carry an agent URL with OAuth params.
4678
+ error: redactedHttpResult?.error ?? (passed ? void 0 : "Probe validations failed."),
4182
4679
  next: getNextStepPreview(step.id, allSteps, context, runState.runnerVars),
4183
4680
  request: requestRecord,
4184
4681
  ...responseRecord && { response_record: responseRecord },
@@ -4201,26 +4698,7 @@ function applyFixtureBindingsSafely(request, task, options, runState) {
4201
4698
  }
4202
4699
  }
4203
4700
  function buildEffectiveStepRequest(step, context, options, runState) {
4204
- let request;
4205
- if (options.request) {
4206
- request = injectContext({ ...options.request }, context, runState.runnerVars);
4207
- } else if (step.expect_error && step.sample_request) {
4208
- request = injectContext({ ...step.sample_request }, context, runState.runnerVars);
4209
- } else if (hasRequestEnricher(step.task)) {
4210
- request = enrichRequest(step, context, options, runState.runnerVars);
4211
- } else if (step.sample_request) {
4212
- request = injectContext({ ...step.sample_request }, context, runState.runnerVars);
4213
- } else {
4214
- request = {};
4215
- }
4216
- if (step.context_inputs?.length) {
4217
- request = applyContextInputs(request, step.context_inputs, context);
4218
- }
4219
- request = applyBrandInvariant(request, options, step.task, { omit_account: step.omit_account });
4220
- if (options.disable_sandbox === true) {
4221
- request = applyDisableSandboxHint(request, step.task);
4222
- }
4223
- request = applyIdempotencyInvariant(request, step.task, step);
4701
+ const request = buildStepRequest(step, step, context, options, runState.runnerVars);
4224
4702
  const fixtureBinding = applyFixtureBindingsSafely(request, step.task, options, runState);
4225
4703
  if (!fixtureBinding.ok) return fixtureBinding;
4226
4704
  const creativeAssetExpansion = expandCreativeAssetDirectivesWithDiagnostics(
@@ -4236,23 +4714,32 @@ function buildEffectiveStepRequest(step, context, options, runState) {
4236
4714
  request: creativeAssetExpansion.value
4237
4715
  };
4238
4716
  }
4239
- function preflightRemainingCreativeAssetDirectives(allSteps, afterGlobalIndex, context, options, runState, excludedPhaseIds = /* @__PURE__ */ new Set()) {
4717
+ function preflightRemainingCreativeAssetDirectives(allSteps, afterGlobalIndex, context, options, runState, excludedPhaseIds = /* @__PURE__ */ new Set(), resolveAssignment) {
4240
4718
  const contractsInScope = new Set(options.contracts ?? []);
4241
4719
  for (const target of allSteps) {
4242
4720
  if (target.globalIndex <= afterGlobalIndex) continue;
4243
4721
  if (excludedPhaseIds.has(target.phaseId)) continue;
4244
- const resolvedTask = resolveTaskName(target.step, options);
4722
+ const assignment = resolveAssignment?.(target.step);
4723
+ if (resolveAssignment && !assignment) continue;
4724
+ const selectedOptions = assignment?.options ?? options;
4725
+ const selectedState = assignment ? {
4726
+ ...runState,
4727
+ agentUrl: assignment.agentUrl,
4728
+ agentProfile: assignment.profile,
4729
+ agentLibraryVersion: assignment.profile?.library_version
4730
+ } : runState;
4731
+ const resolvedTask = resolveTaskName(target.step, selectedOptions);
4245
4732
  if (!resolvedTask) continue;
4246
- if (target.step.requires_tool && options.agentTools && !options.agentTools.includes(target.step.requires_tool)) {
4733
+ if (target.step.requires_tool && selectedOptions.agentTools && !selectedOptions.agentTools.includes(target.step.requires_tool)) {
4247
4734
  continue;
4248
4735
  }
4249
4736
  if (target.step.requires_contract && !contractsInScope.has(target.step.requires_contract)) {
4250
4737
  continue;
4251
4738
  }
4252
- if (target.step.task === "expect_rate_limit_not_replayed" && (!contractsInScope.has(RATE_LIMIT_TRIP_CONTRACT) || options.allowLiveSideEffects !== true)) {
4739
+ if (target.step.task === "expect_rate_limit_not_replayed" && (!contractsInScope.has(RATE_LIMIT_TRIP_CONTRACT) || selectedOptions.allowLiveSideEffects !== true)) {
4253
4740
  continue;
4254
4741
  }
4255
- if (!PROBE_TASKS.has(target.step.task) && options.agentTools && !options.agentTools.includes(resolvedTask)) {
4742
+ if (!PROBE_TASKS.has(target.step.task) && selectedOptions.agentTools && !selectedOptions.agentTools.includes(resolvedTask)) {
4256
4743
  continue;
4257
4744
  }
4258
4745
  let requestStep = resolvedTask === target.step.task ? target.step : { ...target.step, task: resolvedTask };
@@ -4266,7 +4753,7 @@ function preflightRemainingCreativeAssetDirectives(allSteps, afterGlobalIndex, c
4266
4753
  omit_idempotency_key: true
4267
4754
  };
4268
4755
  }
4269
- const request = buildEffectiveStepRequest(requestStep, context, options, runState);
4756
+ const request = buildEffectiveStepRequest(requestStep, context, selectedOptions, selectedState);
4270
4757
  if (!request.ok && "creativeAssetFailure" in request) {
4271
4758
  return { target, failure: request.creativeAssetFailure };
4272
4759
  }
@@ -4934,23 +5421,6 @@ function phaseUsesRuntimeContext(phase) {
4934
5421
  const expr = phase.skip_if?.trim();
4935
5422
  return expr ? phaseConditionUsesContext(expr) : false;
4936
5423
  }
4937
- function resolveTaskName(step, options) {
4938
- if (!step.task.startsWith("$test_kit.")) return step.task;
4939
- const path = step.task.slice("$test_kit.".length).split(".");
4940
- let value = options.test_kit;
4941
- for (const segment of path) {
4942
- if (value == null || typeof value !== "object") {
4943
- value = void 0;
4944
- break;
4945
- }
4946
- value = value[segment];
4947
- }
4948
- const configured = typeof value === "string" && value.length > 0 ? value : step.task_default;
4949
- if (step.task === "$test_kit.auth.probe_task") {
4950
- return selectProbeTask(configured, options.agentTools);
4951
- }
4952
- return configured;
4953
- }
4954
5424
  function defaultAuthHeadersForRawProbe(options) {
4955
5425
  const headers = {};
4956
5426
  if (options.auth) {
@@ -4974,6 +5444,354 @@ function defaultAuthHeadersForRawProbe(options) {
4974
5444
  }
4975
5445
  return headers;
4976
5446
  }
5447
+ function sessionProbeRoutingHeaders(options) {
5448
+ const headers = {};
5449
+ for (const [name, value] of Object.entries(options.headers ?? {})) {
5450
+ if (!SESSION_PROBE_ROUTING_HEADERS.has(name.toLowerCase())) continue;
5451
+ try {
5452
+ assertSafeAuthHeaderPart(value, `options.headers.${name}`);
5453
+ } catch {
5454
+ continue;
5455
+ }
5456
+ headers[name] = value;
5457
+ }
5458
+ setHeaderIfAbsent(headers, "X-Test-Session-ID", options.test_session_id, "options.test_session_id");
5459
+ setHeaderIfAbsent(headers, "User-Agent", options.userAgent, "options.userAgent");
5460
+ return headers;
5461
+ }
5462
+ function setHeaderIfAbsent(headers, name, value, label) {
5463
+ if (!value) return;
5464
+ const lower = name.toLowerCase();
5465
+ if (Object.keys(headers).some((existing) => existing.toLowerCase() === lower)) return;
5466
+ try {
5467
+ assertSafeAuthHeaderPart(value, label);
5468
+ } catch {
5469
+ return;
5470
+ }
5471
+ headers[name] = value;
5472
+ }
5473
+ function runCredentialValues(options) {
5474
+ const values = [];
5475
+ const auth = options.auth;
5476
+ if (auth?.type === "bearer" && typeof auth.token === "string") values.push(auth.token);
5477
+ if (auth?.type === "basic") {
5478
+ if (typeof auth.password === "string") values.push(auth.password);
5479
+ if (typeof auth.username === "string" && typeof auth.password === "string") {
5480
+ values.push(`${auth.username}:${auth.password}`);
5481
+ }
5482
+ }
5483
+ if (auth?.type === "oauth" || auth?.type === "oauth_client_credentials") {
5484
+ const token = auth.tokens?.access_token;
5485
+ if (typeof token === "string") values.push(token);
5486
+ }
5487
+ const kit = options.test_kit?.auth;
5488
+ if (typeof kit?.api_key === "string") values.push(kit.api_key);
5489
+ const basic = kit?.basic;
5490
+ if (typeof basic?.password === "string") values.push(basic.password);
5491
+ if (typeof basic?.username === "string" && typeof basic?.password === "string") {
5492
+ values.push(`${basic.username}:${basic.password}`);
5493
+ }
5494
+ if (typeof basic?.credentials === "string") values.push(basic.credentials);
5495
+ for (const [name, value] of Object.entries(options.headers ?? {})) {
5496
+ if (typeof value !== "string" || value.length === 0) continue;
5497
+ if (AUTH_OVERRIDE_HEADER_NAMES.has(name.toLowerCase()) || isCredentialHeaderName(name)) values.push(value);
5498
+ }
5499
+ return values.filter((value) => value.trim().length > 0);
5500
+ }
5501
+ const SESSION_PROBE_ROUTING_HEADERS = /* @__PURE__ */ new Set([
5502
+ "x-tenant-id",
5503
+ "x-tenant",
5504
+ "x-account",
5505
+ "x-account-id",
5506
+ "x-routing-key",
5507
+ "x-partition-key",
5508
+ "x-region",
5509
+ "x-environment",
5510
+ "x-request-id",
5511
+ "x-correlation-id",
5512
+ "x-idempotency-key",
5513
+ "x-test-session-id",
5514
+ "user-agent",
5515
+ "accept-language"
5516
+ ]);
5517
+ function unroutableProbeHeader(options) {
5518
+ const runSecrets = runCredentialValues(options);
5519
+ for (const [name, value] of Object.entries(options.headers ?? {})) {
5520
+ const lower = name.toLowerCase();
5521
+ if (SESSION_PROBE_ROUTING_HEADERS.has(lower)) {
5522
+ try {
5523
+ assertSafeAuthHeaderPart(value, `options.headers.${name}`);
5524
+ } catch {
5525
+ return name;
5526
+ }
5527
+ continue;
5528
+ }
5529
+ if (AUTH_OVERRIDE_HEADER_NAMES.has(lower)) continue;
5530
+ if (runSecrets.some((secret) => value.includes(secret))) continue;
5531
+ return name;
5532
+ }
5533
+ return void 0;
5534
+ }
5535
+ function effectiveOAuthAccessToken(client, options, agentUrl) {
5536
+ const live = liveAgentOAuthAccessToken(client, agentUrl);
5537
+ if (live !== void 0) return live;
5538
+ const auth = options.auth;
5539
+ if (auth?.type !== "oauth" && auth?.type !== "oauth_client_credentials") return void 0;
5540
+ const configured = auth.tokens?.access_token;
5541
+ return typeof configured === "string" && configured.length > 0 ? configured : void 0;
5542
+ }
5543
+ function liveAgentOAuthAccessToken(client, agentUrl) {
5544
+ try {
5545
+ const resolved = client?.getAgent?.(TEST_CLIENT_AGENT_ID);
5546
+ if (resolved == null) return void 0;
5547
+ const candidates = [resolved];
5548
+ if (typeof resolved.getAgent === "function") candidates.push(resolved.getAgent());
5549
+ for (const candidate of candidates) {
5550
+ const token = candidate?.oauth_tokens?.access_token;
5551
+ if (typeof token !== "string" || token.length === 0) continue;
5552
+ const configuredUri = candidate?.agent_uri;
5553
+ if (agentUrl !== void 0 && typeof configuredUri === "string" && configuredUri !== agentUrl) continue;
5554
+ if (agentUrl !== void 0 && typeof configuredUri !== "string") continue;
5555
+ return token;
5556
+ }
5557
+ } catch {
5558
+ }
5559
+ return void 0;
5560
+ }
5561
+ const TEST_CLIENT_AGENT_ID = "test";
5562
+ function withMcpBearerParity(headers) {
5563
+ const authorization = headers.authorization;
5564
+ if (authorization === void 0 || !authorization.startsWith("Bearer ")) return headers;
5565
+ const token = authorization.slice("Bearer ".length);
5566
+ if (token.length === 0) return headers;
5567
+ return { ...headers, "x-adcp-auth": token };
5568
+ }
5569
+ function oauthAccessTokenHeaders(options, client, agentUrl) {
5570
+ const token = effectiveOAuthAccessToken(client, options, agentUrl);
5571
+ if (token === void 0) return void 0;
5572
+ try {
5573
+ assertSafeAuthHeaderPart(token, "options.auth.tokens.access_token");
5574
+ } catch {
5575
+ return void 0;
5576
+ }
5577
+ return { authorization: `Bearer ${token}` };
5578
+ }
5579
+ function staticCredentialHeaders(directive, options) {
5580
+ try {
5581
+ const headers = authHeadersForStep(directive, options);
5582
+ return headers.authorization !== void 0 ? { authorization: headers.authorization } : void 0;
5583
+ } catch {
5584
+ }
5585
+ return void 0;
5586
+ }
5587
+ function sessionControlCredentials(mechanism, options, client, agentUrl) {
5588
+ const oauth = oauthAccessTokenHeaders(options, client, agentUrl);
5589
+ const bearer = options.auth?.type === "bearer" ? staticCredentialHeaders({ type: "api_key", value: options.auth.token }, options) : void 0;
5590
+ const basicFromOptions = options.auth?.type === "basic" ? staticCredentialHeaders(
5591
+ { type: "basic", username: options.auth.username, password: options.auth.password },
5592
+ options
5593
+ ) : void 0;
5594
+ const kitApiKey = typeof options.test_kit?.auth?.api_key === "string" && options.test_kit.auth.api_key.length > 0 ? staticCredentialHeaders({ type: "api_key", from_test_kit: true }, options) : void 0;
5595
+ const kitBasic = options.test_kit?.auth?.basic !== void 0 ? staticCredentialHeaders({ type: "basic", from_test_kit: true }, options) : void 0;
5596
+ switch (mechanism) {
5597
+ case "oauth_bearer": {
5598
+ if (oauth) return { headers: oauth };
5599
+ return {
5600
+ unavailable: {
5601
+ reason: `this run holds no OAuth access token, and a static API key or Basic credential is not evidence about the OAuth path at all \u2014 accepting a shared secret says nothing about whether tokens from the issuer advertised in your protected-resource metadata are what gates this resource`,
5602
+ remedy: `Run the storyboard with OAuth so the runner holds a token minted by that issuer (\`adcp --save-auth <alias> <url> --oauth\`, or pass \`--oauth\` to \`storyboard run\`).`
5603
+ }
5604
+ };
5605
+ }
5606
+ case "api_key": {
5607
+ const headers = bearer ?? kitApiKey;
5608
+ if (headers) return { headers };
5609
+ return {
5610
+ unavailable: {
5611
+ reason: `this run holds no valid API key to prove the endpoint accepts one`,
5612
+ remedy: "Declare `auth.api_key` in the test kit, or pass a bearer `options.auth` (CLI: `--auth`)."
5613
+ }
5614
+ };
5615
+ }
5616
+ case "basic": {
5617
+ const headers = basicFromOptions ?? kitBasic;
5618
+ if (headers) return { headers };
5619
+ return {
5620
+ unavailable: {
5621
+ reason: `this run holds no valid Basic credential to prove the endpoint accepts one`,
5622
+ remedy: "Declare `auth.basic` in the test kit, or pass a basic `options.auth`."
5623
+ }
5624
+ };
5625
+ }
5626
+ case "any": {
5627
+ const headers = oauth ?? bearer ?? basicFromOptions ?? kitApiKey ?? kitBasic;
5628
+ if (headers) return { headers };
5629
+ return {
5630
+ unavailable: {
5631
+ reason: `this run holds no valid credential, so a rejection cannot be told apart from an endpoint that refuses every request`,
5632
+ remedy: "Declare `auth.api_key` or `auth.basic` in the test kit, pass `options.auth`, or run with `--oauth`."
5633
+ }
5634
+ };
5635
+ }
5636
+ }
5637
+ }
5638
+ function summarizeAdvertisedTools(tools) {
5639
+ const names = (tools ?? []).slice(0, 20).map((name) => escapeControlChars(name.slice(0, 64)));
5640
+ const overflow = (tools?.length ?? 0) - names.length;
5641
+ return overflow > 0 ? `${names.join(", ")}, \u2026${overflow} more` : names.join(", ");
5642
+ }
5643
+ function escapeControlChars(value) {
5644
+ return value.replace(
5645
+ /[\u0000-\u001f\u007f-\u009f]/g,
5646
+ (char) => `\\u${char.charCodeAt(0).toString(16).padStart(4, "0")}`
5647
+ );
5648
+ }
5649
+ const SESSION_PROBE_PUBLIC_TIER = /* @__PURE__ */ new Set([
5650
+ "get_adcp_capabilities",
5651
+ "get_products",
5652
+ "list_products",
5653
+ "list_creative_formats"
5654
+ ]);
5655
+ const CANONICAL_ADCP_TOOLS = /* @__PURE__ */ new Set([
5656
+ ...MEDIA_BUY_TOOLS,
5657
+ ...CREATIVE_TOOLS,
5658
+ ...SIGNALS_TOOLS,
5659
+ ...GOVERNANCE_TOOLS,
5660
+ ...ACCOUNT_TOOLS,
5661
+ ...BRAND_RIGHTS_TOOLS,
5662
+ ...PROTOCOL_TOOLS,
5663
+ ...EVENT_TRACKING_TOOLS
5664
+ ]);
5665
+ const PREFERRED_PROBE_TARGET = "get_principal";
5666
+ function hasNoRequiredRequestFields(tool) {
5667
+ const schema = TOOL_REQUEST_SCHEMAS[tool];
5668
+ const shape = schema?.shape;
5669
+ if (!shape) return false;
5670
+ return !Object.values(shape).some((field) => {
5671
+ const candidate = field;
5672
+ if (typeof candidate?.safeParse !== "function") return false;
5673
+ return !candidate.safeParse(void 0).success;
5674
+ });
5675
+ }
5676
+ function protectedToolCandidates(tools) {
5677
+ if (!tools) return [];
5678
+ const advertised = new Set(tools);
5679
+ const eligible = (tool) => advertised.has(tool) && !SESSION_PROBE_PUBLIC_TIER.has(tool) && !MUTATING_TASKS.has(tool);
5680
+ const allowlisted = PROBE_TASK_ALLOWLIST.filter(eligible);
5681
+ const canonicalReads = [...CANONICAL_ADCP_TOOLS].filter((tool) => /^(list|get)_/.test(tool)).filter((tool) => !allowlisted.includes(tool)).filter(eligible).filter(hasNoRequiredRequestFields).sort((a, b) => {
5682
+ if (a === PREFERRED_PROBE_TARGET) return -1;
5683
+ if (b === PREFERRED_PROBE_TARGET) return 1;
5684
+ return a.localeCompare(b);
5685
+ });
5686
+ return [...allowlisted, ...canonicalReads];
5687
+ }
5688
+ function signatureBoundTools(options) {
5689
+ if (options.functional_request_signing === void 0) return /* @__PURE__ */ new Set();
5690
+ const raw = options._profile?.raw_capabilities;
5691
+ if (raw === null || typeof raw !== "object") return "unparseable";
5692
+ const advertised = raw.request_signing;
5693
+ if (advertised === void 0) return /* @__PURE__ */ new Set();
5694
+ if (advertised === null || typeof advertised !== "object") return "unparseable";
5695
+ const buckets = advertised;
5696
+ const bound = /* @__PURE__ */ new Set();
5697
+ for (const bucket of [buckets.required_for, buckets.supported_for]) {
5698
+ if (bucket === void 0) continue;
5699
+ if (!Array.isArray(bucket) || bucket.some((entry) => typeof entry !== "string")) return "unparseable";
5700
+ for (const entry of bucket) bound.add(entry);
5701
+ }
5702
+ return bound;
5703
+ }
5704
+ function selectProtectedToolTarget(tools) {
5705
+ return protectedToolCandidates(tools)[0];
5706
+ }
5707
+ function sessionControlMechanismFor(auth) {
5708
+ if (auth === "none") return "any";
5709
+ switch (auth.type) {
5710
+ case "oauth_bearer":
5711
+ return "oauth_bearer";
5712
+ case "basic":
5713
+ return "basic";
5714
+ case "api_key":
5715
+ return "api_key";
5716
+ }
5717
+ }
5718
+ function planMcpSessionSentinel(step, options, client, agentUrl) {
5719
+ if (options.protocol !== "mcp") {
5720
+ const declared = options.protocol === void 0 ? "no transport" : `"${options.protocol}"`;
5721
+ return {
5722
+ kind: "error",
5723
+ error: `"${MCP_SESSION_PROBE_TASK}" is an MCP session probe and requires an explicit \`protocol: 'mcp'\` on the run; this run declared ${declared}. A2A has no equivalent parameter-free protected operation, so the runner refuses to substitute one.`
5724
+ };
5725
+ }
5726
+ if (step.auth === void 0) {
5727
+ return {
5728
+ kind: "skip",
5729
+ reason: "session_probe_ungradable",
5730
+ detail: redactOAuthUrlsInText(
5731
+ `Agent advertises no auth-required, read-only AdCP tool that accepts an empty request body, so the runner fell back to the MCP "${MCP_SESSION_PROBE_TASK}" session probe. That probe cannot grade a positive static-credential step: its validations assert an AdCP task response body, which no MCP protocol operation produces, so this mechanism's branch cannot contribute auth_mechanism_verified. Remedy: advertise one allowlisted read tool (${PROBE_TASK_ALLOWLIST_SUMMARY}), or serve RFC 9728 metadata and run with OAuth so the OAuth branch can be verified instead. Advertised tools: [${summarizeAdvertisedTools(options.agentTools)}].`
5732
+ )
5733
+ };
5734
+ }
5735
+ const signatureBound = signatureBoundTools(options);
5736
+ const candidates = protectedToolCandidates(options.agentTools);
5737
+ if (signatureBound === "unparseable") {
5738
+ return {
5739
+ kind: "skip",
5740
+ reason: "session_probe_ungradable",
5741
+ detail: `This run signs functional dispatch (RFC 9421), but the runner could not read which operations your \`request_signing\` capability covers, so it cannot tell whether the session probe's unsigned call would be refused for the signature rather than the credential. Refusing to grade instead of guessing. Remedy: advertise \`request_signing.required_for\` / \`supported_for\` as string arrays, or advertise one allowlisted read tool (${PROBE_TASK_ALLOWLIST_SUMMARY}) so the probe has a protocol-vouched target.`
5742
+ };
5743
+ }
5744
+ const toolNames = candidates.filter((tool) => !signatureBound.has(tool));
5745
+ if (toolNames.length === 0 && candidates.length > 0) {
5746
+ return {
5747
+ kind: "skip",
5748
+ reason: "session_probe_ungradable",
5749
+ detail: redactOAuthUrlsInText(
5750
+ `Every protected read the probe could call (${candidates.join(", ")}) is covered by this agent's \`request_signing\` advertisement, and the session probe mints no RFC 9421 signatures. An unsigned call would be refused for the missing signature, which is not evidence about the credential, so the runner refuses to grade it. Remedy: advertise one allowlisted read tool (${PROBE_TASK_ALLOWLIST_SUMMARY}) outside \`request_signing.required_for\`/\`supported_for\`, or run with OAuth against RFC 9728 metadata so the OAuth branch can be verified instead.`
5751
+ )
5752
+ };
5753
+ }
5754
+ if (toolNames.length === 0) {
5755
+ return {
5756
+ kind: "skip",
5757
+ reason: "session_probe_ungradable",
5758
+ detail: redactOAuthUrlsInText(
5759
+ `Agent advertises no auth-required, read-only AdCP tool the probe can call with an empty request body, so there is no protected operation to grade. MCP discovery (\`tools/list\`) is not a protected task and public-tier tools (${[...SESSION_PROBE_PUBLIC_TIER].join(", ")}) are served unauthenticated by design. Remedy: advertise one allowlisted read tool (${PROBE_TASK_ALLOWLIST_SUMMARY}). Advertised tools: [${summarizeAdvertisedTools(options.agentTools)}].`
5760
+ )
5761
+ };
5762
+ }
5763
+ const unroutable = unroutableProbeHeader(options);
5764
+ if (unroutable !== void 0) {
5765
+ return {
5766
+ kind: "skip",
5767
+ reason: "session_probe_ungradable",
5768
+ detail: `The runner cannot classify run header "${escapeControlChars(unroutable.slice(0, 64))}", and both answers are unsafe \u2014 forwarding it could make the unauthenticated probe authenticated, dropping it could send the probe to a different tenant than the rest of this run. Nothing was graded, and this is a property of the run, not of the agent. Three ways forward: rename it to a recognised routing header (${[...SESSION_PROBE_ROUTING_HEADERS].join(", ")}); drop it from this run if the probe does not need it; or, if it carries a credential, move that into \`options.auth\` / \`test_kit.auth\` where the runner owns it.`
5769
+ };
5770
+ }
5771
+ const routing = sessionProbeRoutingHeaders(options);
5772
+ let headers;
5773
+ try {
5774
+ headers = { ...routing, ...withMcpBearerParity(authHeadersForStep(step.auth, options)) };
5775
+ } catch (err) {
5776
+ return {
5777
+ kind: "error",
5778
+ error: `Step auth configuration error: ${err instanceof Error ? err.message : String(err)}`
5779
+ };
5780
+ }
5781
+ const control = sessionControlCredentials(sessionControlMechanismFor(step.auth), options, client, agentUrl);
5782
+ if ("unavailable" in control) {
5783
+ return { kind: "probe", headers, toolNames, control: { kind: "unavailable", ...control.unavailable } };
5784
+ }
5785
+ if (headers.authorization !== void 0 && control.headers.authorization === headers.authorization) {
5786
+ return { kind: "probe", headers, toolNames, control: { kind: "probe_is_valid_credential" } };
5787
+ }
5788
+ return {
5789
+ kind: "probe",
5790
+ headers,
5791
+ toolNames,
5792
+ control: { kind: "credential", headers: { ...routing, ...withMcpBearerParity(control.headers) } }
5793
+ };
5794
+ }
4977
5795
  function authHeadersForStep(directive, options) {
4978
5796
  if (directive === "none") return {};
4979
5797
  if (directive.type === "basic") return basicAuthHeadersForStep(directive, options);
@@ -5381,7 +6199,8 @@ function createRoutingDispatcher(ctx, options, agents) {
5381
6199
  const keyToIndex = new Map(keyOrder.map((k, i) => [k, i]));
5382
6200
  return {
5383
6201
  nextFor(step) {
5384
- const key = resolveAgentForStep(step, options, ctx);
6202
+ const task = resolveTaskName(step, { ...options, agentTools: void 0 });
6203
+ const key = resolveAgentForStep(task ? { ...step, task } : step, options, ctx);
5385
6204
  const client = ctx.clients.get(key);
5386
6205
  const profile = ctx.profiles.get(key);
5387
6206
  const url = agents[key]?.url;
@@ -5392,11 +6211,21 @@ function createRoutingDispatcher(ctx, options, agents) {
5392
6211
  `key ${key} unbound`
5393
6212
  );
5394
6213
  }
6214
+ if (!profile) {
6215
+ const failure = ctx.discoveryFailures.find((failure2) => failure2.agentKey === key);
6216
+ throw new RoutingError(
6217
+ `Agent "${key}" has no discovered profile; its task contract cannot be established.` + (failure ? ` Discovery failed: ${failure.underlying}. Fix the agent or select a healthy route.` : ""),
6218
+ step.task,
6219
+ `agent "${key}" failed discovery`
6220
+ );
6221
+ }
5395
6222
  return {
5396
6223
  client,
5397
6224
  agentUrl: url,
6225
+ agentKey: key,
5398
6226
  instanceIndex: keyToIndex.get(key) ?? 0,
5399
- profile
6227
+ profile,
6228
+ options: routedAgentOptions(agents[key], options, profile)
5400
6229
  };
5401
6230
  }
5402
6231
  };
@@ -5476,7 +6305,10 @@ function getFirstStepPreview(storyboard, context = {}) {
5476
6305
  export {
5477
6306
  __defaultAuthHeadersForRawProbeForTest,
5478
6307
  __filterResponseHeadersForTest,
6308
+ __protectedToolCandidatesForTest,
5479
6309
  __redactSecretsForTest,
6310
+ __selectProtectedToolTargetForTest,
6311
+ __sessionControlCredentialsForTest,
5480
6312
  applyAdcpVersionRunOptions,
5481
6313
  applyBrandInvariant,
5482
6314
  applyDisableSandboxHint,
@@ -5490,5 +6322,8 @@ export {
5490
6322
  resolveCapabilityPath,
5491
6323
  runStoryboard,
5492
6324
  runStoryboardStep,
6325
+ signingCoverage,
6326
+ signingCoverageUnverified,
6327
+ storyboardCapabilityPredicates,
5493
6328
  summarizeStrictValidation
5494
6329
  };