@adcp/sdk 15.9.0 → 16.0.0-beta.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (295) 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 +16 -2
  12. package/dist/lib/core/SingleAgentClient.d.ts +16 -2
  13. package/dist/lib/core/SingleAgentClient.js +259 -62
  14. package/dist/lib/core/SingleAgentClient.mjs +261 -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/index.d.mts +10 -0
  28. package/dist/lib/identity-3.3/index.d.ts +10 -0
  29. package/dist/lib/identity-3.3/index.js +75 -0
  30. package/dist/lib/identity-3.3/index.mjs +46 -0
  31. package/dist/lib/identity-3.3/lifecycle.d.mts +113 -0
  32. package/dist/lib/identity-3.3/lifecycle.d.ts +113 -0
  33. package/dist/lib/identity-3.3/lifecycle.js +267 -0
  34. package/dist/lib/identity-3.3/lifecycle.mjs +240 -0
  35. package/dist/lib/identity-3.3/revocation.d.mts +50 -0
  36. package/dist/lib/identity-3.3/revocation.d.ts +50 -0
  37. package/dist/lib/identity-3.3/revocation.js +238 -0
  38. package/dist/lib/identity-3.3/revocation.mjs +216 -0
  39. package/dist/lib/identity-3.3/schemas.draft.d.mts +2472 -0
  40. package/dist/lib/identity-3.3/schemas.draft.d.ts +2472 -0
  41. package/dist/lib/identity-3.3/schemas.draft.js +1448 -0
  42. package/dist/lib/identity-3.3/schemas.draft.mjs +1428 -0
  43. package/dist/lib/identity-3.3/server.d.mts +34 -0
  44. package/dist/lib/identity-3.3/server.d.ts +34 -0
  45. package/dist/lib/identity-3.3/server.js +219 -0
  46. package/dist/lib/identity-3.3/server.mjs +194 -0
  47. package/dist/lib/identity-3.3/store.d.mts +24 -0
  48. package/dist/lib/identity-3.3/store.d.ts +24 -0
  49. package/dist/lib/identity-3.3/store.js +191 -0
  50. package/dist/lib/identity-3.3/store.mjs +169 -0
  51. package/dist/lib/identity-3.3/trust.d.mts +94 -0
  52. package/dist/lib/identity-3.3/trust.d.ts +94 -0
  53. package/dist/lib/identity-3.3/trust.js +278 -0
  54. package/dist/lib/identity-3.3/trust.mjs +239 -0
  55. package/dist/lib/identity-3.3/types.d.mts +127 -0
  56. package/dist/lib/identity-3.3/types.d.ts +127 -0
  57. package/dist/lib/identity-3.3/types.js +16 -0
  58. package/dist/lib/identity-3.3/types.mjs +0 -0
  59. package/dist/lib/identity-3.3/validation.d.mts +2 -0
  60. package/dist/lib/identity-3.3/validation.d.ts +2 -0
  61. package/dist/lib/identity-3.3/validation.js +125 -0
  62. package/dist/lib/identity-3.3/validation.mjs +91 -0
  63. package/dist/lib/index.d.mts +1 -1
  64. package/dist/lib/index.d.ts +1 -1
  65. package/dist/lib/reporting/azure/index.d.mts +5 -0
  66. package/dist/lib/reporting/azure/index.d.ts +5 -0
  67. package/dist/lib/reporting/azure/index.js +26 -7
  68. package/dist/lib/reporting/azure/index.mjs +26 -7
  69. package/dist/lib/reporting/bigquery/index.d.mts +80 -25
  70. package/dist/lib/reporting/bigquery/index.d.ts +80 -25
  71. package/dist/lib/reporting/bigquery/index.js +184 -81
  72. package/dist/lib/reporting/bigquery/index.mjs +182 -80
  73. package/dist/lib/reporting/gcs/adapter.d.mts +8 -1
  74. package/dist/lib/reporting/gcs/adapter.d.ts +8 -1
  75. package/dist/lib/reporting/gcs/errors.d.mts +6 -0
  76. package/dist/lib/reporting/gcs/errors.d.ts +6 -0
  77. package/dist/lib/reporting/gcs/fence.d.mts +5 -0
  78. package/dist/lib/reporting/gcs/fence.d.ts +5 -0
  79. package/dist/lib/reporting/gcs/index.d.mts +9 -0
  80. package/dist/lib/reporting/gcs/index.d.ts +9 -0
  81. package/dist/lib/reporting/gcs/reader.d.mts +27 -3
  82. package/dist/lib/reporting/gcs/reader.d.ts +27 -3
  83. package/dist/lib/reporting/gcs/row-provider.d.mts +7 -0
  84. package/dist/lib/reporting/gcs/row-provider.d.ts +7 -0
  85. package/dist/lib/reporting/gcs/row-provider.js +34 -14
  86. package/dist/lib/reporting/gcs/row-provider.mjs +34 -14
  87. package/dist/lib/reporting/ledger/change-feed.d.mts +22 -1
  88. package/dist/lib/reporting/ledger/change-feed.d.ts +22 -1
  89. package/dist/lib/reporting/ledger/index.d.mts +11 -0
  90. package/dist/lib/reporting/ledger/index.d.ts +11 -0
  91. package/dist/lib/reporting/ledger/managed-postgres.d.mts +8 -0
  92. package/dist/lib/reporting/ledger/managed-postgres.d.ts +8 -0
  93. package/dist/lib/reporting/ledger/managed-router.d.mts +27 -2
  94. package/dist/lib/reporting/ledger/managed-router.d.ts +27 -2
  95. package/dist/lib/reporting/ledger/managed.d.mts +86 -6
  96. package/dist/lib/reporting/ledger/managed.d.ts +86 -6
  97. package/dist/lib/reporting/ledger/notification-activity.d.mts +65 -3
  98. package/dist/lib/reporting/ledger/notification-activity.d.ts +65 -3
  99. package/dist/lib/reporting/ledger/object-writes.d.mts +64 -5
  100. package/dist/lib/reporting/ledger/object-writes.d.ts +64 -5
  101. package/dist/lib/reporting/ledger/postgres.d.mts +43 -9
  102. package/dist/lib/reporting/ledger/postgres.d.ts +43 -9
  103. package/dist/lib/reporting/ledger/postgres.js +43 -27
  104. package/dist/lib/reporting/ledger/postgres.mjs +43 -27
  105. package/dist/lib/reporting/ledger/row-encoding.d.mts +92 -6
  106. package/dist/lib/reporting/ledger/row-encoding.d.ts +92 -6
  107. package/dist/lib/reporting/ledger/row-encoding.js +8 -4
  108. package/dist/lib/reporting/ledger/row-encoding.mjs +6 -3
  109. package/dist/lib/reporting/ledger/row-storage-errors.d.mts +11 -1
  110. package/dist/lib/reporting/ledger/row-storage-errors.d.ts +11 -1
  111. package/dist/lib/reporting/ledger/row-storage-migration.d.mts +19 -1
  112. package/dist/lib/reporting/ledger/row-storage-migration.d.ts +19 -1
  113. package/dist/lib/reporting/ledger/row-storage-migration.js +133 -18
  114. package/dist/lib/reporting/ledger/row-storage-migration.mjs +133 -18
  115. package/dist/lib/reporting/ledger/row-storage-object.d.mts +103 -12
  116. package/dist/lib/reporting/ledger/row-storage-object.d.ts +103 -12
  117. package/dist/lib/reporting/ledger/row-storage-object.js +106 -31
  118. package/dist/lib/reporting/ledger/row-storage-object.mjs +104 -31
  119. package/dist/lib/reporting/ledger/row-storage.d.mts +87 -20
  120. package/dist/lib/reporting/ledger/row-storage.d.ts +87 -20
  121. package/dist/lib/reporting/ledger/row-storage.js +126 -66
  122. package/dist/lib/reporting/ledger/row-storage.mjs +129 -67
  123. package/dist/lib/reporting/ledger/schedule.d.mts +13 -0
  124. package/dist/lib/reporting/ledger/schedule.d.ts +13 -0
  125. package/dist/lib/reporting/ledger/schedule.js +24 -0
  126. package/dist/lib/reporting/ledger/schedule.mjs +23 -0
  127. package/dist/lib/reporting/ledger/types.d.mts +23 -1
  128. package/dist/lib/reporting/ledger/types.d.ts +23 -1
  129. package/dist/lib/reporting/s3/index.d.mts +5 -0
  130. package/dist/lib/reporting/s3/index.d.ts +5 -0
  131. package/dist/lib/reporting/s3/index.js +37 -14
  132. package/dist/lib/reporting/s3/index.mjs +37 -14
  133. package/dist/lib/reporting/service/index.d.mts +10 -0
  134. package/dist/lib/reporting/service/index.d.ts +10 -0
  135. package/dist/lib/reporting/service/maintenance.d.mts +28 -2
  136. package/dist/lib/reporting/service/maintenance.d.ts +28 -2
  137. package/dist/lib/schemas-data/v2.5/_provenance.json +1 -1
  138. package/dist/lib/server/account-sync-contract.d.mts +14 -0
  139. package/dist/lib/server/account-sync-contract.d.ts +14 -0
  140. package/dist/lib/server/account-sync-contract.js +225 -0
  141. package/dist/lib/server/account-sync-contract.mjs +197 -0
  142. package/dist/lib/server/adcp-server.js +5 -0
  143. package/dist/lib/server/adcp-server.mjs +10 -0
  144. package/dist/lib/server/auth-signature.d.mts +10 -0
  145. package/dist/lib/server/auth-signature.d.ts +10 -0
  146. package/dist/lib/server/auth-signature.js +61 -2
  147. package/dist/lib/server/auth-signature.mjs +65 -2
  148. package/dist/lib/server/auth.d.mts +6 -0
  149. package/dist/lib/server/auth.d.ts +6 -0
  150. package/dist/lib/server/auth.js +6 -0
  151. package/dist/lib/server/auth.mjs +6 -0
  152. package/dist/lib/server/create-adcp-server.d.mts +19 -5
  153. package/dist/lib/server/create-adcp-server.d.ts +19 -5
  154. package/dist/lib/server/create-adcp-server.js +238 -19
  155. package/dist/lib/server/create-adcp-server.mjs +240 -10
  156. package/dist/lib/server/decisioning/account.d.mts +24 -1
  157. package/dist/lib/server/decisioning/account.d.ts +24 -1
  158. package/dist/lib/server/decisioning/index.d.mts +1 -1
  159. package/dist/lib/server/decisioning/index.d.ts +1 -1
  160. package/dist/lib/server/decisioning/runtime/from-platform.d.mts +0 -50
  161. package/dist/lib/server/decisioning/runtime/from-platform.d.ts +0 -50
  162. package/dist/lib/server/decisioning/runtime/from-platform.js +61 -11
  163. package/dist/lib/server/decisioning/runtime/from-platform.mjs +65 -12
  164. package/dist/lib/server/index.d.mts +2 -0
  165. package/dist/lib/server/index.d.ts +2 -0
  166. package/dist/lib/server/index.js +12 -0
  167. package/dist/lib/server/index.mjs +12 -0
  168. package/dist/lib/server/notification-subscriptions/runtime.js +9 -1
  169. package/dist/lib/server/notification-subscriptions/runtime.mjs +9 -1
  170. package/dist/lib/server/notification-subscriptions/types.d.mts +5 -0
  171. package/dist/lib/server/notification-subscriptions/types.d.ts +5 -0
  172. package/dist/lib/server/principal/types.d.mts +1 -1
  173. package/dist/lib/server/principal/types.d.ts +1 -1
  174. package/dist/lib/server/serve.js +5 -0
  175. package/dist/lib/server/serve.mjs +5 -0
  176. package/dist/lib/server/webhook-delivery/recovery.d.mts +1 -0
  177. package/dist/lib/server/webhook-delivery/recovery.d.ts +1 -0
  178. package/dist/lib/server/webhook-delivery/recovery.js +4 -0
  179. package/dist/lib/server/webhook-delivery/recovery.mjs +4 -0
  180. package/dist/lib/server/webhook-emitter.d.mts +10 -0
  181. package/dist/lib/server/webhook-emitter.d.ts +10 -0
  182. package/dist/lib/server/webhook-emitter.js +22 -0
  183. package/dist/lib/server/webhook-emitter.mjs +22 -0
  184. package/dist/lib/signing/agent-context.d.mts +0 -5
  185. package/dist/lib/signing/agent-context.d.ts +0 -5
  186. package/dist/lib/signing/agent-context.js +9 -1
  187. package/dist/lib/signing/agent-context.mjs +9 -1
  188. package/dist/lib/signing/agent-fetch.js +27 -2
  189. package/dist/lib/signing/agent-fetch.mjs +32 -2
  190. package/dist/lib/signing/agent-resolver/canonicalize.d.mts +10 -15
  191. package/dist/lib/signing/agent-resolver/canonicalize.d.ts +10 -15
  192. package/dist/lib/signing/agent-resolver/canonicalize.js +17 -5
  193. package/dist/lib/signing/agent-resolver/canonicalize.mjs +16 -5
  194. package/dist/lib/signing/agent-resolver/index.d.mts +1 -0
  195. package/dist/lib/signing/agent-resolver/index.d.ts +1 -0
  196. package/dist/lib/signing/agent-resolver/index.js +5 -0
  197. package/dist/lib/signing/agent-resolver/index.mjs +3 -0
  198. package/dist/lib/signing/agent-resolver/resolved-agent-jwks.d.mts +3 -2
  199. package/dist/lib/signing/agent-resolver/resolved-agent-jwks.d.ts +3 -2
  200. package/dist/lib/signing/agent-resolver/resolved-agent-jwks.js +30 -3
  201. package/dist/lib/signing/agent-resolver/resolved-agent-jwks.mjs +30 -3
  202. package/dist/lib/signing/agent-resolver/strict-json.d.mts +2 -2
  203. package/dist/lib/signing/agent-resolver/strict-json.d.ts +2 -2
  204. package/dist/lib/signing/agent-resolver/strict-json.js +5 -3
  205. package/dist/lib/signing/agent-resolver/strict-json.mjs +5 -3
  206. package/dist/lib/signing/brand-jwks.d.mts +2 -2
  207. package/dist/lib/signing/brand-jwks.d.ts +2 -2
  208. package/dist/lib/signing/brand-jwks.js +4 -4
  209. package/dist/lib/signing/brand-jwks.mjs +4 -4
  210. package/dist/lib/signing/client.d.mts +1 -0
  211. package/dist/lib/signing/client.d.ts +1 -0
  212. package/dist/lib/signing/client.js +5 -0
  213. package/dist/lib/signing/client.mjs +3 -0
  214. package/dist/lib/signing/jwks-https.d.mts +1 -1
  215. package/dist/lib/signing/jwks-https.d.ts +1 -1
  216. package/dist/lib/signing/jwks-https.js +1 -1
  217. package/dist/lib/signing/jwks-https.mjs +1 -1
  218. package/dist/lib/signing/jwks.d.mts +11 -3
  219. package/dist/lib/signing/jwks.d.ts +11 -3
  220. package/dist/lib/signing/jwks.js +1 -1
  221. package/dist/lib/signing/jwks.mjs +1 -1
  222. package/dist/lib/signing/parser.d.mts +1 -1
  223. package/dist/lib/signing/parser.d.ts +1 -1
  224. package/dist/lib/signing/parser.js +5 -3
  225. package/dist/lib/signing/parser.mjs +6 -4
  226. package/dist/lib/signing/revocation.d.mts +4 -1
  227. package/dist/lib/signing/revocation.d.ts +4 -1
  228. package/dist/lib/signing/revocation.js +33 -3
  229. package/dist/lib/signing/revocation.mjs +31 -2
  230. package/dist/lib/signing/server.d.mts +1 -1
  231. package/dist/lib/signing/server.d.ts +1 -1
  232. package/dist/lib/signing/server.js +4 -0
  233. package/dist/lib/signing/server.mjs +4 -0
  234. package/dist/lib/signing/types.d.mts +3 -0
  235. package/dist/lib/signing/types.d.ts +3 -0
  236. package/dist/lib/signing/web-bot-auth.d.mts +117 -0
  237. package/dist/lib/signing/web-bot-auth.d.ts +117 -0
  238. package/dist/lib/signing/web-bot-auth.js +660 -0
  239. package/dist/lib/signing/web-bot-auth.mjs +624 -0
  240. package/dist/lib/testing/client.d.mts +1 -4
  241. package/dist/lib/testing/client.d.ts +1 -4
  242. package/dist/lib/testing/client.js +141 -20
  243. package/dist/lib/testing/client.mjs +137 -19
  244. package/dist/lib/testing/compliance/comply.js +29 -10
  245. package/dist/lib/testing/compliance/comply.mjs +37 -11
  246. package/dist/lib/testing/storyboard/account-sync-contract.d.mts +3 -0
  247. package/dist/lib/testing/storyboard/account-sync-contract.d.ts +3 -0
  248. package/dist/lib/testing/storyboard/account-sync-contract.js +79 -0
  249. package/dist/lib/testing/storyboard/account-sync-contract.mjs +55 -0
  250. package/dist/lib/testing/storyboard/default-invariants.js +2 -0
  251. package/dist/lib/testing/storyboard/default-invariants.mjs +2 -0
  252. package/dist/lib/testing/storyboard/runner.js +23 -8
  253. package/dist/lib/testing/storyboard/runner.mjs +24 -8
  254. package/dist/lib/testing/storyboard/validations.d.mts +1 -1
  255. package/dist/lib/testing/storyboard/validations.d.ts +1 -1
  256. package/dist/lib/types/adcp.d.mts +4 -0
  257. package/dist/lib/types/adcp.d.ts +4 -0
  258. package/dist/lib/types/schemas.generated.d.ts +6 -6
  259. package/dist/lib/utils/capabilities.d.mts +1 -0
  260. package/dist/lib/utils/capabilities.d.ts +1 -0
  261. package/dist/lib/utils/capabilities.js +5 -0
  262. package/dist/lib/utils/capabilities.mjs +5 -0
  263. package/dist/lib/v2/projection/creative-delivery.d.mts +3 -1
  264. package/dist/lib/v2/projection/creative-delivery.d.ts +3 -1
  265. package/dist/lib/v2/projection/creative-delivery.js +26 -10
  266. package/dist/lib/v2/projection/creative-delivery.mjs +26 -10
  267. package/dist/lib/v2/projection/index.d.mts +1 -1
  268. package/dist/lib/v2/projection/index.d.ts +1 -1
  269. package/dist/lib/v2/projection/legacy-routes.d.mts +24 -2
  270. package/dist/lib/v2/projection/legacy-routes.d.ts +24 -2
  271. package/dist/lib/v2/projection/legacy-routes.js +28 -2
  272. package/dist/lib/v2/projection/legacy-routes.mjs +26 -2
  273. package/dist/lib/validation/schema-loader.d.mts +2 -0
  274. package/dist/lib/validation/schema-loader.d.ts +2 -0
  275. package/dist/lib/validation/schema-loader.js +43 -4
  276. package/dist/lib/validation/schema-loader.mjs +39 -3
  277. package/dist/lib/version.d.mts +3 -3
  278. package/dist/lib/version.d.ts +3 -3
  279. package/dist/lib/version.js +3 -3
  280. package/dist/lib/version.mjs +3 -3
  281. package/docs/TYPE-SUMMARY.md +2 -2
  282. package/docs/guides/DISCOVERY-CACHE-AND-SESSION-REUSE.md +4 -0
  283. package/docs/guides/REPORTING-LEDGER-CUTOVER.md +1 -1
  284. package/docs/guides/REPORTING-LEDGER.md +132 -46
  285. package/docs/guides/REPORTING-OPERATIONS.md +25 -4
  286. package/docs/guides/REPORTING-STABILITY.md +76 -0
  287. package/docs/guides/account-resolution.md +101 -0
  288. package/docs/llms.txt +3 -2
  289. package/docs/migration-12-to-13.md +7 -0
  290. package/docs/migration-14.x-rc-worksheet.md +4 -4
  291. package/docs/migration-agent-identity-3.3.md +355 -0
  292. package/docs/migration-agent-resolution-3.3.md +5 -0
  293. package/docs/migration-reporting-row-storage-alignment.md +137 -0
  294. package/examples/storyboards/account-sync-contract.yaml +57 -0
  295. package/package.json +15 -1
