@adcp/sdk 15.9.1 → 16.0.0-beta.2

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 (321) hide show
  1. package/bin/adcp-identity.js +74 -0
  2. package/bin/adcp.js +2 -0
  3. package/dist/lib/adapters/keyed-account-backend.d.mts +37 -0
  4. package/dist/lib/adapters/keyed-account-backend.d.ts +37 -0
  5. package/dist/lib/adapters/keyed-account-backend.js +121 -0
  6. package/dist/lib/adapters/keyed-account-backend.mjs +94 -0
  7. package/dist/lib/adapters/keyed-account-store.d.mts +28 -0
  8. package/dist/lib/adapters/keyed-account-store.d.ts +28 -0
  9. package/dist/lib/adapters/keyed-account-store.js +227 -0
  10. package/dist/lib/adapters/keyed-account-store.mjs +203 -0
  11. package/dist/lib/core/SingleAgentClient.d.mts +25 -2
  12. package/dist/lib/core/SingleAgentClient.d.ts +25 -2
  13. package/dist/lib/core/SingleAgentClient.js +280 -62
  14. package/dist/lib/core/SingleAgentClient.mjs +282 -57
  15. package/dist/lib/core/TaskExecutor.d.mts +6 -0
  16. package/dist/lib/core/TaskExecutor.d.ts +6 -0
  17. package/dist/lib/core/TaskExecutor.js +66 -5
  18. package/dist/lib/core/TaskExecutor.mjs +71 -5
  19. package/dist/lib/core/postgres-webhook-registration-store.js +32 -5
  20. package/dist/lib/core/postgres-webhook-registration-store.mjs +32 -5
  21. package/dist/lib/core/redis-webhook-registration-store.js +23 -1
  22. package/dist/lib/core/redis-webhook-registration-store.mjs +23 -1
  23. package/dist/lib/core/webhook-registration.d.mts +7 -1
  24. package/dist/lib/core/webhook-registration.d.ts +7 -1
  25. package/dist/lib/core/webhook-registration.js +24 -2
  26. package/dist/lib/core/webhook-registration.mjs +23 -2
  27. package/dist/lib/identity-3.3/generated-compat.d.mts +34 -0
  28. package/dist/lib/identity-3.3/generated-compat.d.ts +34 -0
  29. package/dist/lib/identity-3.3/generated-compat.js +16 -0
  30. package/dist/lib/identity-3.3/generated-compat.mjs +0 -0
  31. package/dist/lib/identity-3.3/index.d.mts +10 -0
  32. package/dist/lib/identity-3.3/index.d.ts +10 -0
  33. package/dist/lib/identity-3.3/index.js +79 -0
  34. package/dist/lib/identity-3.3/index.mjs +50 -0
  35. package/dist/lib/identity-3.3/lifecycle.d.mts +125 -0
  36. package/dist/lib/identity-3.3/lifecycle.d.ts +125 -0
  37. package/dist/lib/identity-3.3/lifecycle.js +294 -0
  38. package/dist/lib/identity-3.3/lifecycle.mjs +272 -0
  39. package/dist/lib/identity-3.3/revocation.d.mts +86 -0
  40. package/dist/lib/identity-3.3/revocation.d.ts +86 -0
  41. package/dist/lib/identity-3.3/revocation.js +308 -0
  42. package/dist/lib/identity-3.3/revocation.mjs +286 -0
  43. package/dist/lib/identity-3.3/schemas.draft.d.mts +2472 -0
  44. package/dist/lib/identity-3.3/schemas.draft.d.ts +2472 -0
  45. package/dist/lib/identity-3.3/schemas.draft.js +1448 -0
  46. package/dist/lib/identity-3.3/schemas.draft.mjs +1428 -0
  47. package/dist/lib/identity-3.3/server.d.mts +46 -0
  48. package/dist/lib/identity-3.3/server.d.ts +46 -0
  49. package/dist/lib/identity-3.3/server.js +279 -0
  50. package/dist/lib/identity-3.3/server.mjs +260 -0
  51. package/dist/lib/identity-3.3/store.d.mts +24 -0
  52. package/dist/lib/identity-3.3/store.d.ts +24 -0
  53. package/dist/lib/identity-3.3/store.js +191 -0
  54. package/dist/lib/identity-3.3/store.mjs +169 -0
  55. package/dist/lib/identity-3.3/trust.d.mts +155 -0
  56. package/dist/lib/identity-3.3/trust.d.ts +155 -0
  57. package/dist/lib/identity-3.3/trust.js +383 -0
  58. package/dist/lib/identity-3.3/trust.mjs +342 -0
  59. package/dist/lib/identity-3.3/types.d.mts +155 -0
  60. package/dist/lib/identity-3.3/types.d.ts +155 -0
  61. package/dist/lib/identity-3.3/types.js +16 -0
  62. package/dist/lib/identity-3.3/types.mjs +0 -0
  63. package/dist/lib/identity-3.3/validation.d.mts +2 -0
  64. package/dist/lib/identity-3.3/validation.d.ts +2 -0
  65. package/dist/lib/identity-3.3/validation.js +125 -0
  66. package/dist/lib/identity-3.3/validation.mjs +91 -0
  67. package/dist/lib/index.d.mts +1 -1
  68. package/dist/lib/index.d.ts +1 -1
  69. package/dist/lib/index.js +2 -0
  70. package/dist/lib/index.mjs +2 -0
  71. package/dist/lib/protocols/index.d.mts +1 -1
  72. package/dist/lib/protocols/index.d.ts +1 -1
  73. package/dist/lib/protocols/index.js +2 -2
  74. package/dist/lib/protocols/index.mjs +2 -2
  75. package/dist/lib/reporting/azure/index.d.mts +5 -0
  76. package/dist/lib/reporting/azure/index.d.ts +5 -0
  77. package/dist/lib/reporting/azure/index.js +26 -7
  78. package/dist/lib/reporting/azure/index.mjs +26 -7
  79. package/dist/lib/reporting/bigquery/index.d.mts +39 -5
  80. package/dist/lib/reporting/bigquery/index.d.ts +39 -5
  81. package/dist/lib/reporting/bigquery/index.js +26 -20
  82. package/dist/lib/reporting/bigquery/index.mjs +26 -20
  83. package/dist/lib/reporting/gcs/adapter.d.mts +8 -1
  84. package/dist/lib/reporting/gcs/adapter.d.ts +8 -1
  85. package/dist/lib/reporting/gcs/errors.d.mts +6 -0
  86. package/dist/lib/reporting/gcs/errors.d.ts +6 -0
  87. package/dist/lib/reporting/gcs/fence.d.mts +5 -0
  88. package/dist/lib/reporting/gcs/fence.d.ts +5 -0
  89. package/dist/lib/reporting/gcs/index.d.mts +9 -0
  90. package/dist/lib/reporting/gcs/index.d.ts +9 -0
  91. package/dist/lib/reporting/gcs/reader.d.mts +27 -3
  92. package/dist/lib/reporting/gcs/reader.d.ts +27 -3
  93. package/dist/lib/reporting/gcs/row-provider.d.mts +7 -0
  94. package/dist/lib/reporting/gcs/row-provider.d.ts +7 -0
  95. package/dist/lib/reporting/gcs/row-provider.js +34 -14
  96. package/dist/lib/reporting/gcs/row-provider.mjs +34 -14
  97. package/dist/lib/reporting/ledger/change-feed.d.mts +22 -1
  98. package/dist/lib/reporting/ledger/change-feed.d.ts +22 -1
  99. package/dist/lib/reporting/ledger/index.d.mts +11 -0
  100. package/dist/lib/reporting/ledger/index.d.ts +11 -0
  101. package/dist/lib/reporting/ledger/managed-postgres.d.mts +8 -0
  102. package/dist/lib/reporting/ledger/managed-postgres.d.ts +8 -0
  103. package/dist/lib/reporting/ledger/managed-router.d.mts +27 -2
  104. package/dist/lib/reporting/ledger/managed-router.d.ts +27 -2
  105. package/dist/lib/reporting/ledger/managed.d.mts +86 -6
  106. package/dist/lib/reporting/ledger/managed.d.ts +86 -6
  107. package/dist/lib/reporting/ledger/notification-activity.d.mts +65 -3
  108. package/dist/lib/reporting/ledger/notification-activity.d.ts +65 -3
  109. package/dist/lib/reporting/ledger/object-writes.d.mts +64 -5
  110. package/dist/lib/reporting/ledger/object-writes.d.ts +64 -5
  111. package/dist/lib/reporting/ledger/postgres.d.mts +43 -9
  112. package/dist/lib/reporting/ledger/postgres.d.ts +43 -9
  113. package/dist/lib/reporting/ledger/postgres.js +43 -27
  114. package/dist/lib/reporting/ledger/postgres.mjs +43 -27
  115. package/dist/lib/reporting/ledger/row-encoding.d.mts +92 -6
  116. package/dist/lib/reporting/ledger/row-encoding.d.ts +92 -6
  117. package/dist/lib/reporting/ledger/row-encoding.js +8 -4
  118. package/dist/lib/reporting/ledger/row-encoding.mjs +6 -3
  119. package/dist/lib/reporting/ledger/row-storage-errors.d.mts +11 -1
  120. package/dist/lib/reporting/ledger/row-storage-errors.d.ts +11 -1
  121. package/dist/lib/reporting/ledger/row-storage-migration.d.mts +19 -1
  122. package/dist/lib/reporting/ledger/row-storage-migration.d.ts +19 -1
  123. package/dist/lib/reporting/ledger/row-storage-migration.js +133 -18
  124. package/dist/lib/reporting/ledger/row-storage-migration.mjs +133 -18
  125. package/dist/lib/reporting/ledger/row-storage-object.d.mts +103 -12
  126. package/dist/lib/reporting/ledger/row-storage-object.d.ts +103 -12
  127. package/dist/lib/reporting/ledger/row-storage-object.js +106 -31
  128. package/dist/lib/reporting/ledger/row-storage-object.mjs +104 -31
  129. package/dist/lib/reporting/ledger/row-storage.d.mts +87 -20
  130. package/dist/lib/reporting/ledger/row-storage.d.ts +87 -20
  131. package/dist/lib/reporting/ledger/row-storage.js +126 -66
  132. package/dist/lib/reporting/ledger/row-storage.mjs +129 -67
  133. package/dist/lib/reporting/ledger/schedule.d.mts +13 -0
  134. package/dist/lib/reporting/ledger/schedule.d.ts +13 -0
  135. package/dist/lib/reporting/ledger/schedule.js +24 -0
  136. package/dist/lib/reporting/ledger/schedule.mjs +23 -0
  137. package/dist/lib/reporting/ledger/types.d.mts +23 -1
  138. package/dist/lib/reporting/ledger/types.d.ts +23 -1
  139. package/dist/lib/reporting/s3/index.d.mts +5 -0
  140. package/dist/lib/reporting/s3/index.d.ts +5 -0
  141. package/dist/lib/reporting/s3/index.js +37 -14
  142. package/dist/lib/reporting/s3/index.mjs +37 -14
  143. package/dist/lib/reporting/service/index.d.mts +10 -0
  144. package/dist/lib/reporting/service/index.d.ts +10 -0
  145. package/dist/lib/reporting/service/maintenance.d.mts +28 -2
  146. package/dist/lib/reporting/service/maintenance.d.ts +28 -2
  147. package/dist/lib/schemas-data/v2.5/_provenance.json +1 -1
  148. package/dist/lib/server/account-sync-contract.d.mts +14 -0
  149. package/dist/lib/server/account-sync-contract.d.ts +14 -0
  150. package/dist/lib/server/account-sync-contract.js +225 -0
  151. package/dist/lib/server/account-sync-contract.mjs +197 -0
  152. package/dist/lib/server/adcp-server.js +5 -0
  153. package/dist/lib/server/adcp-server.mjs +10 -0
  154. package/dist/lib/server/auth-signature.d.mts +15 -0
  155. package/dist/lib/server/auth-signature.d.ts +15 -0
  156. package/dist/lib/server/auth-signature.js +72 -2
  157. package/dist/lib/server/auth-signature.mjs +81 -2
  158. package/dist/lib/server/auth.d.mts +6 -0
  159. package/dist/lib/server/auth.d.ts +6 -0
  160. package/dist/lib/server/auth.js +6 -0
  161. package/dist/lib/server/auth.mjs +6 -0
  162. package/dist/lib/server/create-adcp-server.d.mts +19 -5
  163. package/dist/lib/server/create-adcp-server.d.ts +19 -5
  164. package/dist/lib/server/create-adcp-server.js +259 -19
  165. package/dist/lib/server/create-adcp-server.mjs +266 -10
  166. package/dist/lib/server/decisioning/account.d.mts +24 -1
  167. package/dist/lib/server/decisioning/account.d.ts +24 -1
  168. package/dist/lib/server/decisioning/index.d.mts +1 -1
  169. package/dist/lib/server/decisioning/index.d.ts +1 -1
  170. package/dist/lib/server/decisioning/runtime/from-platform.d.mts +0 -50
  171. package/dist/lib/server/decisioning/runtime/from-platform.d.ts +0 -50
  172. package/dist/lib/server/decisioning/runtime/from-platform.js +61 -11
  173. package/dist/lib/server/decisioning/runtime/from-platform.mjs +65 -12
  174. package/dist/lib/server/index.d.mts +2 -0
  175. package/dist/lib/server/index.d.ts +2 -0
  176. package/dist/lib/server/index.js +12 -0
  177. package/dist/lib/server/index.mjs +12 -0
  178. package/dist/lib/server/notification-subscriptions/runtime.js +9 -1
  179. package/dist/lib/server/notification-subscriptions/runtime.mjs +9 -1
  180. package/dist/lib/server/notification-subscriptions/types.d.mts +5 -0
  181. package/dist/lib/server/notification-subscriptions/types.d.ts +5 -0
  182. package/dist/lib/server/principal/types.d.mts +1 -1
  183. package/dist/lib/server/principal/types.d.ts +1 -1
  184. package/dist/lib/server/serve.js +5 -0
  185. package/dist/lib/server/serve.mjs +5 -0
  186. package/dist/lib/server/webhook-delivery/recovery.d.mts +1 -0
  187. package/dist/lib/server/webhook-delivery/recovery.d.ts +1 -0
  188. package/dist/lib/server/webhook-delivery/recovery.js +4 -0
  189. package/dist/lib/server/webhook-delivery/recovery.mjs +4 -0
  190. package/dist/lib/server/webhook-emitter.d.mts +10 -0
  191. package/dist/lib/server/webhook-emitter.d.ts +10 -0
  192. package/dist/lib/server/webhook-emitter.js +22 -0
  193. package/dist/lib/server/webhook-emitter.mjs +22 -0
  194. package/dist/lib/signing/agent-context.d.mts +0 -5
  195. package/dist/lib/signing/agent-context.d.ts +0 -5
  196. package/dist/lib/signing/agent-context.js +9 -1
  197. package/dist/lib/signing/agent-context.mjs +9 -1
  198. package/dist/lib/signing/agent-fetch.js +27 -2
  199. package/dist/lib/signing/agent-fetch.mjs +32 -2
  200. package/dist/lib/signing/agent-resolver/canonicalize.d.mts +10 -15
  201. package/dist/lib/signing/agent-resolver/canonicalize.d.ts +10 -15
  202. package/dist/lib/signing/agent-resolver/canonicalize.js +17 -5
  203. package/dist/lib/signing/agent-resolver/canonicalize.mjs +16 -5
  204. package/dist/lib/signing/agent-resolver/index.d.mts +1 -0
  205. package/dist/lib/signing/agent-resolver/index.d.ts +1 -0
  206. package/dist/lib/signing/agent-resolver/index.js +5 -0
  207. package/dist/lib/signing/agent-resolver/index.mjs +3 -0
  208. package/dist/lib/signing/agent-resolver/resolved-agent-jwks.d.mts +3 -2
  209. package/dist/lib/signing/agent-resolver/resolved-agent-jwks.d.ts +3 -2
  210. package/dist/lib/signing/agent-resolver/resolved-agent-jwks.js +30 -3
  211. package/dist/lib/signing/agent-resolver/resolved-agent-jwks.mjs +30 -3
  212. package/dist/lib/signing/agent-resolver/strict-json.d.mts +2 -2
  213. package/dist/lib/signing/agent-resolver/strict-json.d.ts +2 -2
  214. package/dist/lib/signing/agent-resolver/strict-json.js +5 -3
  215. package/dist/lib/signing/agent-resolver/strict-json.mjs +5 -3
  216. package/dist/lib/signing/brand-jwks.d.mts +2 -2
  217. package/dist/lib/signing/brand-jwks.d.ts +2 -2
  218. package/dist/lib/signing/brand-jwks.js +4 -4
  219. package/dist/lib/signing/brand-jwks.mjs +4 -4
  220. package/dist/lib/signing/client.d.mts +1 -0
  221. package/dist/lib/signing/client.d.ts +1 -0
  222. package/dist/lib/signing/client.js +5 -0
  223. package/dist/lib/signing/client.mjs +3 -0
  224. package/dist/lib/signing/crypto.js +8 -0
  225. package/dist/lib/signing/crypto.mjs +9 -1
  226. package/dist/lib/signing/fetch-async.js +1 -1
  227. package/dist/lib/signing/fetch-async.mjs +1 -1
  228. package/dist/lib/signing/fetch.js +1 -1
  229. package/dist/lib/signing/fetch.mjs +1 -1
  230. package/dist/lib/signing/jwks-https.d.mts +1 -1
  231. package/dist/lib/signing/jwks-https.d.ts +1 -1
  232. package/dist/lib/signing/jwks-https.js +1 -1
  233. package/dist/lib/signing/jwks-https.mjs +1 -1
  234. package/dist/lib/signing/jwks.d.mts +11 -3
  235. package/dist/lib/signing/jwks.d.ts +11 -3
  236. package/dist/lib/signing/jwks.js +1 -1
  237. package/dist/lib/signing/jwks.mjs +1 -1
  238. package/dist/lib/signing/middleware.js +9 -0
  239. package/dist/lib/signing/middleware.mjs +14 -0
  240. package/dist/lib/signing/parser.d.mts +9 -6
  241. package/dist/lib/signing/parser.d.ts +9 -6
  242. package/dist/lib/signing/parser.js +82 -64
  243. package/dist/lib/signing/parser.mjs +83 -65
  244. package/dist/lib/signing/revocation.d.mts +4 -1
  245. package/dist/lib/signing/revocation.d.ts +4 -1
  246. package/dist/lib/signing/revocation.js +36 -3
  247. package/dist/lib/signing/revocation.mjs +34 -2
  248. package/dist/lib/signing/server.d.mts +1 -1
  249. package/dist/lib/signing/server.d.ts +1 -1
  250. package/dist/lib/signing/server.js +4 -0
  251. package/dist/lib/signing/server.mjs +4 -0
  252. package/dist/lib/signing/types.d.mts +3 -0
  253. package/dist/lib/signing/types.d.ts +3 -0
  254. package/dist/lib/signing/verifier.js +1 -1
  255. package/dist/lib/signing/verifier.mjs +1 -1
  256. package/dist/lib/signing/web-bot-auth.d.mts +191 -0
  257. package/dist/lib/signing/web-bot-auth.d.ts +191 -0
  258. package/dist/lib/signing/web-bot-auth.js +837 -0
  259. package/dist/lib/signing/web-bot-auth.mjs +796 -0
  260. package/dist/lib/signing/webhook-verifier.js +1 -1
  261. package/dist/lib/signing/webhook-verifier.mjs +1 -1
  262. package/dist/lib/testing/client.d.mts +1 -4
  263. package/dist/lib/testing/client.d.ts +1 -4
  264. package/dist/lib/testing/client.js +141 -20
  265. package/dist/lib/testing/client.mjs +137 -19
  266. package/dist/lib/testing/compliance/comply.js +29 -10
  267. package/dist/lib/testing/compliance/comply.mjs +37 -11
  268. package/dist/lib/testing/storyboard/account-sync-contract.d.mts +3 -0
  269. package/dist/lib/testing/storyboard/account-sync-contract.d.ts +3 -0
  270. package/dist/lib/testing/storyboard/account-sync-contract.js +79 -0
  271. package/dist/lib/testing/storyboard/account-sync-contract.mjs +55 -0
  272. package/dist/lib/testing/storyboard/default-invariants.js +2 -0
  273. package/dist/lib/testing/storyboard/default-invariants.mjs +2 -0
  274. package/dist/lib/testing/storyboard/runner.js +23 -8
  275. package/dist/lib/testing/storyboard/runner.mjs +24 -8
  276. package/dist/lib/testing/storyboard/validations.d.mts +1 -1
  277. package/dist/lib/testing/storyboard/validations.d.ts +1 -1
  278. package/dist/lib/types/adcp.d.mts +4 -0
  279. package/dist/lib/types/adcp.d.ts +4 -0
  280. package/dist/lib/types/schemas.generated.d.ts +6 -6
  281. package/dist/lib/utils/capabilities.d.mts +1 -0
  282. package/dist/lib/utils/capabilities.d.ts +1 -0
  283. package/dist/lib/utils/capabilities.js +5 -0
  284. package/dist/lib/utils/capabilities.mjs +5 -0
  285. package/dist/lib/v2/projection/catalog-snapshot.js +3 -1
  286. package/dist/lib/v2/projection/catalog-snapshot.mjs +3 -1
  287. package/dist/lib/v2/projection/creative-delivery.d.mts +34 -10
  288. package/dist/lib/v2/projection/creative-delivery.d.ts +34 -10
  289. package/dist/lib/v2/projection/creative-delivery.js +26 -10
  290. package/dist/lib/v2/projection/creative-delivery.mjs +26 -10
  291. package/dist/lib/v2/projection/index.d.mts +1 -1
  292. package/dist/lib/v2/projection/index.d.ts +1 -1
  293. package/dist/lib/v2/projection/index.js +2 -0
  294. package/dist/lib/v2/projection/index.mjs +2 -0
  295. package/dist/lib/v2/projection/legacy-routes.d.mts +34 -2
  296. package/dist/lib/v2/projection/legacy-routes.d.ts +34 -2
  297. package/dist/lib/v2/projection/legacy-routes.js +35 -2
  298. package/dist/lib/v2/projection/legacy-routes.mjs +32 -2
  299. package/dist/lib/validation/schema-loader.d.mts +2 -0
  300. package/dist/lib/validation/schema-loader.d.ts +2 -0
  301. package/dist/lib/validation/schema-loader.js +43 -4
  302. package/dist/lib/validation/schema-loader.mjs +39 -3
  303. package/dist/lib/version.d.mts +3 -3
  304. package/dist/lib/version.d.ts +3 -3
  305. package/dist/lib/version.js +3 -3
  306. package/dist/lib/version.mjs +3 -3
  307. package/docs/TYPE-SUMMARY.md +2 -2
  308. package/docs/guides/DISCOVERY-CACHE-AND-SESSION-REUSE.md +4 -0
  309. package/docs/guides/REPORTING-LEDGER-CUTOVER.md +1 -1
  310. package/docs/guides/REPORTING-LEDGER.md +99 -29
  311. package/docs/guides/REPORTING-OPERATIONS.md +29 -13
  312. package/docs/guides/REPORTING-STABILITY.md +76 -0
  313. package/docs/guides/account-resolution.md +101 -0
  314. package/docs/llms.txt +3 -2
  315. package/docs/migration-12-to-13.md +15 -0
  316. package/docs/migration-14.x-rc-worksheet.md +4 -4
  317. package/docs/migration-agent-identity-3.3.md +494 -0
  318. package/docs/migration-agent-resolution-3.3.md +5 -0
  319. package/docs/migration-reporting-row-storage-alignment.md +137 -0
  320. package/examples/storyboards/account-sync-contract.yaml +57 -0
  321. package/package.json +17 -1