@@ -1,7 +1,7 @@
1
1
  /**
2
2
  * AdCP SDK library version
3
3
  */
4
- export declare const LIBRARY_VERSION = "15.9.0";
4
+ export declare const LIBRARY_VERSION = "16.0.0-beta.1";
5
5
  /**
6
6
  * AdCP specification version this library is built for
7
7
  */
@@ -33,10 +33,10 @@ export type AdcpVersion = (typeof COMPATIBLE_ADCP_VERSIONS)[number];
33
33
  * Full version information
34
34
  */
35
35
  export declare const VERSION_INFO: {
36
- readonly library: "15.9.0";
36
+ readonly library: "16.0.0-beta.1";
37
37
  readonly adcp: "3.2.4";
38
38
  readonly compatibleVersions: readonly ["v2.5", "v2.6", "v3", "3.0.0", "3.0", "3.0.1", "3.0.2", "3.0.3", "3.0.4", "3.0.5", "3.0.6", "3.0.7", "3.0.8", "3.0.9", "3.0.10", "3.0.11", "3.0.12", "3.0.13", "3.0.14", "3.0.15", "3.0.16", "3.0.17", "3.0.18", "3.0.19", "3.0.20", "3.0.21", "3.0.22", "3.0.23", "3.0.24", "3.0.25", "3.1.0", "3.1", "3.1.1", "3.1.2", "3.1.3", "3.1.4", "3.1.5", "3.1.6", "3.1.7", "3.1.8", "3.1.9", "3.1.10", "3.1.11", "3.1.12", "3.1.13", "3.1.14", "3.1.15", "3.1.16", "3.1.17", "3.1.18", "3.1.19", "3.1.20", "3.1.21", "3.1.22", "3.1.23", "3.1.24", "3.2.1", "3.2", "3.2.2", "3.2.3", "3.2.4"];
39
- readonly generatedAt: "2026-10-13T01:26:11.275Z";
39
+ readonly generatedAt: "2026-10-14T03:59:15.421Z";
40
40
  };
41
41
  /**
42
42
  * Get the AdCP specification version this library is built for
@@ -1,7 +1,7 @@
1
1
  /**
2
2
  * AdCP SDK library version
3
3
  */
4
- export declare const LIBRARY_VERSION = "15.9.0";
4
+ export declare const LIBRARY_VERSION = "16.0.0-beta.1";
5
5
  /**
6
6
  * AdCP specification version this library is built for
7
7
  */
@@ -33,10 +33,10 @@ export type AdcpVersion = (typeof COMPATIBLE_ADCP_VERSIONS)[number];
33
33
  * Full version information
34
34
  */
35
35
  export declare const VERSION_INFO: {
36
- readonly library: "15.9.0";
36
+ readonly library: "16.0.0-beta.1";
37
37
  readonly adcp: "3.2.4";
38
38
  readonly compatibleVersions: readonly ["v2.5", "v2.6", "v3", "3.0.0", "3.0", "3.0.1", "3.0.2", "3.0.3", "3.0.4", "3.0.5", "3.0.6", "3.0.7", "3.0.8", "3.0.9", "3.0.10", "3.0.11", "3.0.12", "3.0.13", "3.0.14", "3.0.15", "3.0.16", "3.0.17", "3.0.18", "3.0.19", "3.0.20", "3.0.21", "3.0.22", "3.0.23", "3.0.24", "3.0.25", "3.1.0", "3.1", "3.1.1", "3.1.2", "3.1.3", "3.1.4", "3.1.5", "3.1.6", "3.1.7", "3.1.8", "3.1.9", "3.1.10", "3.1.11", "3.1.12", "3.1.13", "3.1.14", "3.1.15", "3.1.16", "3.1.17", "3.1.18", "3.1.19", "3.1.20", "3.1.21", "3.1.22", "3.1.23", "3.1.24", "3.2.1", "3.2", "3.2.2", "3.2.3", "3.2.4"];
39
- readonly generatedAt: "2026-10-13T01:26:11.275Z";
39
+ readonly generatedAt: "2026-10-14T03:59:15.421Z";
40
40
  };