@@ -0,0 +1,494 @@
1
+ # Experimental AdCP 3.3 agent identity
2
+
3
+ The experimental identity rollout is tracked in
4
+ [adcp-client#3233](https://github.com/adcontextprotocol/adcp-client/issues/3233).
5
+ This release implements the rollout behind explicit experimental configuration.
6
+ The SDK's default `ADCP_VERSION` remains **3.2.4**. Experimental client/server
7
+ instances select the 3.3 carrier and apply the pinned draft overlays to the
8
+ released bundle; they do not regenerate or replace the public 3.2 types.
9
+ Upstream PRs remain open, so the experiment can change before graduation.
10
+
11
+ The dedicated API is `@adcp/sdk/identity-3.3`. Existing RFC configuration remains
12
+ supported through 3.x and emits a one-time deprecation warning when used.
13
+
14
+ ## Canonical agent origins
15
+
16
+ ```ts
17
+ import { canonicalAgentOrigin } from '@adcp/sdk/signing/client';
18
+
19
+ const origin = canonicalAgentOrigin('HTTPS://User@Buyer.Example.COM.:443/mcp?x=1');
20
+ // https://buyer.example.com
21
+ ```
22
+
23
+ The helper is also exported from `@adcp/sdk/signing/server` and
24
+ `@adcp/sdk/signing`. It reuses the existing authority canonicalization rules:
25
+ scheme and host case normalization, one trailing DNS root dot removed,
26
+ userinfo and default ports stripped, and non-default ports preserved. Path,
27
+ query, and fragment do not participate in origin comparison. Malformed
28
+ authorities, raw authority backslashes or control characters, and IPv6 zone
29
+ identifiers are rejected. Producer inputs with IDN
30
+ U-labels normalize to Punycode A-labels. Wire comparers must separately reject
31
+ raw non-ASCII hostnames before comparing, as the existing `canonicalAgentUrl`
32
+ helper does.
33
+
34
+ The existing `canonicalizeOrigin` / `originsEqual` primitives and
35
+ `identity.key_origins` comparisons use this same authority validation. A
36
+ single trailing DNS root dot now compares equal to its dotless form;
37
+ malformed authorities that the URL parser previously repaired are rejected.
38
+ `CanonicalizeError` is exported from the same signing entry points. Origin
39
+ errors use fixed messages and redact the input in `meta.input`, including
40
+ userinfo, path, and query values.
41
+
42
+ Origin normalization does not verify a signature or grant authority. Continue
43
+ to use full canonical agent URLs for existing RFC 9421 identities, governance
44
+ JWS issuers, and path-mounted agents. The WBA profile permits one agent
45
+ per origin; origin equality alone must not merge existing principals.
46
+
47
+ ## Resolver request context
48
+
49
+ Both `JwksResolver.resolve(keyid, signerOrigin?)` and the optional
50
+ `resolveWithMetadata(keyid, signerOrigin?)` accept an origin locator. Existing
51
+ one-argument implementations and calls remain compatible. Static and HTTPS
52
+ resolvers remain pinned to their configured keys or URL; the additional
53
+ argument does not turn them into identity-discovery resolvers.
54
+
55
+ `ResolvedAgentJwksResolver` checks a supplied origin against the origin of its
56
+ configured agent URL before discovery or cached-key access. A mismatch or
57
+ malformed locator is rejected with `request_signature_key_unknown`; raw
58
+ non-ASCII context hostnames are rejected before origin comparison. Matching
59
+ origins retain the full capability-confirmed `agentUrl` in discovery metadata.
60
+ Percent-encoded context hostnames are also rejected so escaped U-labels
61
+ cannot bypass wire validation; percent escapes in stripped userinfo remain
62
+ accepted. Producer origin normalization retains its existing behavior.
63
+ `BrandJsonJwksResolver` forwards the context through both lookup methods,
64
+ including after legacy onboarding has selected and pinned an agent URL.
65
+ When legacy brand configuration omits `agentUrl`, initial onboarding must
66
+ complete the configured operator, capability, and JWKS discovery chain to
67
+ confirm and pin an agent URL before it compares origin context. Subsequent
68
+ lookups check the pinned origin before fetching keys. The
69
+ context never changes the onboarding fetch target.
70
+
71
+ Custom wrappers must forward both the argument and discovery metadata:
72
+
73
+ ```ts
74
+ import type { JwksResolver } from '@adcp/sdk/signing/server';
75
+
76
+ function wrapResolver(inner: JwksResolver): JwksResolver {
77
+ return {
78
+ resolve: (keyid, signerOrigin) => inner.resolve(keyid, signerOrigin),
79
+ ...(inner.resolveWithMetadata && {
80
+ resolveWithMetadata: (keyid: string, signerOrigin?: string) =>
81
+ inner.resolveWithMetadata!(keyid, signerOrigin),
82
+ }),
83
+ };
84
+ }
85
+ ```
86
+
87
+ Origin-aware caches and concurrent-lookup coalescing must use
88
+ `(canonicalAgentOrigin(signerOrigin), keyid)` as their key. A shared `kid`
89
+ must never select another origin's key or metadata. Keep context-free lookups
90
+ separate. Use a structured key, such as nested maps or `JSON.stringify([origin, keyid])`,
91
+ to prevent delimiter collisions. Treat the origin as an unverified locator until signature
92
+ verification succeeds. Validate request-derived locators against the wire
93
+ rules before forming a cache key; producer normalization alone does not
94
+ reject raw IDN U-labels. On request verification, metadata remains necessary
95
+ to reject webhook-only fallback keys and expired operator delegations.
96
+
97
+ ## Buyer signing and webhook registration
98
+
99
+ ```ts
100
+ import { SingleAgentClient } from '@adcp/sdk';
101
+ import { jwkThumbprint } from '@adcp/sdk/identity-3.3';
102
+
103
+ const client = new SingleAgentClient({
104
+ ...seller,
105
+ request_signing: {
106
+ profile: 'web-bot-auth',
107
+ agent_url: 'https://buyer.example.com',
108
+ kid: jwkThumbprint(privateJwk),
109
+ alg: 'ed25519',
110
+ private_key: privateJwk,
111
+ },
112
+ }, {
113
+ experimentalIdentity33: true,
114
+ webhookSigningProfile: 'web-bot-auth',
115
+ webhookVerification: {
116
+ webBotAuth: { directory, revocation: revocations },
117
+ },
118
+ });
119
+ ```
120
+
121
+ The official MCP/A2A transports receive the SDK's signed fetch wrapper. The
122
+ seller must advertise `request_signing.profiles` containing `web-bot-auth`.
123
+ Provider configurations additionally supply `public_key`; the provider's
124
+ thumbprint kid and algorithm must match that public key. The wrapper signs the
125
+ final UTF-8 body, covers the selected `Signature-Agent` member and digest,
126
+ uses a fresh nonce, and refuses automatic HTTP redirects. `signWebBotAuth`
127
+ also supports `relay: true` with a new label; the verifier validates every
128
+ layer regardless of dictionary ordering.
129
+
130
+ `SignatureDirectoryResolver` derives the directory from the covered canonical
131
+ origin. It validates a possession signature for every key and the exact body
132
+ digest before caching keys. Its audit proof retains the signed body and
133
+ headers. Verification requires this resolver so context-free JWKS adapters cannot
134
+ attribute a key to an arbitrary origin. Discovery uses HTTPS, DNS pinning, no redirects, a 256 KiB cap, a
135
+ 5-second connect bound and 10-second total bound, at most 64 keys, and bounded
136
+ single-flight/negative caches. Successful refresh replaces the key set;
137
+ failed refresh cannot prove removal, and never extends possession-proof
138
+ expiry. Published vector keys are rejected in production.
139
+
140
+ Publish an origin revocation list even when no keys are revoked. For example:
141
+
142
+ ```sh
143
+ adcp identity revocations --origin https://buyer.example.com --keys private-jwks.json --output revocations.jws
144
+ ```
145
+
146
+ Serve the exact JWS at `/.well-known/governance-revocations.json` and refresh it
147
+ before `next_update` (the command defaults to five minutes). Pass `--snapshot`
148
+ to sign a list of revoked key thumbprints and optional reasons/dates.
149
+ `createSignedOriginRevocationList` provides the same authoring API. The SDK
150
+ supports Ed25519 and P-256 identity keys. Observed key revocations are permanent;
151
+ refresh failures use the last verified list only within the published grace
152
+ window. Staleness follows the list's signed `next_update`, never the polling
153
+ interval: the verifier re-polls at least every polling interval (at most 30
154
+ minutes) and fails closed only after `next_update` plus four polling
155
+ intervals. Publishers MUST NOT declare `next_update` more than 30 minutes ahead
156
+ (the authoring helper refuses it), but a verifier tolerates a longer cadence
157
+ from other implementations: each successful fetch of such a list stays valid
158
+ for at most 30 minutes plus grace, so an outage cannot extend acceptance past
159
+ that. A list whose `updated` is more than 60 seconds ahead of the verifier
160
+ clock, or whose `next_update` has passed, is refused. `OriginRevocationResolver.status()` reports `revoked`, `current`
161
+ (including within grace), `absent` (the origin answers 404/410: the identity is
162
+ established but cannot be bound for spend) or `unknown` (no verifiable list and
163
+ grace has passed: the identity is not established, so the request is handled as
164
+ unverified). History-store failures throw `revocation_persistence_failed`, an
165
+ infrastructure outage handled by the application layer. `isRevoked()` remains as
166
+ a compatibility wrapper that throws `revocation_unavailable` for `absent` and
167
+ `unknown`.
168
+
169
+ For positively negotiated 3.3 sellers advertising signed webhooks, experimental
170
+ clients omit injected reporting/task webhook HMAC authentication even when a
171
+ client secret exists. Explicit caller authentication preserves the legacy
172
+ choice. Older, unknown-version, and unsigned-webhook sellers preserve existing
173
+ behavior. `update_media_buy` and artifact registrations are validated with the
174
+ same negotiated draft rules. The selected asymmetric profile is persisted in
175
+ the trusted callback registration and survives Redis/Postgres storage and
176
+ restart. An incoming header cannot change that selection. Reporting routes
177
+ use the configured registration lifetime; keep it long enough for delivery.
178
+ Sellers must persist `reporting_webhook.signing_profile` with their media-buy
179
+ record and pass it to later `emitWebhook` calls; the request context forwards
180
+ it automatically only for deliveries emitted during that request.
181
+
182
+ WBA webhook verification pins the signer to the registered seller origin.
183
+ Registrations requiring legacy delegated-operator resolution or publisher JWS
184
+ pins must select the RFC webhook profile; the SDK rejects that combination
185
+ under WBA. Configure a shared replay store across replicas.
186
+
187
+ ## Seller authorization and durable state
188
+
189
+ Signature verification establishes an origin, never a principal or spend
190
+ permission. Trust evaluation runs at binding, grants, and open onboarding,
191
+ never during cryptographic verification. Wire `signedRequests.webBotAuth` (or
192
+ `verifySignatureAsAuthenticator.webBotAuth`) with a signed directory,
193
+ origin-revocation resolver, and `createIdentity33PrincipalResolver`.
194
+
195
+ ```ts
196
+ import {
197
+ createIdentity33StateStores, TrustEvaluator, OriginIdentityLifecycle,
198
+ SignatureDirectoryResolver, OriginRevocationResolver,
199
+ createIdentity33PrincipalResolver, createIdentity33PrincipalScopeResolver, createIdentity33Authorization,
200
+ withIdentity33PrincipalHandlers,
201
+ } from '@adcp/sdk/identity-3.3';
202
+
203
+ const stores = createIdentity33StateStores({ store: sharedStateStore, tenantId });
204
+ const trust = new TrustEvaluator({ authorityHistory: stores.authorityHistory });
205
+ const lifecycle = new OriginIdentityLifecycle({
206
+ store: stores.identity,
207
+ trust,
208
+ onboarding,
209
+ lookupLegacyPrincipals: app.lookupLegacyPrincipals,
210
+ checkRequirement: app.checkOnboardingRequirement,
211
+ hasBillingRelationship: app.hasBillingRelationship,
212
+ notify: app.publishPrincipalInvalidation,
213
+ });
214
+ // Configure principalRuntime's resolvePrincipal with this mapping. Both its
215
+ // authorization scope and public record id must use the audited binding.
216
+ const resolvePrincipalScope = createIdentity33PrincipalScopeResolver({
217
+ lifecycle, tenantId, legacy: app.resolveLegacyPrincipal,
218
+ });
219
+
220
+ const directory = new SignatureDirectoryResolver();
221
+ const revocations = new OriginRevocationResolver({ directory, store: stores.revocations });
222
+ const authorize = createIdentity33Authorization({
223
+ lifecycle,
224
+ grants: { evaluator: trust, resolveBrandHouse: app.resolveVerifiedBrandHouse },
225
+ resolveClaims: app.resolveAuthorizedAccountClaims, // Read-only account lookup; never provision here.
226
+ });
227
+
228
+ const server = createAdcpServerFromPlatform(platform, {
229
+ ...serverOptions,
230
+ identity33: { authorize },
231
+ protocol: withIdentity33PrincipalHandlers(principalRuntime.protocol, lifecycle),
232
+ signedRequests: {
233
+ ...legacyVerifierOptions,
234
+ assertLegacyOriginAllowed: url => lifecycle.assertLegacyAllowed(url),
235
+ webBotAuth: {
236
+ directory,
237
+ // Revocation and binding run after verification, in the identity layer.
238
+ resolvePrincipal: createIdentity33PrincipalResolver({ lifecycle, revocation: revocations }),
239
+ },
240
+ },
241
+ });
242
+ ```
243
+
244
+ `sharedStateStore` must implement atomic `getWithVersion`/`putIfMatch`; the SDK's
245
+ Postgres store supplies these. Hoist stores outside request factories and bind
246
+ `tenantId` to trusted routing. The adapters retain bindings/audits, operator
247
+ quotas, authoritative trust history, applications/outbox notifications, and
248
+ monotonic revocation facts across restarts. In-memory stores are for development.
249
+ `resolveClaims` runs before account resolution and receives the authenticated server context: for `sync_accounts`,
250
+ return every proposed claim before provisioning; for spend, use the existing
251
+ seller-resolved account's brand/operator/billing/sandbox, never request
252
+ reassignment. Authorization runs before idempotency lookup and handler effects.
253
+ Keep the normal buyer registry's suspension, blocking, sandbox and billing
254
+ gates enabled; grants do not replace them.
255
+
256
+ `bindPrincipal` requires seller audit evidence. Existing RFC mappings require
257
+ explicit migration approval and an unambiguous origin. `sync_principal` may
258
+ create only a new principal under declared open tiers; legacy-ledger lookup is
259
+ mandatory. Quotas apply to the operator domain. PRIVATE PSL origins can open
260
+ sandbox access only. Open agent billing is never automatic; production operator
261
+ or advertiser billing additionally requires the seller's existing billing
262
+ relationship with that billed domain. Unknown requirements remain unsatisfied;
263
+ wrong-direction requirements are ignored, with message/URL fallback for humans.
264
+
265
+ Set the seller's `platform.capabilities.account.agentOnboarding`, supported
266
+ billing and sandbox fields, and declare `account.agent_onboarding` in
267
+ `platform.capabilities.overrides.experimental_features`. Declare request
268
+ profiles through `overrides.request_signing`. Server construction validates
269
+ posture semantics; unbound `get_principal` reads remain `unconfigured` and
270
+ never run the durable principal runtime. Caller-only relationships may exist
271
+ before binding. Notification reasons are `relationship_changed` and
272
+ `relationship_expiring`. Queue state is committed before publish; reuse the
273
+ provided notification ID as the emitter's delivery ID. Call
274
+ `flushRelationshipNotifications` after restart and schedule
275
+ `notifyRelationshipExpiring` with your seller-declared lead time.
276
+
277
+ ## Trust, grants, and revocation
278
+
279
+ The operator is derived using the pinned ICANN+PRIVATE PSL, never a document
280
+ field or authoritative hop host. Trust reads allow one document hop, zero HTTP
281
+ redirects, 2 MiB, depth 32, and no duplicate JSON keys. Exactly one canonical
282
+ origin must carry the required role. Cache lifetime is the configured revocation
283
+ poll interval (60–1800 seconds), negatives at most 60 seconds. Failures are not
284
+ absence. Share authoritative-history state when retaining legacy fallback.
285
+ Fetches to an operator's own hosts are rate-limited per (operator, host);
286
+ `authoritative_location` hops to hosts outside the operator's registrable domain
287
+ share one separate per-host budget. A hop therefore never spends the target
288
+ operator's own budget, and many operators cannot multiply fetches to one host.
289
+ A host-rate refusal is a retryable outage that is not cached as the operator's
290
+ failure.
291
+
292
+ A record that cannot be read (transport error, outage, rate, invalid content)
293
+ raises `TrustRecordUnavailableError`; a current record that does not list the
294
+ origin with the required role raises `TrustMembershipError`. Both extend
295
+ `IdentityAuthorizationError`. For a bound origin:
296
+
297
+ - **Delisted:** the last record read does not list the origin with the role
298
+ (operators retire agents by publishing an empty `agents[]`). The origin is
299
+ identity-established for every request, task polling and cancellation
300
+ included: the principal resolver demotes it to the per-origin anonymous
301
+ scope with no credential and no registry-resolved `ctx.agent`, and it gets
302
+ the anonymous tool policy plus `get_principal` (which reports
303
+ `unconfigured`). The binding is kept: `open` onboarding cannot re-bind it and
304
+ RFC 9421 stays refused for the origin. Spend gets `PERMISSION_DENIED` with no
305
+ details. A known delisting stays a delisting through a later failed refresh.
306
+ - **Unreachable:** a record that cannot be read, including a 404/410 after a
307
+ record was read (or for any bound origin, on every replica), is a discovery
308
+ failure, never a removal; the last record read stays authoritative.
309
+ Spend-committing calls get a retryable `SERVICE_UNAVAILABLE`. As seller
310
+ policy, reads and identity configuration continue under the binding while
311
+ the last record read listed the origin and is within
312
+ `TrustEvaluator({ maxOutageContinuationSeconds })` (default four polling
313
+ intervals) of its freshness; after that nothing is served (`503`).
314
+
315
+ After every signature verifies, authorization outcomes use the standard AdCP
316
+ error envelope, never a 403 with `Accept-Signature`. That includes a principal
317
+ resolver that throws: a transient (or uncoded) error is an outage answered
318
+ `503 SERVICE_UNAVAILABLE` by the server, and any other coded error is
319
+ `PERMISSION_DENIED`, delivered on the tool call (other requests are refused with
320
+ that envelope and no challenge).
321
+
322
+ Demand grants come from the verified brand or house record. Implicit authority
323
+ requires brand, account operator, and signer operator to share a registrable
324
+ domain. Otherwise only a direct grant with the account operator equal to the
325
+ signer, a direct grant from a self-operated brand (the brand is its own account
326
+ operator) to the signer's operator, or a two-link chain through the account
327
+ operator, is accepted. The
328
+ intersection must cover the actual brand IDs, countries, scope, signer-origin
329
+ narrowing and temporal window. A restrictive published grant cannot be
330
+ superseded by seller fallback. A trust 200 disables brand.json authority;
331
+ authoritative absence alone permits explicit legacy policy. An established
332
+ identity lacking a grant gets `PERMISSION_DENIED` with
333
+ `{ scope: 'agent', reason: 'grant_absent' }`. No account or live buy is changed.
334
+ A grantor that once served trust.json and is now unreachable (404/410
335
+ included) never falls back to brand.json `authorized_operators[]`, and it is
336
+ not a grant removal: spend gets a retryable `SERVICE_UNAVAILABLE`.
337
+
338
+ Origin key revocations use `/.well-known/governance-revocations.json`, signed
339
+ with `typ: adcp-gov-revocation+jws`, as ratified R3 specifies. This origin key
340
+ list does not migrate governance-context, designated-task response or rights
341
+ JWS discovery: those retain the RFC chain in 3.3. Polling fails closed, revoked
342
+ keys remain revoked forever, `keyCompromise` cannot be weakened, and the earliest
343
+ `invalidity_date` is retained. Revocation never pauses or cancels committed buys.
344
+
345
+ Permanent revocation storage reserves separate bounded capacity for audited bound
346
+ origins and anonymous/self-service origins, so first-contact traffic cannot exhaust the bound
347
+ pool. Storage failures deny reads and mutations without outage grace; inspect the
348
+ non-enumerable error cause and raise `createIdentity33StateStores.revocationLimits`
349
+ when capacity is exhausted. Existing facts must remain stored. When the shared
350
+ refresh limiter is full (attacker-selected origins can occupy it), an origin
351
+ whose last verified list is still inside `next_update` plus grace keeps that
352
+ status, exactly as if its own fetch had failed; past grace it fails closed.
353
+
354
+ ## Authoring and pinned sources
355
+
356
+ ```sh
357
+ adcp identity trust-validate trust.json
358
+ adcp identity directory --origin https://buyer.example.com \
359
+ --keys private-jwks.json --output directory-response.json
360
+ ```
361
+
362
+ Serve the output's exact body and headers at the directory well-known path.
363
+ Re-run after rotation and before proof expiry. The helper publishes public
364
+ thumbprint keys only; keep the input private key file private. The SDK also
365
+ exports `createSignedSignatureDirectory`, `createTrustRecord`, and
366
+ `validateTrustRecord` for applications. Trust records contain no key discovery.
367
+
368
+ The implementation pins these upstream heads, rather than claiming they are
369
+ released schemas:
370
+
371
+ | PR | Pinned head | Surface |
372
+ | --- | --- | --- |
373
+ | [7894](https://github.com/adcontextprotocol/adcp/pull/7894) | `656bd080f01cc2fca4a1e623af44e96cfd827ba5` | WBA wire profile, profile selectors, directory and request/relay vectors |
374
+ | [8121](https://github.com/adcontextprotocol/adcp/pull/8121) | `f5973ac0267b1b94d714c55fc4e3ad8fc2511350` | Origin identity and key-free trust v1 |
375
+ | [8162](https://github.com/adcontextprotocol/adcp/pull/8162) | `5c9914c5c382cc32f3d2ad7842942e548c414705` | Ratified identity, coexistence, revocation |
376
+ | [8168](https://github.com/adcontextprotocol/adcp/pull/8168) | `45540941dfd61e80ab8a463f780cb147c82a32f0` | Relationship and principal response arms |
377
+ | [8169](https://github.com/adcontextprotocol/adcp/pull/8169) | `3ce6a14d7afaa71fa78ddf2223ed0421e01205ae` | Grants, trust schema, grant_absent |
378
+ | [8170](https://github.com/adcontextprotocol/adcp/pull/8170) | `8d3591e70e9a717c7fdfb513360a796fba24ca9a` | Onboarding additions only; its old trust key fields are excluded |
379
+ | [8177](https://github.com/adcontextprotocol/adcp/pull/8177) | `b663f8e4235fe4276c73fb9bac6db491b2252bbf` | Reporting authentication omission |
380
+
381
+ Ratified R2 defaults replay to 429. Older vector negative/002 expects 403;
382
+ `replayStatus: 403` is an explicit compatibility test option, not the default.
383
+
384
+ Verifier outcomes follow DR-0023 and WBA §5.5/§6.10. `verifyWebBotAuth` needs
385
+ only key discovery and a replay store and returns the verified origins;
386
+ revocation, bindings and the origin-binding fence run afterwards in the
387
+ identity layer (`createIdentity33PrincipalResolver({ lifecycle, revocation })`),
388
+ so verification can run in a CDN or middleware in front of the AdCP server.
389
+
390
+ - Signature-path errors are WBA statuses and headers only: 400 for a field that
391
+ does not parse, 403 with `Accept-Signature` for a signature that does not
392
+ verify, 429 for a replayed nonce. Any AdCP body is the generic authentication
393
+ error (`AUTH_INVALID`); the specific reason is logged, never sent.
394
+ - A key-directory fetch failure (transport error or any non-200, 404/410/5xx
395
+ included) is a discovery failure. It never evicts a cached, unexpired
396
+ directory, which keeps verifying. Without one the request is unverified and
397
+ answered 403 with `Accept-Signature` (the SDK's default unverified-request
398
+ policy). A fetched directory without the key is a signature failure.
399
+ - Plain JWKS directories without Appendix B signatures are accepted, with every
400
+ key checked against its RFC 7638 thumbprint; pass
401
+ `requireSignedDirectories: true` to the resolver to refuse them. An unsigned
402
+ directory keeps verifying through failed refreshes for at most
403
+ `maxUnsignedDirectoryAgeSeconds` (default one day).
404
+ - A revoked key is 403 with the generic authentication error and no
405
+ `Accept-Signature`: the signer must stop using that key. Revocation status
406
+ `unknown` (stale past grace) leaves the identity unverified (403 with
407
+ `Accept-Signature`). An origin that serves no revocation list (`absent`) is
408
+ identity-established and cannot be bound for spend.
409
+ - Replay-store and revocation-history-store failures are infrastructure
410
+ outages, raised as `WebBotAuthUnavailableError`. The server integrations
411
+ answer them at the application layer with 503 `SERVICE_UNAVAILABLE` and
412
+ `Retry-After`, never as a signature outcome.
413
+ - `webBotAuth.isRevoked`, `requireFreshRevocation` and `deferAuthorizationErrors`
414
+ are deprecated. A server needs either a revocation-aware principal resolver or
415
+ the deprecated `isRevoked`, and the webhook receiver either `revocation` or
416
+ `isRevoked`. The deprecated path cannot express "established but not
417
+ bindable", so it refuses an origin that serves no list (unverified).
418
+ - Clients act on the HTTP status and `Accept-Signature`, not the generic body:
419
+ re-sign on 403 with `Accept-Signature`, stop using the key on 403 without it,
420
+ back off on 429 or 503.
421
+ - `@target-uri` and `@authority` are taken from the target URI as received
422
+ (RFC 9421 §2.2.2), never canonicalized; canonical origins identify the signer
423
+ only. Default nonces are 64 bytes (draft §4.2). Ed25519, ECDSA P-256 and
424
+ RSA-PSS-SHA512 keys are supported. `test/fixtures/wba-interop/` holds fixtures
425
+ verified in both directions against Cloudflare's `web-bot-auth`.
426
+ Older #7894 governance vectors propose a superseded migration and are retained
427
+ with their non-applicability recorded in `test/fixtures/wba-profile/PINNED.json`.
428
+ The buyer default onboarding field is `profiles.adcp.onboarding`, matching the
429
+ schema; the design's `record_profiles` wording names the schema definition.
430
+
431
+ Process-local authority history is bounded and never evicts remembered operators. Public deployments must supply `authorityHistory` from the shared state stores so history survives restarts and cache eviction. See [Public deployment limits](#public-deployment-limits) for admission and legacy-fallback behavior.
432
+
433
+ Open `sync_principal` commits the newly approved origin binding before the caller notification-configuration handler runs. A later configuration failure does not undo that binding; retry applies configuration to the same principal. This allocation never grants spend authority: every mutating request still passes tier, relationship and grant checks before provisioning or idempotency.
434
+
435
+ `resolveClaims` must perform its own read-only lookup of the existing seller account; `ctx.account` is unset because authorization precedes account resolution and provisioning. Always use `createIdentity33PrincipalResolver` with this authorization hook so verified WBA requests carry the protected identity claim.
436
+
437
+ Before enabling persisted webhook profile selection, rerun `getWebhookRegistrationMigration()` against existing PostgreSQL registration tables. It adds the optional `signing_profile` and `delivery_kind` columns; existing NULL rows retain the RFC verifier and their existing provenance. Redis and memory records preserve the optional fields directly.
438
+
439
+ Reusing a reporting or artifact URL extends its matching registration's expiry.
440
+ Use a new callback URL when changing its signing profile while old deliveries are
441
+ still outstanding. A live URL's verifier remains immutable; changing it requires
442
+ explicitly deleting the old registration, which also stops accepting old deliveries.
443
+
444
+ Compute the deletion key with `deliveryWebhookRegistrationId` from
445
+ `@adcp/sdk/identity-3.3`, then call
446
+ `store.delete(agentId, deliveryWebhookRegistrationId('reporting', callbackUrl))`.
447
+
448
+ The standard principal resolver automatically fences RFC signatures for already-bound origins. Custom resolvers must supply `assertLegacyOriginAllowed`; legacy keys must resolve an unambiguous agent origin. Preserve an existing operator principal during approved migration by passing `principalKind: "operator"` to `bindPrincipal`. WBA authenticators enforce signature presence and must use `requireSignatureWhenPresent` for bearer coexistence.
449
+
450
+ Signing capabilities include the experimental `wba_draft_revision` field next to `profiles`, identifying `draft-ietf-webbotauth-httpsig-protocol-00` as required by ratified R2. Reporting and artifact callback choices are persisted by destination before dispatch, including update calls; their receivers pass the trusted request URL and `taskType` (`media_buy_delivery` or `artifact_delivery`) to `verifyAndParseWebhook`. These deliveries preserve the original payload in `result` after authentication and schema validation; `envelope` adds SDK routing/status metadata. PostgreSQL migrations also add optional `delivery_kind`.
451
+
452
+ Revocation stores allocate no permanent row for an empty list. Each audited/unbound pool reserves a tenant-wide CAS budget (10,000 origins and 100,000 keys; each operator is limited to 256 origins and 16,384 keys per pool). Audited bindings promote existing facts without deleting them; self-service `openAccess` bindings stay in the unbound pool. Failed writes may conservatively reserve capacity; facts are never evicted to regain it. Store/quota failures return `SERVICE_UNAVAILABLE` for every operation. In-memory revocation storage is for development/tests and is bounded per origin, per operator (registrable domain, default 16,384 keys) and in total, so wildcard subdomains of one operator cannot fill it alone (several operators still can, and a refused merge fails closed); production sellers use shared persistent stores.
453
+
454
+ Unbound callers use an internal per-origin anonymous scope to isolate task/proposal state; this is not a durable principal and is never returned by `get_principal`. Only the explicit anonymous tool policy is allowed.
455
+
456
+ ### Public deployment limits
457
+
458
+ - **Durable authority history is required for public deployments.** Without
459
+ `authorityHistory`, the trust evaluator remembers which operators have served
460
+ a trust record only in process memory. Nothing is evicted, so no operator's
461
+ legacy `authorized_operators[]` fallback changes because of others, but the
462
+ memory is bounded: `maxEntries` (default 1,000) in total, at most half of
463
+ that (`maxPrivateAuthoritativeOperators`) for PSL PRIVATE-section names, and
464
+ `maxAuthoritativeOperatorsPerPrivateSuffix` (default 32) per hosting provider
465
+ (the provider's ICANN registrable domain, so every `*.vercel.app`,
466
+ `*.s3.<region>.amazonaws.com` or `*.<project>.platformsh.site` operator
467
+ shares one budget). An operator over budget cannot have its trust record
468
+ accepted in that process: 32 subdomains under one provider block later operators on that
469
+ provider, and a full `maxEntries` refuses every new trust record publisher.
470
+ When an operator fits its budget, a history slot is reserved on any 200,
471
+ before the body is validated, so a removed or invalid record still prevents
472
+ a legacy downgrade for that remembered operator. An operator refused for
473
+ lack of budget is not remembered: its trust record remains unavailable,
474
+ but a later 404/410 is treated as absence and may invoke explicit legacy
475
+ authorization, as after a process restart. With durable `authorityHistory`,
476
+ every 200 is recorded, the in-memory set is only a cache, and none of these
477
+ admission limits refuse records.
478
+ - **The unbound revocation pool can fill.** With the default CAS limits
479
+ (100,000 keys per pool, 16,384 per operator), about seven registrable domains,
480
+ including free PSL PRIVATE-section names, can exhaust the unbound pool. New
481
+ unbound origins with revoked keys then fail closed with `SERVICE_UNAVAILABLE`
482
+ until capacity is raised; the bound pool is unaffected.
483
+ - **Delisted origins have no exception.** A bound origin whose operator
484
+ delists it is identity-established for every request, including polling and
485
+ cancelling tasks it created while it was listed.
486
+ - **Duplicate structured-field keys are rejected.** Signature-Input,
487
+ Signature and Signature-Agent with a duplicated dictionary member or a
488
+ duplicated parameter (for example `created=1;created=2`) are malformed: 400
489
+ under Web Bot Auth, `request_signature_header_malformed` under RFC 9421. RFC
490
+ 8941 parsers keep the last value, which other implementations may not.
491
+ - **`createExpressVerifier` does not implement Web Bot Auth.** It answers a
492
+ request carrying `Signature-Agent` or the `web-bot-auth` tag with 403 (no
493
+ challenge) instead of verifying it under RFC 9421. Use `createAdcpServer`
494
+ `signedRequests.webBotAuth` or `verifySignatureAsAuthenticator({ webBotAuth })`.
@@ -40,6 +40,11 @@ disable it. Set `legacyWebhookFallback: false` on a standalone brand resolver to
40
40
  `ResolvedAgentJwksResolver` requires explicitly enabling the fallback for webhook use.
41
41
  Wrappers shared with request verification must forward `resolveWithMetadata`
42
42
  so the verifier can refuse webhook-only fallback keys.
43
+ The [agent identity foundations note](./migration-agent-identity-3.3.md)
44
+ describes canonical origins and the optional signer-origin lookup argument;
45
+ wrappers must forward that argument on both resolver methods as well.
46
+ Origin consistency comparisons now remove one trailing DNS root dot and
47
+ reject malformed authorities instead of accepting URL-parser repairs.
43
48
 
44
49
  Capabilities discovery defaults to MCP. A2A integrations using
45
50
  `BrandJsonJwksResolver` must set `protocol: 'a2a'`; the onboarding record does
@@ -0,0 +1,137 @@
1
+ # Breaking: reporting row storage field alignment
2
+
3
+ Reliable Reporting row storage now stores every value in the format AdCP
4
+ already defines for it, and `{period_date}` is the period's calendar date in its
5
+ `source_timezone` instead of UTC. This is one deliberate breaking change, made
6
+ before any deployment activated row storage in production. It ships in the
7
+ 15.9.0 release.
8
+
9
+ Affected: anyone who applied `REPORTING_ROW_STORAGE_MIGRATION`, configured
10
+ `rowStorage`, or wrote a custom `ReportingRowObjectProviderV1`. Not affected:
11
+ the wire (`revision_content_sha256` and every other buyer-visible value is
12
+ unchanged), PostgreSQL-kind row storage behavior, and anyone who never installed
13
+ the row-storage tables.
14
+
15
+ ## Upgrading
16
+
17
+ Apply the new `REPORTING_ROW_STORAGE_MIGRATION` before starting any binary that
18
+ contains this change, and stop older writers first: they read the old column
19
+ names and fail against the renamed tables. A new binary refuses to start row
20
+ storage against an un-migrated database (`probeReportingRowStorageSchemaV1`
21
+ names the missing columns). The migration takes a brief exclusive lock on the
22
+ row-storage tables, so apply it in a maintenance window. It is idempotent,
23
+ serialized by an advisory lock so concurrent appliers cannot race, runs on a
24
+ fresh install, and on an installed database it:
25
+
26
+ - renames the columns listed below in place, keeping every recorded location;
27
+ - replaces `encoding` with `format` and `algorithm`, backfilled to `jsonl` and
28
+ `adcp_jcs_rows_v1` (the old column admitted exactly one value);
29
+ - adds the AdCP length checks (a database that already holds an out-of-bounds
30
+ key fails the migration with a message naming the count, and rolls back);
31
+ - rewrites open write intents' `created_objects` from `objectKey` /
32
+ `nativeVersion` to `object_ref` / `native_version_ref`.
33
+
34
+ If you installed the row-storage tables but never activated them, the in-place
35
+ migration is enough: there is nothing to preserve. Dropping the tables to start
36
+ clean also works, but it discards `adcp_persistence_installation`, so the new
37
+ installation ID changes every binding's `namespace_key` and with it the object
38
+ key prefix. Do not drop tables that contain row sets.
39
+
40
+ The migration does not rewrite object keys. Objects written before the upgrade
41
+ keep the key recorded in `object_ref`, rendered under the old UTC rule with a
42
+ `yyyy/MM/dd` layout. Reads, retention and deletes use the recorded key, so they
43
+ keep working. New writes render the new key, so a period re-written after the
44
+ upgrade may sit at a different key than its earlier objects, and an upload that
45
+ was in flight across the upgrade can leave its old-key object behind. Re-sync
46
+ instead of upgrading in place if you want every object under the new layout.
47
+
48
+ ## Object key templates require `{revision_key}`
49
+
50
+ Every writable object binding's `keyTemplate` must now include
51
+ `{revision_key}`, not only when snapshot compaction is on, so no two row sets
52
+ can ever name the same object key. The default template already includes it.
53
+ The store throws `INVALID_INPUT` when a binding is configured and again in
54
+ `readyRowStorage` if a template omits it. A custom template without it must
55
+ add it, under a new binding ID (a binding's identity digest includes its
56
+ template).
57
+
58
+ Objects already written stay readable: reads use each chunk's recorded
59
+ `object_ref`, not a re-rendered key. Keep the old binding definition
60
+ configured while revisions reference it, and mark it `readOnly: true`; a
61
+ read-only binding is exempt from the requirement, is never chosen for new
62
+ writes, and is still used for reads and retirement (`readyRowStorage` still
63
+ probes it, so keep its location reachable). Compaction ignores read-only
64
+ bindings, because nothing can adopt through them. The
65
+ reference-checked deletes and the per-object lock are unchanged, because
66
+ header-only revisions still share chunks within an obligation.
67
+
68
+ ## Renamed fields
69
+
70
+ | Before | After | AdCP definition |
71
+ | ----------------------------------------------- | ------------------------------------------- | --------------------------------------------------------- |
72
+ | `adcp_reporting_row_chunks.object_key` | `object_ref` (1 to 1024 characters) | `reporting-file-object-ref.json` |
73
+ | `adcp_reporting_row_chunks.native_version` | `native_version_ref` (1 to 1024 characters) | `reporting-native-version-ref.json` |
74
+ | `adcp_reporting_row_chunks.physical_byte_count` | `size_bytes` | `reporting-file-entry.json` `size_bytes`: stored size |
75
+ | `adcp_reporting_row_chunks.byte_count` | `canonical_size_bytes` | uncompressed canonical bytes; the digest-pinned manifest |
76
+ | `adcp_reporting_row_sets.canonical_byte_count` | `content_size_bytes` | size of the content `content_sha256` covers (the binding's byte count) |
77
+ | `adcp_reporting_row_sets.encoding` | `format` = `jsonl`, `algorithm` = `adcp_jcs_rows_v1` | `reporting-file-manifest.json` `format`, `reporting-canonicalization-contract.json` `algorithm` |
78
+
79
+ `size_bytes` means what it means in the AdCP file manifest: the size of the
80
+ stored object, after compression. The uncompressed canonical size is a separate
81
+ value because chunk and segment digests, byte ranges and the binding verify
82
+ against it. A row set's `content_size_bytes` is a third quantity: the byte count of
83
+ the content `content_sha256` digests, which for a revision includes the
84
+ envelope, so it is not the sum of its chunks' `canonical_size_bytes`. Manifest JSON field names (`byte_count`, `byte_offset`) are
85
+ digest-pinned and did not change.
86
+
87
+ TypeScript and provider API:
88
+
89
+ - `ReportingRowChunkLocatorV1`: `objectKey` is `objectRef`, `nativeVersion` is
90
+ `nativeVersionRef`, `physicalByteCount` is `sizeBytes`.
91
+ - `ReportingRowObjectProviderV1`: inputs take `objectRef` (was `key`) and
92
+ `nativeVersionRef` (was `nativeVersion`); `putIfAbsent` returns
93
+ `{ created, nativeVersionRef }`. Add the optional
94
+ `stat({ objectRef, nativeVersionRef })` returning
95
+ `{ nativeVersionRef, sizeBytes }` (the version it resolved, which must equal the
96
+ one asked for, and the stored size) or `null`.
97
+ The commit transaction uses it to prove an adopted object unchanged without
98
+ re-downloading it under the account lock; a provider without `stat` falls back
99
+ to the full read. Every bundled provider implements it, and
100
+ `runReportingRowObjectProviderConformanceV1` checks it (new
101
+ `version-pinned-stat` entry).
102
+ - `ReportingRowBindingSelectionInputV1.canonical_byte_count` is
103
+ `content_size_bytes`; `ReportingRowSetHandleV1.canonicalByteCount` is
104
+ `contentSizeBytes`.
105
+ - `ReportingRowSetPrepareInputV1` takes `sourceTimezone` next to `periodStart`;
106
+ a `periodStart` without a usable `sourceTimezone` fails with `INVALID_INPUT`.
107
+ - `REPORTING_ROW_ENCODING_V1` is replaced by `REPORTING_ROW_FORMAT_V1`
108
+ (`jsonl`) and `REPORTING_ROW_ALGORITHM_V1` (`adcp_jcs_rows_v1`);
109
+ `encodeReportingRowsV1` returns `format` and `algorithm` instead of `encoding`.
110
+
111
+ ## `{period_date}`
112
+
113
+ The placeholder name is unchanged. It now renders AdCP's `YYYY-MM-DD`: the
114
+ calendar date of the period start in the period's `source_timezone`, as one path
115
+ segment. A period starting `2026-10-02T07:00:00Z` in `America/Los_Angeles` is
116
+ `2026-10-02`; one starting `2026-10-01T15:00:00Z` in `Asia/Tokyo` is also
117
+ `2026-10-02`. The old rendering used the UTC date and split it into
118
+ `yyyy/MM/dd` directories. A missing, unknown or non-IANA timezone fails the
119
+ write rather than guessing a date. The default key template string did not
120
+ change, so existing binding identities remain valid.
121
+
122
+ If you built tooling that lists objects by `yyyy/MM/dd` directory, list by the
123
+ single `YYYY-MM-DD` segment, or read the recorded `object_ref` from
124
+ `adcp_reporting_row_chunks`.
125
+
126
+ ## Digests
127
+
128
+ `adcp_jcs_rows_v1` names the per-row RFC 8785 canonicalization the stored rows
129
+ use. A revision's `content_sha256` is still the envelope digest
130
+ (`revision_envelope_v1`), not AdCP's array-shaped content digest; only an
131
+ adjustment's `rows_v1` digest has that shape. The format and algorithm tokens
132
+ label the encoding; they are not an input to any
133
+ chunk, segment, manifest or protocol digest. No digest changed. The shared
134
+ golden fixture `test/fixtures/reporting-row-storage-v1.json` replaced its
135
+ top-level `encoding` label with `format` and `algorithm`; every expected digest
136
+ and byte count is identical. Other SDKs sharing the fixture must adopt the new
137
+ labels and storage names but reproduce the same bytes.