41
41
  /**
42
42
  * Get the AdCP specification version this library is built for
@@ -31,7 +31,7 @@ __export(version_exports, {
31
31
  toReleasePrecisionVersion: () => toReleasePrecisionVersion
32
32
  });
33
33
  module.exports = __toCommonJS(version_exports);
34
- const LIBRARY_VERSION = "15.9.0";
34
+ const LIBRARY_VERSION = "16.0.0-beta.1";
35
35
  const ADCP_VERSION = "3.2.4";
36
36
  const ADCP_MAJOR_VERSION = 3;
37
37
  const COMPATIBLE_ADCP_VERSIONS = [
@@ -98,10 +98,10 @@ const COMPATIBLE_ADCP_VERSIONS = [
98
98
  "3.2.4"
99
99
  ];
100
100
  const VERSION_INFO = {
101
- library: "15.9.0",
101
+ library: "16.0.0-beta.1",
102
102
  adcp: "3.2.4",
103
103
  compatibleVersions: COMPATIBLE_ADCP_VERSIONS,
104
- generatedAt: "2026-10-13T01:26:11.275Z"
104
+ generatedAt: "2026-10-14T03:59:15.421Z"
105
105
  };
106
106
  function getAdcpVersion() {
107
107
  return ADCP_VERSION;
@@ -1,4 +1,4 @@
1
- const LIBRARY_VERSION = "15.9.0";
1
+ const LIBRARY_VERSION = "16.0.0-beta.1";
2
2
  const ADCP_VERSION = "3.2.4";
3
3
  const ADCP_MAJOR_VERSION = 3;
4
4
  const COMPATIBLE_ADCP_VERSIONS = [
@@ -65,10 +65,10 @@ const COMPATIBLE_ADCP_VERSIONS = [
65
65
  "3.2.4"
66
66
  ];
67
67
  const VERSION_INFO = {
68
- library: "15.9.0",
68
+ library: "16.0.0-beta.1",
69
69
  adcp: "3.2.4",
70
70
  compatibleVersions: COMPATIBLE_ADCP_VERSIONS,
71
- generatedAt: "2026-10-13T01:26:11.275Z"
71
+ generatedAt: "2026-10-14T03:59:15.421Z"
72
72
  };
73
73
  function getAdcpVersion() {
74
74
  return ADCP_VERSION;
@@ -1,7 +1,7 @@
1
1
  # AdCP Type Summary
2
2
 
3
- > Generated at: 2026-10-13
4
- > @adcp/sdk v15.9.0
3
+ > Generated at: 2026-10-14
4
+ > @adcp/sdk v16.0.0-beta.1
5
5
 
6
6
  Curated reference of the types that matter for using the AdCP client. For full generated types see `src/lib/types/tools.generated.ts` and `src/lib/types/core.generated.ts`.
7
7
 
@@ -9,6 +9,10 @@ Two independent mechanisms remove that cost:
9
9
 
10
10
  ## Shared discovery cache
11
11
 
12
+ `comply()` automatically owns discovery and connections for one run. Storyboards reuse clients, tool schemas and capability observations for the same URL, credentials, headers, AdCP version and transport settings, including a configured `trustedFetchFn`. Routed agents and changed credentials or versions get separate discovery. Explicit invalidation refreshes discovery, and failed discovery remains retryable by later storyboards. Every new `comply()` invocation starts with fresh discovery; ordinary SDK calls with a scoped fetch still follow the isolation rules below.
13
+
14
+ Failed discovery is attempted once per storyboard, so the runner's applicability and execution checks do not repeat a failing probe. Auth-diagnostic storyboards retain an empty profile after an authentication rejection, including when they load test-kit credentials; this placeholder contains no tool or capability evidence. MCP sessions remain open across storyboards until the run completes.
15
+
12
16
  ```ts
13
17
  import { AgentClient, createInMemoryAgentDiscoveryCache } from '@adcp/sdk';
14
18
 
@@ -139,7 +139,7 @@ const sink = createBigQueryReportingWarehouseSinkV1({
139
139
 
140
140
  Give the sink its **own new tables** rather than your legacy ones. It adds its
141
141
  own fixed columns (`reporting_revision_id`, `reporting_obligation_id`,
142
- `account_id`, `revision_number`, `finality`, `period_date`, `ordinal`), and
142
+ `account_id`, `revision_number`, `finality`, `period_date` (the period start's date in its source timezone), `ordinal`), and
143
143
  loading into a table another writer owns invites double counting. Give analysts
144
144
  one view that `UNION ALL`s the legacy table, bounded to periods before the
145
145
  cutover boundary, with the sink's `current_rows` view, bounded to periods from
@@ -2,6 +2,8 @@
2
2
 
3
3
  `@adcp/sdk/reporting/ledger` turns a conforming reporting source into durable seller-side Reliable Reporting Core. It is separate from the buyer-side `reconcileReporting` API.
4
4
 
5
+ > **Stability:** the storage, row, change-feed, managed-delivery and warehouse-sink exports (`@adcp/sdk/reporting/gcs`, `s3`, `azure`, `bigquery`, and the `@experimental` exports of `ledger`) are experimental and may change in minor releases. Pin with `~`. See the [Reliable Reporting stability policy](REPORTING-STABILITY.md).
6
+
5
7
  ## Recommended: install the lifecycle service
6
8
 
7
9
  `createReliableReportingService` is the adapter-first Core path. A
@@ -338,6 +340,19 @@ do {
338
340
  Removing rows from ledger documents frees space only after `VACUUM FULL` or an
339
341
  online repack of `adcp_reporting_revisions` and `adcp_reporting_adjustments`.
340
342
 
343
+ ### Stored field names
344
+
345
+ Stored values use AdCP's names and bounds: a chunk's `object_ref` and
346
+ `native_version_ref` (1 to 1024 characters each, enforced by `CHECK`
347
+ constraints), `size_bytes` (the stored object's size after compression, as in
348
+ the AdCP file manifest), and `canonical_size_bytes` (the uncompressed canonical
349
+ bytes that the chunk digests cover; a row set's `content_size_bytes` is the
350
+ byte count of the content its `content_sha256` covers). A row set records `format` (`jsonl`) and
351
+ `algorithm` (`adcp_jcs_rows_v1`). Neither token feeds a digest. Installed
352
+ databases upgrade in place when you re-apply `REPORTING_ROW_STORAGE_MIGRATION`;
353
+ see [Breaking: reporting row storage field alignment](../migration-reporting-row-storage-alignment.md)
354
+ for the old names, the API renames and the re-sync option.
355
+
341
356
  ### Object storage bindings
342
357
 
343
358
  Rows can live in object storage instead of PostgreSQL. A binding is defined in
@@ -368,7 +383,7 @@ const store = new PostgresReportingLedgerStore(pool, {
368
383
  providers: {
369
384
  filesystem: createFilesystemReportingRowObjectProviderV1({ roots: { reports: '/var/lib/adcp/rows' } }),
370
385
  },
371
- selectRowBinding: ({ canonical_byte_count }) => (canonical_byte_count < 256 * 1024 ? 'inline' : 'reports'),
386
+ selectRowBinding: ({ content_size_bytes }) => (content_size_bytes < 256 * 1024 ? 'inline' : 'reports'),
372
387
  },
373
388
  });
374
389
  await store.readyRowStorage();
@@ -380,19 +395,41 @@ await store.readyRowStorage();
380
395
  - Keys always start with `{prefix}/{namespace_key}/` and use a hashed account
381
396
  segment, never a raw account ID. Override `keyTemplate` with the placeholders
382
397
  in `REPORTING_ROW_KEY_PLACEHOLDERS`; templates must include
383
- `{content_sha256}` and `{chunk_index}`.
384
- Enabling snapshot compaction additionally requires `{revision_key}` (see
385
- [Compacting superseded snapshots](#compacting-superseded-snapshots-opt-in)).
386
- - A custom `keyTemplate` without `{account_key}` and `{revision_key}` can map
387
- row sets from different obligations or accounts with identical chunk content
388
- (an adjustment's digest covers its rows alone) to one object, which the
389
- second writer adopts. Every delete path (period retirement, compaction and
390
- the intent sweep) therefore skips an object while a live row set outside the
398
+ `{content_sha256}`, `{chunk_index}` and `{revision_key}`. `{revision_key}` is
399
+ required on every writable binding, so each row set writes its own object
400
+ keys (it hashes the row-set ID, so two uploads never name the same key). The store refuses a
401
+ template without it when it is configured and again in `readyRowStorage`,
402
+ with `INVALID_INPUT`.
403
+ `{period_date}` renders AdCP's `YYYY-MM-DD`: the calendar date of the period
404
+ start in the period's `source_timezone`, never UTC (a period starting
405
+ `2026-10-02T07:00:00Z` in `America/Los_Angeles` is `2026-10-02`; one starting
406
+ `2026-10-01T15:00:00Z` in `Asia/Tokyo` is also `2026-10-02`). It is one path
407
+ segment, so the default layout is
408
+ `{prefix}/{namespace_key}/{account_key}/2026-10-02/{finality}/...`, not
409
+ `2026/10/02/`. A missing, unknown or non-IANA timezone fails the write with
410
+ `INVALID_INPUT` rather than guessing a date. The rendered key must stay within
411
+ AdCP's 1024-character `object_ref` bound.
412
+ - Rows written under an older template without `{revision_key}` stay readable:
413
+ every read uses the chunk's recorded `object_ref`, never a re-rendered key.
414
+ Changing a template needs a new binding ID, and the old definition must stay
415
+ configured while revisions reference it. Mark that old definition
416
+ `readOnly: true` to keep it configured without `{revision_key}`: it is
417
+ exempt from the requirement, never selected for new writes, and still used
418
+ for reads and retirement. A read-only binding is still registered and
419
+ probed by `readyRowStorage`, so keep its location reachable (and keep
420
+ enforcing `readOnly` in every process that shares the database: it is not
421
+ stored).
422
+ - Header-only revisions share their predecessor's chunks within an obligation,
423
+ and chunk rows written under an older template can name one object from
424
+ several row sets. Every delete path (period retirement, compaction and the
425
+ intent sweep) therefore skips an object while a live row set outside the
391
426
  operation still references the same binding, key and native version, or an
392
- open write intent created it. The reference check and the delete run in one
427
+ open write intent created it. (With unique keys, a create-only write only
428
+ finds an existing object when a writer retries the same row set.) The check
429
+ and delete run under the per-object lock described below. The reference check and the delete run in one
393
430
  transaction under a per-object advisory lock, and a commit that adopts an
394
- existing object takes the same lock, re-reads the object and holds the lock
395
- until its chunk rows commit. A delete that wins the lock makes the adopting
431
+ existing object takes the same lock, proves the object is still there and
432
+ holds the lock until its chunk rows commit. A delete that wins the lock makes the adopting
396
433
  commit fail with `STATE_UNAVAILABLE` (the writer re-uploads once its intent
397
434
  lapses); a commit that wins is seen by the delete, which skips. A skipped
398
435
  object is deleted by the retirement, compaction or sweep of the last row set
@@ -415,7 +452,16 @@ await store.readyRowStorage();
415
452
  filesystem is wrong, not the code.
416
453
  - Custom providers implement `ReportingRowObjectProviderV1`. Run
417
454
  `runReportingRowObjectProviderConformanceV1(provider, { location, prefix })`
418
- against a dedicated test prefix before using one.
455
+ against a dedicated test prefix before using one. Provider calls take and
456
+ return AdCP's names: `objectRef` (the decoded, destination-relative object
457
+ key) and `nativeVersionRef` (the decoded provider-native version), each 1 to
458
+ 1024 characters. Implement the optional `stat({ objectRef, nativeVersionRef })`,
459
+ which returns `{ sizeBytes }` for that exact version or `null` when it is
460
+ absent, without reading the body. The commit transaction uses it to prove an
461
+ adopted object is unchanged (native versions are write-unique, so the same
462
+ version at the recorded size is the same bytes) instead of downloading it
463
+ while holding the account and object locks. A provider without `stat` falls
464
+ back to reading the whole object there. All bundled providers implement it.
419
465
 
420
466
  #### Cloud providers
421
467
 
@@ -690,15 +736,16 @@ revision referencing them is compacted.
690
736
  Compaction records no change-feed row: the revision's metadata did not change,
691
737
  and a sink still catching up holds the revision back (above).
692
738
 
693
- Compaction requires every object row binding's `keyTemplate` to include
694
- `{revision_key}` (the default template does). Deletes now skip objects another
695
- row set still references (see [Object storage](#object-storage-bindings)),
696
- so this is defense in depth rather than the only guard: with `{revision_key}`
697
- no two revisions ever name the same object, so compaction never depends on the
698
- reference check. The SDK fails closed: `createReliableReportingService` and
699
- `createPostgresReliableReportingProductionService` throw at construction when
700
- compaction is enabled and a binding's template omits `{revision_key}`, and
701
- `compactSupersededSnapshots` throws the same error before deleting anything.
739
+ Every writable object row binding's `keyTemplate` must include
740
+ `{revision_key}` (the default template does), so two uploads never name the
741
+ same object. Deletes skip objects another row set still references (see
742
+ [Object storage](#object-storage-bindings)), which still matters for header-only
743
+ revisions that share chunks within an obligation and for rows written under an
744
+ older template, so compaction does not depend on key uniqueness alone. A
745
+ `readOnly` binding for older rows is exempt: it never takes commits, so nothing
746
+ can adopt through it. The SDK fails closed when the store is configured, and
747
+ `createReliableReportingService`, `createPostgresReliableReportingProductionService`
748
+ and `compactSupersededSnapshots` re-check before compacting.
702
749
 
703
750
  ### Core-only setup with row storage, change feed and retention
704
751
 
@@ -908,32 +955,69 @@ setInterval(() => {
908
955
  store's verified reader. It loads rows first and revision metadata second,
909
956
  in one load job per table per tick. The sink always adds
910
957
  `reporting_revision_id`, `reporting_obligation_id`, `account_id`,
911
- `revision_number`, `finality`, `period_date` (the period's date in its source
912
- timezone) and `ordinal` to your mapped columns.
958
+ `revision_number`, `finality`, `period_date` and `ordinal` to your mapped
959
+ columns. `period_date` is a `DATE`: the calendar date of the period start in
960
+ the period's `source_timezone`, as `YYYY-MM-DD` (an SDK column derived from
961
+ AdCP's `period`), not the UTC date unless that is the source timezone. A
962
+ period starting `2026-10-02T07:00:00Z` in `America/Los_Angeles` is
963
+ `2026-10-02`; one starting `2026-10-01T15:00:00Z` in `Asia/Tokyo` is also
964
+ `2026-10-02`. It is the start's date only, not a coverage range: a period
965
+ that crosses local midnight or spans several days is one `period_date`, so
966
+ `PARTITION BY period_date` holds source-local days and a UTC "yesterday"
967
+ filter can straddle partitions. The sink computes it with the same helper
968
+ that renders `{period_date}` in object keys. It fails the batch rather than
969
+ load a guessed date when a revision's period or timezone is missing or
970
+ invalid. The batch stays retained, so the sink stops until that revision's
971
+ period is repaired (or the runtime's timezone data is upgraded); reset with
972
+ `discardRetainedPlan` restarts from the beginning, so empty the tables first.
913
973
  - Batches are planned durably before loading, and job IDs derive from the
914
- change-feed range. A crash between a load and the cursor commit replays the
915
- same batch under the same job ID, which BigQuery refuses to run twice. A job
916
- that finished with an error is retried under a new attempt for that table
917
- only.
974
+ change-feed range. Before every submission the sink looks that job ID up in
975
+ the destination project and location: a job that finished cleanly counts as
976
+ loaded, a job that is pending or running is waited for (never uploaded
977
+ again), and only a missing job (404) is uploaded. A crash or timeout between a
978
+ load and the cursor commit therefore replays the same batch under the same
979
+ job ID without a second upload. An upload an earlier run abandoned at its
980
+ deadline is still running in the same process (the official client cannot
981
+ abort it), so the next run waits for it, within its own deadline, rather than
982
+ starting another, however long ago it started (that age includes the gap
983
+ between runs). If that wait outlasts the run's deadline it counts as a timeout
984
+ and the deadline grows. Only an upload still pending after 6 hours, the
985
+ largest deadline, is abandoned and replaced; BigQuery refuses a duplicate job
986
+ ID, so a replacement can never load the batch twice. A job that finished with
987
+ an error is retried under a new attempt for that table only. Deadline and
988
+ timeout errors name the table (`rows` or `revisions`, and its ID), the
989
+ deadline in force and that table's timeout count, never a file path or
990
+ credential.
918
991
  - `projectId` scopes both load submission and replay status checks. When it is
919
992
  omitted, both use the BigQuery client's default project. Each replica must
920
- be able to read the BigQuery jobs submitted by the other replicas.
921
- - `loadTimeoutMilliseconds` (default 10 minutes) is a client-side deadline for
922
- one load. When a load passes it, the sink asks BigQuery to cancel that job by
923
- its deterministic ID, in `projectId` and `location`, and rejects with the
924
- plan retained. The next run finds the cancelled job finished with an error,
925
- advances that table's attempt and rejects; the run after that loads under the
926
- new attempt. If the cancel has not taken effect yet it waits for the job.
927
- Each attempt doubles the load deadline (up to 6 hours), so a slow but healthy
928
- load converges; set the deadline above your slowest expected load to avoid
929
- the cancelled attempts. Cancellation is best effort (BigQuery may finish the
930
- job anyway, which the next run then accepts), a failed cancel other than "not
931
- found" raises a `ADCP_BIGQUERY_SINK_CANCEL_FAILED` process warning, and a
932
- status check that times out is not cancelled. BigQuery's server-side
933
- `jobTimeoutMs` is not used: for a local-file load the official client builds
934
- `configuration.load` from the load options and cannot set job-level fields,
935
- and BigQuery silently drops `labels` and `jobTimeoutMs` found inside
936
- `configuration.load`. (Staging the file in GCS and submitting the load with
993
+ be able to read the BigQuery jobs submitted by the other replicas. Set
994
+ `location` for any dataset outside the US and EU multi-regions: BigQuery
995
+ answers a job lookup without the right location with 404, and the sink then
996
+ cannot find the jobs it created.
997
+ - `loadTimeoutMilliseconds` (default 10 minutes) is the base deadline for one
998
+ run's work on one load: uploading the file, or waiting for a job that is still
999
+ running. It bounds a run, not the job. BigQuery does not stop a load when the
1000
+ client gives up (a cancel is accepted and the job finishes anyway), and it
1001
+ refuses a resubmitted job ID only after the whole file is uploaded again, so
1002
+ the sink never cancels and never relies on that refusal. When the deadline
1003
+ passes, the run rejects with the plan retained and nothing advanced: the job
1004
+ ID, the attempt and the cursor stay as they were, and the next run looks the
1005
+ job up by its ID again. A job whose upload outlasted a deadline is created in
1006
+ the background and is picked up by the next run with no second upload. Each
1007
+ such timeout doubles that table's deadline for later runs (up to 6 hours).
1008
+ The growth is kept with the plan in `planned_rows_timeouts` and
1009
+ `planned_revisions_timeouts` (so it survives restarts and applies to every
1010
+ replica, and clears when the batch commits), so an upload slower than the
1011
+ deadline eventually gets enough time. Set the deadline above your slowest
1012
+ expected load to avoid the extra runs. Only a job BigQuery reports as
1013
+ finished with an error advances the attempt. A status check that times out
1014
+ is bounded by the base deadline and does not grow it. Re-run
1015
+ `REPORTING_WAREHOUSE_SINK_MIGRATION` after upgrading: it adds the two timeout
1016
+ columns (a sink table without them rejects with a message saying so).
1017
+ BigQuery's server-side `jobTimeoutMs` is not used: for a local-file load the
1018
+ official client builds `configuration.load` from the load options and cannot
1019
+ set job-level fields, and BigQuery silently drops `labels` and `jobTimeoutMs`
1020
+ found inside `configuration.load`. (Staging the file in GCS and submitting the load with
937
1021
  `bigquery.createJob` can set both; the sink does not stage files.) For the
938
1022
  same reason the `labels` option has no effect (it warns once per process and
939
1023
  is deprecated). To attribute load cost, query
@@ -974,7 +1058,9 @@ setInterval(() => {
974
1058
  jobs may have succeeded; reconcile the plan against BigQuery, then call
975
1059
  `reset({ discardRetainedPlan: true })`. It does not touch the warehouse: a sink
976
1060
  that already loaded history reloads the retained revisions, so empty the
977
- destination tables first or use a new sink name against new tables. Every
1061
+ destination tables first (after stopping every worker and letting in-flight
1062
+ uploads and jobs finish, since the sink never cancels a load) or use a new
1063
+ sink name against new tables. Every
978
1064
  reset starts a new job ID generation, so reloaded batches submit fresh BigQuery
979
1065
  jobs instead of matching the finished jobs of the earlier history. Nothing holds
980
1066
  change retention between `reset()` and the first committed batch. If `reset()`
@@ -5,6 +5,8 @@ consumer runtime. Reliable Reporting controls evidence used for billing and
5
5
  large media-spend decisions. Treat its PostgreSQL state, destination objects,
6
6
  signing keys, and authentication registry as financial infrastructure.
7
7
 
8
+ > **Stability:** the storage subpaths this runbook operates are experimental. Pin `@adcp/sdk` with `~` and read each minor's changeset before upgrading. See the [Reliable Reporting stability policy](REPORTING-STABILITY.md).
9
+
8
10
  ## Production topology
9
11
 
10
12
  Use one PostgreSQL primary with synchronous durability appropriate to the
@@ -90,6 +92,9 @@ service runs for you. See
90
92
  verified chunks. Existing revisions keep their inline rows, and every
91
93
  binary built with row storage reads both forms. Do not run a writer older
92
94
  than this release once chunked revisions exist: it cannot read them.
95
+ Upgrading from 15.8.x? Row storage renamed its stored fields to AdCP's
96
+ names; re-apply the migration before starting new binaries (see
97
+ [Breaking: reporting row storage field alignment](../migration-reporting-row-storage-alignment.md)).
93
98
  2. **Existing inline rows (optional).** Run `migrateInlineRows` in bounded
94
99
  batches from a maintenance job until it returns no cursor. Alert on any
95
100
  `quarantined` IDs: those revisions no longer reproduce their committed
@@ -334,9 +339,22 @@ What it checks:
334
339
  duplicate rows, and that `current_rows` returns one revision per obligation.
335
340
  It also asserts (`PASS`/`FAIL`) that the sink sends no `labels` or
336
341
  `jobTimeoutMs` inside `configuration.load`, where BigQuery silently drops
337
- them, and that a job cancel addressed with the destination project and
338
- location (what the sink sends when a load passes its client-side deadline) is
339
- accepted by BigQuery.
342
+ them. A deadline scenario runs a sink with the minimum 1-second load deadline
343
+ and holds the first load's result past it: the run must reject with the plan
344
+ and job ID unchanged and that table's persisted deadline grown, the job must
345
+ end `DONE` without an error (the sink never cancels it), and later runs under
346
+ the same sink name must converge with no duplicate rows, the same job ID and
347
+ no second upload. A #3234 scenario runs a sink whose upload of a 50,000-row
348
+ batch outlasts its 1-second deadline and asserts that it converges within 8
349
+ runs, loads every row exactly once, never changes the job ID, and never
350
+ starts an upload after the job exists (a link fast enough to beat the
351
+ deadline passes and says so). A
352
+ `period_date` scenario checks that non-UTC periods land on their
353
+ source-timezone date.
354
+ - **Cancel probe of the service** (`INFO`, never a failure). It cancels a
355
+ 5000-row load the moment it is created and reports whether BigQuery stopped
356
+ it; in practice it accepts the cancel and lets the load finish, which is why
357
+ the sink never cancels a load and finds it by job ID instead.
340
358
  - **Overlapping runs** (`INFO`, never a failure). Two concurrent `runOnce()`
341
359
  calls over one pending batch, and a deterministic reproduction of #3196: one
342
360
  run reads its sink state, another completes the batch and a new revision
@@ -353,7 +371,10 @@ What it checks:
353
371
  prevention, lifecycle rules) and `runReportingRowObjectProviderConformanceV1`,
354
372
  then commits a revision through an object binding on the bucket and reads it
355
373
  back verified (full read, ranged page, a second store instance, and a replayed
356
- commit that uploads nothing).
374
+ commit that uploads nothing). It also commits revisions for non-UTC periods and
375
+ checks that each object key has one `{period_date}` segment holding the
376
+ source-timezone date, and that each chunk's `native_version_ref` and
377
+ `size_bytes` match the stored object's generation and size.
357
378
 
358
379
  Everything it creates carries a per-run id: a dataset named
359
380
  `<GCP_DATASET_PREFIX><run id>`, objects under `<GCS_PREFIX>/<run id>/`, and
@@ -0,0 +1,76 @@
1
+ # Reliable Reporting stability policy
2
+
3
+ The Reliable Reporting storage surface is **experimental**. It is new, it has not yet run in production at an adopter, and its shape is still being settled by real use. Marking it experimental lets breaking changes there ship in minor releases, with notice, instead of forcing a major release of the whole SDK.
4
+
5
+ This follows how the AdCP protocol treats experimental surfaces (`x-status: experimental` in the schemas, with advance notice of breaking changes).
6
+
7
+ ## What is experimental
8
+
9
+ An export is experimental when its TSDoc carries an `@experimental` tag that links to this page. Editors show the tag on hover, and some mark the symbol as unstable.
10
+
11
+ | Subpath | Status |
12
+ | ------------------------------ | --------------------------------------------------------------------------- |
13
+ | `@adcp/sdk/reporting/gcs` | Experimental (every export) |
14
+ | `@adcp/sdk/reporting/s3` | Experimental (every export) |
15
+ | `@adcp/sdk/reporting/azure` | Experimental (every export) |
16
+ | `@adcp/sdk/reporting/bigquery` | Experimental (every export) |
17
+ | `@adcp/sdk/reporting/ledger` | Partly experimental (see below) |
18
+ | `@adcp/sdk/reporting/service` | Partly experimental: retention, compaction and change-feed maintenance only |
19
+
20
+ Within `@adcp/sdk/reporting/ledger`, the experimental exports are:
21
+
22
+ - the PostgreSQL ledger store (`PostgresReportingLedgerStore`), its migrations and errors, and `sweepExpiredReportingLedgerState`;
23
+ - row storage (`ReportingRowStorageV1`, row bindings, row encoding, the row-storage migration and probe, and row-store errors) and object writes;
24
+ - the host change feed (`REPORTING_LEDGER_CHANGES_MIGRATION`, change records and cursors);
25
+ - managed delivery (the runtime, the store, the adapter contract, the adapter router and the PostgreSQL store);
26
+ - notification activity stores and checkpoints;
27
+ - the store, transaction, lease and row-read interfaces in `ledger/types`.
28
+
29
+ Within `@adcp/sdk/reporting/service`, the experimental exports are `ReportingRetentionOptionsV1`, `ReportingCompactionOptionsV1`, `ReportingChangeFeedMaintenanceOptionsV1`, `runReportingLedgerMaintenance` and the related maintenance types and error.
30
+
31
+ ### Not experimental
32
+
33
+ These follow normal semver. A breaking change to them ships in a major release.
34
+
35
+ - The protocol-facing handlers: `createReportingDeliveryHandler`, `createReportingStatusHandler`, `createSyncReportingStatusHandler`, `createSyncReportingReceiptsHandler`, and the status-ingest request and response schemas.
36
+ - `createReportingProducer`, `assertSupportedReportingAuthoritativeParty` and `UnsupportedReportingFeatureError`.
37
+ - The health, coverage, lifecycle, schedule and consumer-status-identity helpers in `@adcp/sdk/reporting/ledger`.
38
+ - `createReliableReportingService`, `createPostgresReliableReportingProductionService` and the service conformance runner in `@adcp/sdk/reporting/service`.
39
+ - `@adcp/sdk/reporting/consumer` (buyer reconciliation and worker) and `@adcp/sdk/reporting/source` (source contract and executor). They are separate subpaths with their own `V1` contract suffixes and are not covered by this policy.
40
+
41
+ If you are unsure about a symbol, read its TSDoc. An `@experimental` tag means it is covered. No tag means it is not.
42
+
43
+ ## What "experimental" means
44
+
45
+ - **Breaking changes may ship in minor releases.** That covers signatures, option names, stored field and column names, migrations, and defaults in the experimental exports.
46
+ - **Every such change is announced.** The changeset describes the break and includes a migration note, and the release notes carry it. Larger changes also get a `docs/migration-*.md` walkthrough.
47
+ - **The wire protocol is not affected.** Buyer-visible behavior these exports implement (reporting delivery, `revision_content_sha256`, status, receipts and so on) follows AdCP's own versioning, not this policy. A change to the SDK's storage layout does not change what a buyer sees.
48
+ - **Security and correctness fixes are not held back.** If a fix needs a breaking change, it ships in a minor.
49
+
50
+ ## How to pin
51
+
52
+ Adopters of the experimental subpaths should not use a caret range, which accepts every future minor.
53
+
54
+ ```json
55
+ {
56
+ "dependencies": {
57
+ "@adcp/sdk": "~16.0.0"
58
+ }
59
+ }
60
+ ```
61
+
62
+ - `~16.0.0` takes patches only (recommended).
63
+ - An exact version (`"16.0.0"`) is stricter still.
64
+ - Read the changelog before widening to a new minor, and apply any migration it names.
65
+
66
+ If you use only the stable surfaces, a caret range is fine as usual.
67
+
68
+ ## Migrations
69
+
70
+ Database migrations exported from experimental subpaths (`REPORTING_LEDGER_MIGRATION`, `REPORTING_ROW_STORAGE_MIGRATION` and the others) stay idempotent where practical, and a changeset says when you must re-apply one. See [Reliable Reporting production operations](REPORTING-OPERATIONS.md) and the [ledger guide](REPORTING-LEDGER.md).
71
+
72
+ ## When this will change
73
+
74
+ The surface is expected to stabilize after the first production adopter runs on SDK 16 stable. At that point the `@experimental` tags are removed in a minor release with a changelog note, and breaking changes need a major release from then on.
75
+
76
+ Related: [Seller reporting ledger](REPORTING-LEDGER.md), [Reliable Reporting production operations](REPORTING-OPERATIONS.md).
@@ -29,6 +29,101 @@ For buyer setup and opt-in lifecycle management, see
29
29
  For upgrading an existing integration, use the
30
30
  [14.0-to-14.1 checklist](../migration-14.0-to-14.1.md).
31
31
 
32
+ ### Account sync contracts
33
+
34
+ For platform `accounts.upsert`, the framework looks up accepted natural-key
35
+ entries with `provisioning: false` before calling the batch method. The optional
36
+ `ctx.existing` array is aligned with the entries passed to `upsert`; each element
37
+ is the pre-write account snapshot or `null`. All natural-key dimensions are
38
+ preserved, including brand countries, operator unit, currency, timezone and sandbox.
39
+ Natural-key snapshots require the resolved account's own brand and operator;
40
+ identity-free singleton resolvers supply no snapshot rather than matching every key.
41
+ Use these snapshots to update the existing ID instead of creating another account.
42
+ Snapshots are advisory: enforce uniqueness atomically in your own storage too.
43
+
44
+ The framework emits typed, server-side `accounts.onDiagnostic` events for
45
+ `ACCOUNT_SYNC_IDEMPOTENCY_VIOLATION`, `ACCOUNT_SYNC_PAYMENT_TERMS_MISMATCH`, and
46
+ `ACCOUNT_BILLING_FIELDS_MISSING`, plus `ACCOUNT_SYNC_BILLING_MISMATCH` when an
47
+ active result silently replaces requested agent billing with another party
48
+ (strict mode rejects it with `BILLING_NOT_SUPPORTED`). ID-only resolvers that reject natural-key
49
+ lookups remain usable and emit `ACCOUNT_SYNC_LOOKUP_UNSUPPORTED`; their
50
+ identity checks require store-level enforcement. Events contain only the code, tool and original
51
+ row index. Development logs also receive warnings. Callback exceptions do not
52
+ change the result of a committed write. The default behavior preserves existing
53
+ responses. Set `accounts.strictIdempotency: true` to return per-row failures for
54
+ changed IDs, `created` on an existing key, or an active account that omits or
55
+ changes requested terms (`PAYMENT_TERMS_NOT_SUPPORTED`). Identity violations
56
+ return `SERVICE_UNAVAILABLE`. These post-write checks cannot roll back adopter writes.
57
+
58
+ Missing sync billing/terms are filled only from a stored account whose ID matches
59
+ the result, never from the buyer's requested terms. Agent-billed list rows without
60
+ terms also emit a diagnostic. Low-level handler-bag overrides do not use this
61
+ platform-store guard.
62
+
63
+ ### Persistent keyed accounts
64
+
65
+ `createKeyedAccountStore` from `@adcp/sdk/server` supplies deterministic IDs and
66
+ additive, non-expiring account syncs. Choose `memoryKeyedAccountBackend()` for one
67
+ process, `pgKeyedAccountBackend(pool)` for PostgreSQL, or
68
+ `redisKeyedAccountBackend(client)` for a persistent Redis deployment with eviction
69
+ disabled. Custom KV backends can implement `KeyedAccountBackend` using native
70
+ atomic compare-and-swap; ordinary read followed by write is insufficient.
71
+
72
+ ```ts
73
+ import {
74
+ createKeyedAccountStore,
75
+ getKeyedAccountMigration,
76
+ pgKeyedAccountBackend,
77
+ } from '@adcp/sdk/server';
78
+
79
+ await pool.query(getKeyedAccountMigration());
80
+ const accounts = createKeyedAccountStore({
81
+ namespace: 'seller-production', // trusted deployment namespace
82
+ backend: pgKeyedAccountBackend(pool),
83
+ resolution: 'implicit',
84
+ buildAccount: async (entry, { accountId, existing, dryRun, ctx }) => {
85
+ // Your onboarding code accepts the requested terms or throws AdcpError.
86
+ // It must use accountId for idempotent upstream writes too.
87
+ return onboardAdvertiser(entry, { accountId, existing, dryRun, authInfo: ctx?.authInfo });
88
+ },
89
+ });
90
+ ```
91
+
92
+ `buildAccount` is required and returns the actual account, using the supplied
93
+ `accountId`. The store validates active payment terms before committing; a
94
+ rejected update leaves the stored account intact. It strips `authInfo` before
95
+ persistence; credentials must also stay out of `ctx_metadata`. By default the
96
+ store partitions accounts by stable OAuth client, API key ID or verified agent
97
+ URL. Override `principalKey` only with a trusted authorization partition, never
98
+ buyer-supplied request fields. Use distinct namespaces for different sellers.
99
+
100
+ Concurrent writes retry atomic CAS up to ten times, re-running `buildAccount`
101
+ against fresh state. Its external side effects must therefore be idempotent on
102
+ the supplied account ID. A crash between an upstream write and the local CAS
103
+ still requires that upstream idempotency. The backend stores one roster per
104
+ principal with a default `maxAccounts` limit of 1000 and suits modest rosters; large sellers should use indexed account
105
+ tables with unique natural-key constraints. Share the memory backend across
106
+ server factories; use persistent storage across restarts.
107
+
108
+ Dry runs do not persist; `buildAccount` receives `dryRun: true` and must preview
109
+ without upstream writes or other side effects. Only the seller-returned account
110
+ determines sandbox authority; the buyer's sandbox flag participates in identity
111
+ and never grants test-tool access. Settings updates cannot provision a missing natural-key
112
+ account. `delete_missing` and operator identity reconciliation are explicitly
113
+ unsupported; close accounts through your lifecycle code. List cursors are bound
114
+ to the principal, filters and roster revision and become stale after a write.
115
+ An unknown ID-keyed entry rejects the batch before any `buildAccount` callback:
116
+ this interface requires brand/operator on failed rows, and unauthorized account
117
+ identities must not be invented or exposed. Failed known-account updates retain
118
+ the account's actual status and leave persisted state intact.
119
+
120
+ Run [the account sync storyboard](../../examples/storyboards/account-sync-contract.yaml)
121
+ with one authenticated sandbox caller. Its `account.sync_contract` invariant
122
+ checks repeat syncs with fresh request keys, exact accepted terms and billing
123
+ fields on list rows. The fixture is SDK-authored; canonical protocol storyboards
124
+ remain unchanged. A seller rejecting the fixture's terms needs an accepted-terms
125
+ fixture to exercise successful repeat provisioning.
126
+
32
127
  Account resolvers receive `ctx.provisioning`. It is false on discovery and
33
128
  negotiation (`get_products`, `list_products`, `get_signals`, and proposal
34
129
  request/refine/decline); these tasks MUST use lookup only. It is true on spend
@@ -623,3 +718,9 @@ const accounts = {
623
718
  **Hand-rolled stores.** For stores that don't use `createRosterAccountStore`,
624
719
  handle `resolve(undefined, ctx)` in your own `resolve` implementation by
625
720
  checking `ref === undefined` before the id-arm branch.
721
+
722
+ ### Callback boundaries
723
+
724
+ A custom `principalKey` may be synchronous or asynchronous, and must return a nonempty primitive string derived from trusted authentication state. Missing, object, numeric, boolean, or blank values fail closed before backend access. Use a stable tenant identity, keep it deterministic across repeated calls in one request, and bound callback I/O durations.
725
+
726
+ `createKeyedAccountStore` captures dry-run intent before callbacks and gives each CAS retry fresh copies of sync entries and request input. Mutating callback request arguments cannot change the original request or turn a preview into a committed write. Framework commercial checks also retain an independent request snapshot. Async diagnostic hooks are fire-and-forget; their failures are isolated from dispatch.